Jump to content
Official BF Editor Forums

Corona's Shaders

Recommended Posts

This is a collection of CGFX shaders that I've made. Free to use for everybody. I'm open to suggestions if you would like to see something added.
Each shader comes with instructions if you're not familiar with how to use them and some possible solutions if you run into problems.
Only tested in Max 9 and Max 12 on NVidia Hardware. UV and wind animation only works on applicable techniques and when animation is playing. Hit the play button on the bottom right.

3ds Max

BF2 BundledMesh ViewPort Shader
A CGFX shader for viewing BF2 Bundlemeshs in 3ds Max. Not for exporting.
BF2_BundledMesh_Shader_V2 Hotfix. Repaired low specularity on alpha techniques.
BF2_BundledMesh_Shader_V3 Added: NormalMap as Alpha Source, Animated Tank Tracks

Available Techniques:


BF2 Undergrowth Viewport Shader
A CGFX Shader for viewing BF2 Undergrowth In 3ds Max. Can simulate the BF2 wind system


Updated BF2 Staticmesh Viewport Shader
A CGFX StaticMesh Shader for 3DS Max. You CAN export using this shader and the Poe 2 Tools (only tested in max9 sp2). Can Simulate Overgrowth Wind

Available Techniques


BF Editor

BF2 Editor Terrain Shader
This editor shader will enable the rendering of envmaps on the terrain. There may be noticeable drop in frame rate / performance which is probably why DICE disabled them in the first place. If you have good computer it wont matter.
BF2 Editor Terrain Shader


BF2 Editor Water Shader
This shader will enable the editor to render water the same as the game, with full transparency. You must delete the editor's shader cache to force a recompile before the changes will take place. Instructions included.

BF2 Editor Water Shader

Edited by Coronaextra

Share this post

Link to post
Share on other sites

I've managed to add normal maps, specularity, and phong shading to the BF2 terrain. The shader derives the normals from a heightmap placed into the detailmap's alpha channel. A black alpha, or no alpha, produces no change so it shades as the vanilla game does. The closer the heightmap gets to white (full range) the more intense the normals and specularity become. Most details maps have no alpha so shis shader could be added to almost any existing mod without breaking anything. The bad news: at the moment the light source is hardcoded to directly overhead (0,-1,0). I cant seem to find away to get either the game or the editor to pass that information into the shader, but I am working on it.

In the videos below I have a test map set up with two layers with the same color and detail texture, one has no alpha and the other has a heightmap alpha. The blending between them seems to be working fine, and the distance fade out keeps everything looking vanilla from afar.

Also, this is still a WIP, but I don't have far to go now.

In the editor

In the game - ignore the stupid black dots, my new video card doesn't like BF2.

Edited by Coronaextra

Share this post

Link to post
Share on other sites

Hello Corona.

Its great seeing this thread we found your videos online and was obviously highly interested in this mod may I ask are you going to ever release this work is absolutely stunning.

Thankyou for your time and hope to speak soon. 

Share this post

Link to post
Share on other sites

I assume you mean the terrain normals project? I haven't worked on that in a few years and I also no longer have the files for it. With some effort I could get it back to where it was but I would still run into the same problems as before. I posted about this problem in this forum and never received an answer. Until those problems are resolved I see no reason to continue with the project. Unfortunately there aren't a lot of people that know about BF2 shaders and at this point I would not even know who to ask.

Edited by Coronaextra

Share this post

Link to post
Share on other sites

Hello Corona thankyou for the reply much appreciated.

Well after much time and effort managed to get night vision working correctly with sequential daytime/nighttime maps without static light bugs.


Some new shaders in the zip also.

Would you mind linking the threads regarding the issue you had with the shader I cannot find any info on this apart from this thread?

Your shader is a game changer... I'm sure the dedicated BF2 community would be eternally grateful for any of your work. I'm sure we can iron out the bugs.

ThankYou for your time and hope to speak soon.




Share this post

Link to post
Share on other sites

This is where I asked about adding new variables  http://www.bfeditor.org/forums/index.php?/topic/14407-editing-shaders/&page=2

You seem to have some knowledge of BF2 shaders, so I'll explain the problems here.

The problem is three fold:

1.  Certain LightManager settings need to be passed into the shader for the lighting calculations to work properly, Currently the engine and editor will not do this because they were not programmed to do so. Some of these settings are declared in the shaders but remain empty and unused, possibly a remnant of an early un-optimized version of the game. Once DICE figured out what they needed for the vanilla shaders to function, they simply turned everything else off. The compiled EXE of the game will not use them or pass them to the terrain shaders.

2. Because the master shader for the mod is being edited, there is no control over the settings on a per map basis. Some of these settings don't exist in the game at all, and there would have to be a way to load them and inject them into the instance of the shader at runtime. Doing this for the editor probably would not work at all. Where I left off on this project, every one of the variables were hard coded, forcing the lighting additions to the terrain to be exactly the same across the entire mod, which isn't very useful.

3. Lack of specular maps. The shader loads a heightmap from the alpha channel of the detail map and derives the normals from that. This is really the only unused texture channel for the terrain (except when envmap technique is being used), leaving nothing left for loading specular maps.  The only solution to this problem I've found is to "grey pack" the detail map, placing specular and env maps in the other channels. This would work fine, but it requires the user to sacrifice color detail maps. For some projects that wouldn't matter, for others it would be a deal breaker. To make no change means that specularity can't be controlled and it can look very bad at times.

The loading issues could probably be solved with Python, but I know almost nothing about it, and it's a bit out of my wheelhouse. I am not a very good programmer and what I've achieved so far has been through a lot of trial and error.

After you contacted me I copied over some code from another project that uses a similar system and I got the basics up and running again. I'll post the code below, have a go at it if you want.

Share this post

Link to post
Share on other sites
///  Global Variables

float specularPower = 10;
float fresnelPower = 3;
scalar UVOffset = 0.005f;
scalar NormalsIntensity = 20.0f;
float3 lightDir = normalize(vec3(0.0f, 0.0f, -1.0f)); // Hardcoded light direction

struct APP2VSEditorDetailTextured 
    float4	Pos0 : POSITION0;
    float2	TexCoord0 : TEXCOORD0;
    float4	Pos1 : POSITION1;
    float3	Normal : NORMAL;
struct VS2PSEditorDetailTextured
    float4	Pos : POSITION;
    float2	Tex0 : TEXCOORD0;
    float2	Tex1 : TEXCOORD1;
    float2	Tex2 : TEXCOORD2;
    float2	Tex3 : TEXCOORD3;
    float2	Tex4 : TEXCOORD4;
    float4	BlendValueAndFade : TEXCOORD5;
    float3	FogAndWaterFadeAndFade2 : TEXCOORD6;
    float2	BiFixTex : TEXCOORD7;
	float3  WorldPos : COLOR; ///////////////////////ADDED
VS2PSEditorDetailTextured vsEditorDetailTextured(APP2VSEditorDetailTextured indata)
	VS2PSEditorDetailTextured outdata;
	float4 wPos;
	wPos.xz = (indata.Pos0.xy * vScaleTransXZ.xy) + vScaleTransXZ.zw;
	wPos.yw = (indata.Pos1.xw * vScaleTransY.xy) + vScaleTransY.zw;
 	outdata.FogAndWaterFadeAndFade2.y = 1 - saturate((waterHeight - wPos.y)/3.0f);
 	outdata.Pos = mul(wPos, mViewProj);
	float cameraDist = length(wPos.xz - camerapos.xz) + camerapos.w;	
	float3 tex = float3((indata.Pos0.y * vTexScale.z), -(((indata.Pos1.x) * vTexScale.y)) , (indata.Pos0.x * vTexScale.x));
	float2 xPlaneTexCord = tex.xy;
	float2 yPlaneTexCord = tex.zx;
	float2 zPlaneTexCord = tex.zy;
 	outdata.Tex0 = yPlaneTexCord;
 	outdata.BiFixTex = (yPlaneTexCord * vBiFixTex.x) + vBiFixTex.y;	
	outdata.Tex1 = yPlaneTexCord * vNearTexTiling.z;	
 	outdata.Tex2 = yPlaneTexCord * vFarTexTiling.z;
	outdata.Tex3.xy = xPlaneTexCord.xy * vFarTexTiling.xy;
	outdata.Tex3.y += vFarTexTiling.w;
	outdata.Tex4.xy = zPlaneTexCord.xy * vFarTexTiling.xy;
	outdata.Tex4.y += vFarTexTiling.w;
	outdata.BlendValueAndFade.xyz = saturate(abs(indata.Normal) - vBlendMod);
	float tot = dot(1, outdata.BlendValueAndFade.xyz);
	outdata.BlendValueAndFade.xyz /= tot;
	float interpVal = saturate(cameraDist * vNearFarMorphLimits.x - vNearFarMorphLimits.y);
	outdata.BlendValueAndFade.w = saturate(interpVal * detailFadeMod);
	outdata.FogAndWaterFadeAndFade2.z = 0.5+interpVal*0.5;
 	outdata.FogAndWaterFadeAndFade2.x = saturate(calcFog(outdata.Pos.w));
	outdata.WorldPos = mul(wPos, mViewProj); ///Added 

	return outdata;

float4 psEditorDetailTextured(VS2PSEditorDetailTextured indata) : COLOR
	////////////  Vanilla Terrain Shading
	float4 staticColormap = tex2D(sampler0Clamp, indata.BiFixTex);
	float4 component = tex2D(sampler2Clamp, indata.BiFixTex);
	float4 lowComponent = tex2D(sampler5Clamp, indata.BiFixTex);
	float4 detailmap = tex2D(sampler1Wrap, indata.Tex1);
	float4 yplaneLowDetailmap = 2*tex2D(sampler3Wrap, indata.Tex2);
	float4 xplaneLowDetailmap = 2*tex2D(sampler3Wrap, indata.Tex3);
	float4 zplaneLowDetailmap = 2*tex2D(sampler3Wrap, indata.Tex4);
	float4 lightmap = tex2D(sampler4Clamp, indata.BiFixTex);
	float4 light = (lightmap.y * vSunColor*4) + (lightmap.z * vGIColor*2) +  + (lightmap.x * vPointColor);	
	float3 blendValue = indata.BlendValueAndFade.xyz;
	float fade = indata.BlendValueAndFade.w;	
	float4 colormap = staticColormap;	
	float chartcontrib = dot(componentsel, component);
	float4 lowDetailmap = lerp(1, yplaneLowDetailmap.z, lowComponent.x*indata.FogAndWaterFadeAndFade2.z);
	float mounten = (xplaneLowDetailmap.y * blendValue.x) + (yplaneLowDetailmap.x * blendValue.y) + (zplaneLowDetailmap.y * blendValue.z);
	lowDetailmap *= lerp(1, mounten, lowComponent.z);	
	float4 bothDetailmap = detailmap * lowDetailmap;
	float4 detailout = 2 * lerp(bothDetailmap, 0.5*lowDetailmap, fade);
	float4 outColor = detailout * colormap * light;	
	float4 waterOutColor = lerp(terrainWaterColor, outColor, indata.FogAndWaterFadeAndFade2.y);
	float4 fogWaterOutColor = lerp(FogColor, waterOutColor, indata.FogAndWaterFadeAndFade2.x);
	fogWaterOutColor.a = 1.0f;

//////////   NEW STUFF  /////////////////////////////////////
	////  Derive normals from heightmap
	float2 OffsetA = float2(UVOffset,0);
	float2 OffsetB = float2(0,UVOffset);
	float2 AdjustedUVX = OffsetA + indata.Tex1;
	float2 AdjustedUVZ = OffsetB + indata.Tex1;	
	float4 NormalTextureX = tex2D(sampler1Wrap, float2(UVOffset,0) + indata.Tex1).a;
	float4 NormalTextureY = tex2D(sampler1Wrap, indata.Tex1).a;	
	float4 NormalTextureZ = tex2D(sampler1Wrap, float2(0,UVOffset) + indata.Tex1).a;	
	float OffsetDifferenceA = (NormalTextureX.a - NormalTextureY.a) * NormalsIntensity;
	float OffsetDifferenceB = (NormalTextureZ.a - NormalTextureY.a) * NormalsIntensity;	
	float3 AppendX = float3(1,0,OffsetDifferenceA);
	float3 AppendY = float3(0,1,OffsetDifferenceB);	
	float3 TextureNormals = normalize(cross(AppendX,AppendY));

	//// Basic phong shading using derived normals
	float4 LightingCalc;	
	float3 worldEyeVec = normalize(indata.WorldPos.xyz - camerapos.xyz);
	float3 reflectionVector = - reflect(worldEyeVec, TextureNormals);
	float3 specular = .5 * pow(saturate(dot(reflectionVector, lightDir)), specularPower) * vSunColor;	
	float3 lambert = saturate(dot(-lightDir, TextureNormals));	
	float3 fresnel = saturate(pow(saturate(dot(worldEyeVec, TextureNormals)), fresnelPower)) * (lambert + vGIColor);	
	LightingCalc.rgb = (lambert + vGIColor) * fogWaterOutColor.rgb + specular + fresnel;	;
	LightingCalc.a = 1.0f;
	float4 Output;
	Output.rgb = LightingCalc.rgb;
	Output.a = 1;
	return  Output * chartcontrib; 


Share this post

Link to post
Share on other sites

Hello Corona thankyou for the reply.

So the main 3 issues.

1. Didn't Badsanta use some kind of custom Bf2.exe to translate the optic shaders? Would this be of any use in implementing your shaders? Unfortunately this is beyond me. Also Bf2 Armored Kill's shaders.zip already have the optic shaders implemented but to activate this shader you need a custom hud setup in the weapons config tweak. Also the Armored Kill mod doesn't use a custom EXE either to achieve this?

2. Maybe Badsanta's custom EXE for injecting the shader could be of some help?

3. I would personally sacrifice anything for this shader to work.

Ok going to do some research I'll post back ASAP.

Thankyou for your time and hope to speak soon.

Edited by JOHN007

Share this post

Link to post
Share on other sites

With my .exe .dll hack it is certainly possible to pass any information to the shaders but in this case it would require a bit of work.

BF2 uses the ID3DXEffect interface for managing the shaders so if you could somehow get a pointer to the right effect interface. You  could use functions like GetParameterBySemantic and SetFloat, SetFloatArray... to pass any info to the shaders even textures. The problem is how to get the pointer to the terrain shader effect interface.

BF2 also uses quite old version of the DX9SDK  which may cause some trouble with the interface.

I might look into this when I have some spare time

Share this post

Link to post
Share on other sites

Dear Bad Santa.

The dedicated BF2 community have being really good this year, we have BF3/4 weapons, soldiers, vehicles and have online stats running with progressive unlocks. Everyone needs alittle help from the Bad Santa as Good Santa wont bring us any new shaders..

Please bring us presents..

Many thanks from the BF2 community!

Share this post

Link to post
Share on other sites

I Have RendDX9.dll that needs the path to custom shaders editing, comes with a pair of shaders zips, one for day and one for night maps, it creates a pair of cache folders one for each, ive been told it works but as yet i havn't been able to test it.


Share this post

Link to post
Share on other sites

I got it working :D I even exposed the functionality to the .con files so it is easier to experiment. I only added support for float vectors for now.

shadermanager.setShaderFloatBySemantic [ShaderName] [ParameterSemantic] [float]
shadermanager.setShaderFloat2BySemantic [ShaderName] [ParameterSemantic] [D3DXVECTOR2]
shadermanager.setShaderFloat3BySemantic [ShaderName] [ParameterSemantic] [D3DXVECTOR3]
shadermanager.setShaderFloat4BySemantic [ShaderName] [ParameterSemantic] [D3DXVECTOR4]

For example to pass the sun direction to the terrain shader you could add this to the sky.con or almost any other .con file.

var v_sundirection
lightManager.sunDirection -> v_sundirection
shadermanager.setShaderFloat3BySemantic TerrainShader.fx SUNDIRECTION v_sundirection

You can change any parameter but most of those will be overridden by the game so it is better to just add new parameters with different names.

This works for shaders where the first line looks something like this

#line 2 "TerrainShader.fx"


Edited by Bad_santa12345

Share this post

Link to post
Share on other sites
10 hours ago, Coronaextra said:

Wow dude, that's awesome! So you are saying this works without the addition of your DLL hack or any other third party software?

No you still need the .exe and .dll hack.

I also got custom textures working. I just joined Github and started working on cleaned up open source version of the .dll so all my work doesn't go to waste.

Share this post

Link to post
Share on other sites

That's great news man, I'm super excited to try this. It should open up a whole world of possibilities for BF2 shaders. I have a few ideas on how to vastly improve the sky and water shaders using this.

Does this allow new textures to be loaded in addition to the textures that are already loaded, or does it overwrite the existing samplers?

Share this post

Link to post
Share on other sites

Textures and samplers work just like any other variable. You can add new or use existing ones. When using existing ones there is a change that BF2 overrides your changes.

I don't have the system hooked into BF2's texture manager so there are some differences to regular textures.

  • Textures are loaded on demand instead of deferred loading.
  • Textures don't have to/can't be inside .zip files.
  • Texture path must contain the mods/[modname] because the path is relative to the working directory of  BF2.exe instead of the mod directory
  • Textures are unloaded only when BF2.exe is shut down

Share this post

Link to post
Share on other sites

In anticipation of using your new system, I have been experimenting heavily with the terrain system and I've come to the conclusion that the terrain mesh must have 6 instances of the terrain shader applied to it, one for each layer, because the terrain shader only loads a single detail texture, and uses a variable called "chartcontrib" as a means to blend between them.

Have you confirmed any of that? And if so, is your system capable of passing unique textures into each of the shader instances?

Share this post

Link to post
Share on other sites

Jungle Project meets Shader Project!

A day version of Hunter's Moon running the new normals shader. I also added improved envmap techniques for more realistic puddles. Not perfect but it's looking better every day. I also have a rough test version for you guys to try if you want.



Share this post

Link to post
Share on other sites
On 23.12.2016 at 10:58 PM, Coronaextra said:

In anticipation of using your new system, I have been experimenting heavily with the terrain system and I've come to the conclusion that the terrain mesh must have 6 instances of the terrain shader applied to it, one for each layer, because the terrain shader only loads a single detail texture, and uses a variable called "chartcontrib" as a means to blend between them.

Have you confirmed any of that? And if so, is your system capable of passing unique textures into each of the shader instances?

Yeah. I think the terrain is rendered in 6 passes or so, one for each detail texture. At the moment the system can only pass sort of global data. For example if you pass a texture to a custom texture variable  in the bundledmesh shader the texture will be the same for all bundledmesh instances.

I think I can make it more clever so that it could pass different textures for different terrain detail layers.

PS. I am currently doing some work on the dynamic shadow maps. I already got rid of the horrible shimmering edge when you move or rotate the camera. I think it might be possible to do cascaded shadow maps in BF2. Cascaded shadow maps is the method most modern game engines use for dynamic shadowing.

Share this post

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Create New...