-
|
|
|
This is my first post on the forums, i've read along for a while but never got involved. But i have encountered a problem i cant solve.
Im trying to implement fog into my project. I dont really know where to start. I am using a HLSL effect file i wrote, it works fine. Well i would like to know how to implement fog in the effect file. Im using shader model 3, and i read that fog in SM 3 has to be done using shaders.
Any help would be greatly appreciated.
Check out my blog for updates on my Game Dev: http://gmaker-gd.blogspot.com/
|
|
-
-
- (249)
-
premium membership
-
Posts
227
|
|
Not sure exacltly, but take a look at the particle 3d sample. Im sure you could adapt the smoke so its fog-like.
|
|
-
|
|
|
The particle3D sample...That thing gives me headaches. Ive tried to understand it, but i just dont get it.
I read the point sprites tutorial in the documentation, i got it to work and was able to tweak it some.
I guess i understand the particle3d sample a little but not enough to explain it to someone, or to use it in my own projects ( i dont like using code i cant explain, it doesnt help the learning process )
Im gonna keep looking over it however, probably until i get it, or until i delete it from frustration.
I think im gonna search the internet about particle systems, and emmitters.
Check out my blog for updates on my Game Dev: http://gmaker-gd.blogspot.com/
|
|
-
-
- (142)
-
premium membership
-
Posts
342
|
|
VGMaker0507:
The particle3D sample...That thing gives me headaches. Ive tried to understand it, but i just dont get it.
I read the point sprites tutorial in the documentation, i got it to work and was able to tweak it some.
I guess i understand the particle3d sample a little but not enough to explain it to someone, or to use it in my own projects ( i dont like using code i cant explain, it doesnt help the learning process )
Im gonna keep looking over it however, probably until i get it, or until i delete it from frustration.
I think im gonna search the internet about particle systems, and emmitters.
Can you describe what it is you find confusing? A lot of folks around here can probably help you fill in whatever it is that you are missing. And sometimes I find that just trying to describe what I'm confused about to another person helps me figure it out.
Is it the concept of particles? The code of the engine itself? Point sprites?
Tom
|
|
-
-
- (330)
-
premium membership
MVP
-
Posts
282
|
|
DONT use the particle sample for fog.
You can set your shader up to use fog, add a variable to your vertex out structure called Fog with the symantic FOG like this
struct VS_OUTPUT { // Your stuff here float Fog : FOG; };
then in your vertex shader assign the value of the fog you require like this (do it how you need it, this is an example)
Output.Fog = 1.0f - ( length( Input.Position - EyePosition) / 50.0f);
then in your pass switch the fog on like this:
pass P0 { FOGENABLE = (3); FOGCOLOR = (float4(1,1,1,1)); // VShader // PShader }
Hope this helps.
|
|
-
|
|
|
Thanks Chazsoft that got fog working.
I noticed if i turn the fog color to black,it acutally makes the scene fade really good.
Besides that,
The fog sorta sticks to the ground, is there any way i can get it to hover above it.
Check out my blog for updates on my Game Dev: http://gmaker-gd.blogspot.com/
|
|
-
-
- (7647)
-
premium membership
MVP
-
Posts
5,876
|
|
Output.Fog only works in shader model 2, in general.
In shader model 3, you want to calculate the distance from the camera of the pixel, and then map that distance to a value between 0 and 1 using a fog function, and then lerp between the calculated pixel color (with texturing, lighting, etc), and the fog color, using that calculated value.
[source] // a simple linear-style fog function float fogNear : FOGNEAR; float fogFar : FOGFAR; float4 fogColor : FOGCOLOR; float3 cameraPos : CAMERAPOS;
// fragmentPos can be forwarded as an interpoland from the vertex shader float4 MyPixelShader(... float3 fragmentPos ...) { ... float d = length(fragmentPos - cameraPos); float l = saturate((d-fogNear)/(fogFar-fogNear)); return lerp(outColor, fogColor, l); } [/source]
This will fog everything in an even manner, based on distance from camera. You can make altitude-based fog by adjusting the fog factor based on elevation above ground through this little tweak:
[source] float fogAltitudeScale : FOGALTITUDESCALE = 20; ... // assuming fragmentPos.z is "altitude" float l = saturate((d - fogNear)/(fogFar - fogNear) / clamp(fragmentPos.z / FOGALTITUDESCALE + 1, 1, 10)); [/source]
You might want to change the "+1" and "10" values of that equation to tunable parameters, too; the former controls how high up the fog will start thinning out, and the 10 controls the maximum amount of thinning.
Jon Watte, Direct3D MVP Tweets, occasionallykW X-port 3ds Max .X exporter kW Animation source code
|
|
-
-
- (330)
-
premium membership
MVP
-
Posts
282
|
|
Cool!
Jwatte, Can you apply the FOGALTITUDESCALE to SM2 as well??
|
|
-
-
- (352)
-
premium membership
-
Posts
342
|
|
You can calculate fog manually (which is what the example does) in any shader model as long as your calculations fit into the capabilities of the shader model. The semantic FOGALTITUDESCALE that Jon used in his example is just a way of identifying the shader parameter to his code - the parameters are being identified by semantic rather than by name. He could have called it JONSWKDFOGFACTOR or anything else. Unlike vertex component semantics (POSITION, TEXCOORD, etc.) which must be recognised by the graphics API, the semantics on shader parameters are entirely for your own use and don't mean anything to the graphics API.
So, yes that example should work in SM2 :)
Cheers, Leaf.
|
|
-
|
|
|
jwatte, do you have any good link or recommendation of a book where I can learn these things? it seems shaders just get deeper and deeper. lol.
|
|
-
-
- (330)
-
premium membership
MVP
-
Posts
282
|
|
Leaf,
Ahh, of course it is silly me :) I really should read things properly...
Have sent you a mail regarding this method, thanks for your help. Thanks for your comment on the blog too :)
|
|
-
-
- (330)
-
premium membership
MVP
-
Posts
282
|
|
On the thread of doing fog in the shader for SM3, can any of you guys give an example, it's just that I/most of us are new too all this and just telling us how to go about doing something does not cut it every time (probably just me here), and an example would be great, even if it is just for a simple Texture shader with the SM3 fog logic in it.
Thanks.
|
|
-
-
- (7647)
-
premium membership
MVP
-
Posts
5,876
|
|
Where to learn shaders? I don't know. I started learning about 3D using the POV-Ray program in the late 80s (text-based ray tracing app); then I took the Foley / van Dam graphics class in college, and then I've just kept up to date by following mailing lists and forums.
I would imagine that starting by downloading RenderMonkey and/or FX Composer, and going through the tutorials and examples ought to be a good start. Following the easier HLSL examples in the DirectX SDK would also help. The DirectX SDK documentation is useful, too, because it documents everything about how the shader models actually fit in the pipeline, and all of the HLSL language.
Here's a shader (2.0) that calculates its own fog factor, but which uses fixed-function fog application. If you want less fog for taller things, you could adjust that when calculating Output.Fog, based on the height of the vertex.
[/source] float4 g_MaterialAmbientColor< string UIName = "Ambient"; > = float4( 0.1, 0.1, 0.15, 1 ); // Material's ambient color float4 g_MaterialDiffuseColor< string UIName = "Diffuse"; > = float4( 0.9, 0.85, 0.7, 0 ); // Material's diffuse color float3 g_LightDir : Direction < string UIName = "Light Direction"; string Object = "TargetLight"; > = float3( -0.3, 0.8124, -0.5 ); // Light's direction in world space float4 g_LightDiffuse< string UIName = "Light Diffuse Color"; > = float4( 1, 1, 1, 0 ); // Light's diffuse color
texture g_MeshTexture : DiffuseMap< string UIName = "Diffuse Texture"; >; // Color texture for mesh texture g_NormalTexture : NormalMap< string UIName = "Normal Map"; >; // Large-scale normal map texture g_NormalDetail : NormalDetail< string UIName = "Normal Detail"; >; // Fins-scale normal map float4x4 g_mWorldViewProjection : WORLDVIEWPROJ; // World * View * Projection matrix float4x4 g_mWorld : WORLD;
float4 g_FogColor : FogColor< string UIName = "Fog Color"; > = float4(0.5, 0.5, 0.5, 1); float g_FogDistance : FogDistance< string UIName = "Fog Distance"; > = 2000.0;
float g_NormalUVScale = 256;
sampler MeshTextureSampler = sampler_state { Texture = <g_MeshTexture>; MipFilter = LINEAR; MinFilter = ANISOTROPIC; MagFilter = LINEAR; MaxAnisotropy = 8; };
sampler NormalTextureSampler = sampler_state { Texture = <g_NormalTexture>; MipFilter = LINEAR; MinFilter = ANISOTROPIC; MagFilter = LINEAR; MaxAnisotropy = 8; };
sampler NormalDetailSampler = sampler_state { Texture = <g_NormalDetail>; MipFilter = LINEAR; MinFilter = ANISOTROPIC; MagFilter = LINEAR; MaxAnisotropy = 8; };
struct VS_OUTPUT { float4 Position : POSITION; // vertex position float4 Diffuse : COLOR0; // vertex diffuse color (note that COLOR0 is clamped from 0..1) float2 TextureUV : TEXCOORD0; // vertex texture coords float3 PNormal : TEXCOORD1; // vertex normal float3 PTangent : TEXCOORD2; // vertex U tangent float3 PBitangent : TEXCOORD3; // vertex V tangent float Fog : FOG; // vertex fog };
VS_OUTPUT RenderSceneVS( float4 vPos : POSITION, float3 vNormal : NORMAL, float2 vTexCoord0 : TEXCOORD0 ) { VS_OUTPUT Output; float4 oPos; // Transform the position from object space to homogeneous projection space oPos = mul(vPos, g_mWorldViewProjection); Output.Position = oPos; float3 mNormal = normalize(mul(vNormal, (float3x3)g_mWorld)); Output.PNormal = mNormal; float3 mTangent = g_mWorld[0]; mTangent -= mNormal * dot(mNormal, mTangent); Output.PTangent = normalize(mTangent); Output.PBitangent = cross(mTangent, mNormal); // Calc diffuse color Output.Diffuse.rgb = g_MaterialDiffuseColor; Output.Diffuse.a = 1.0f; // Just copy the texture coordinate through Output.TextureUV = vTexCoord0;
Output.Fog = 1 - saturate((oPos.z - g_FogDistance * 0.2f) / (g_FogDistance * 0.8f));
return Output; }
struct PS_OUTPUT { float4 RGBColor : COLOR0; // Pixel color };
PS_OUTPUT RenderScenePS( VS_OUTPUT In ) { PS_OUTPUT Output;
float3 mNormalDetail = tex2D(NormalDetailSampler, (In.TextureUV - float2(0.5, 0.5)) * g_NormalUVScale) * 2 - 1; float3 mNormal = tex2D(NormalTextureSampler, In.TextureUV) * 2 - 1; mNormal = mNormal + mNormalDetail; float4 color = tex2D(MeshTextureSampler, In.TextureUV);
mNormal = In.PTangent * mNormal.x + In.PBitangent * mNormal.y + In.PNormal * mNormal.z; mNormal = normalize(mNormal); float diffuse = max(0, dot(mNormal, g_LightDir)); Output.RGBColor = color * ((In.Diffuse * g_MaterialDiffuseColor) * diffuse + g_MaterialAmbientColor);
return Output; }
technique RenderScene { pass P0 { AlphaBlendEnable = false; ZEnable = true; ZWriteEnable = true; CullMode = CCW; FogEnable = TRUE; FogVertexMode = LINEAR; FogColor = (g_FogColor); FogStart = (g_FogDistance / 5); FogEnd = (g_FogDistance); VertexShader = compile vs_2_0 RenderSceneVS(); PixelShader = compile ps_2_0 RenderScenePS(); } } [/source]
Jon Watte, Direct3D MVP Tweets, occasionallykW X-port 3ds Max .X exporter kW Animation source code
|
|
-
-
- (330)
-
premium membership
MVP
-
Posts
282
|
|
Awesome, thanks for the shader example.
FXComposer is great to get started with, lots of good examples to leanr from and if the shader you have written is wrong, you know it's your shader and not your XNA code.
As Leaf and others have pointed out this method will not work on the XBox 360 or on SM3, can anyone give us an example of this please? It does not have to be as large as the one put up by jwatte, just one that will demonstrate how to do it under SM3. If I am missing something with the shader above and this too can be applied on the XBox 360, can you explain the diffrence between my attempt and the shader given above.
Sorry for all the asks, but if you don't ask you wont get and I am hear to learn as much as I can and this seems the best place to ask :)
Thanks.
|
|
-
-
- (7647)
-
premium membership
MVP
-
Posts
5,876
|
|
The simple way to do it:
1) Change the FOG output sematic to something like TEXCOORD5.
2) Right before returning the color in the pixel shader, do a lerp() between the calculated color, and the fog color, based on the TEXCOORD5 input value. It really is a one-liner.
That gives you per-vertex fog calculation instead of per-pixel, but unless you use really large triangles that are fogged when you're near them, you're unlikely to see any difference.
In the shader I posted, you change the following lines (red old, green new):
float Fog : FOG; // vertex fog float Fog : TEXCOORD4; // vertex fog
Output.RGBColor = color * ((In.Diffuse * g_MaterialDiffuseColor) * diffuse + g_MaterialAmbientColor); Output.RGBColor = lerp(g_FogColor, color * ((In.Diffuse * g_MaterialDiffuseColor) * diffuse + g_MaterialAmbientColor), In.Fog);
That's the only change, and it'll work on SM 3 and other such targets. You should turn off the FOG render state in the technique/pass set-up, too.
FogEnable = TRUE; FogVertexMode = LINEAR; FogColor = (g_FogColor); FogStart = (g_FogDistance / 5); FogEnd = (g_FogDistance); FogEnable = FALSE;
Btw: As you probably see, the shader I posted uses two tangent-space normal maps; one for the 0..1 UV range, and one for tiling. The reason for this is that I use that shader for my height map implementation, where I use the large normal map instead of vertex normals. If you have another source of normals, you can remove all that complexity per-pixel.
Jon Watte, Direct3D MVP Tweets, occasionallykW X-port 3ds Max .X exporter kW Animation source code
|
|
-
-
- (330)
-
premium membership
MVP
-
Posts
282
|
|
Brilliant!
Thank you so much, you are now my HLSL guru :) I am not to bothered about the application of your shader, as I can just take the "Fog" code and now bolt it into my shaders. I will have a play with the SM2 one you put up as I am sure there is stuff in there that I can leanr from.
Thanks guys, with out people like you contributing to these boards I think XNA and home brew games in general would be moving at a much slower pace.
Thanks again.
|
|
-
-
- (352)
-
premium membership
-
Posts
342
|
|
I knocked up a quick sample of fogging that includes Jon's height fogging code. You can get it here. Cheers, Leaf.
|
|
-
-
- (330)
-
premium membership
MVP
-
Posts
282
|
|
Thanks :)
I have updated my blog, would one of you guys be kind enough to pop along and make sure what I have put is correct (guess I should not be posting on stuff I dont fully know right!, but it is up now...) It is here
|
|
-
|
|
|
Sorry for the bump, but I just implemented this fog shader into my little engine, and apply the fog-function to my terrain, water, vegetation etc. I noticed that this costs me 50fps, the framerate drops from 150fps to 100fps from the same position. Here's the shader: float4 calculateFog(float4 Color, float3 Position) { if(!FogEnable) return Color; else { float d = length(Position - CameraPos); // float l = saturate((d - FogNear) / (FogFar - FogNear) / clamp(Position.y / FogAltitudeScale + 1, 1, FogThinning)); float l = saturate((d - FogNear) / (FogFar - FogNear)); return lerp(Color, FogColor, l); } } Removing the braching (FogEnable) doesn't make any difference, so I guess it's the math functions that have effect on my fillrate limitated graphics card? (GF6800gt)
|
|
-
-
- (7647)
-
premium membership
MVP
-
Posts
5,876
|
|
Yes, it's likely the math. However, a 33% reduction in fill rate means that your pixel shader probably is pretty simple, so adding the fog adds noticably extra data. If your pixel shader were more complex (say, with normal maps and normal mapped environment maps), then the fog would be less noticeable.
One thing you can do is to calculate the length and division in the vertex shader, and send the quotient in as an interpoland, and then only do the saturate() per-pixel. That's sure to reduce the impact of the fog calculation.
Jon Watte, Direct3D MVP Tweets, occasionallykW X-port 3ds Max .X exporter kW Animation source code
|
|
-
|
|
|
Thanks, the performance boost ist pretty significant, almost back to 150fps again.
Too bad it adds some extra work to change every single vertex shader - previously I only had to call my "calculateFog" function from every pixel shader.
As for the shaders - I'm using a water shader, a terrain with 5 tex2D instructions, a skybox (again, 1 tex2D for each side) and an instancing shader for geometry. While 100fps are still fine I think I'm slowly reaching the limits of my card.
|
|
|