http://www.polycount.com/forum/showthread.php?t=117185
I am making some custom terrain shaders with Strumpy's editor and I want to being able to create normals based on my blend MA Sk. Does anyone know how do I can turn grayscale data into basic normal mapping info? I have the seen someone do the unreal but I can ' t remember where.
You probably want to get the difference of the values pixel-by-pixel using DDX, I think.
Off the top of my head ... for CG/HLSL;
Float Heightmap = your height map value;
FLOAT3 Normal;
normal.x = DDX (heightmap);
Normal.y = Ddy (heightmap);
Normal.z = sqrt (1-NORMAL.X*NORMAL.X-NORMAL.Y * normal.y); Reconstruct Z component to get a unit normal.
For OpenGL, I think the functions is DFDX and DFDY.
DirectX11 have Ddx_fine and Ddy_fine which I think give more accurate results.
That ' ll give you the normal in, EHR ... screen space I think?
Otherwise You can sample the heightmap multiple times, offsetting it by a pixel and working out of the difference from those Values. That's should get you it in whatever space the base normal are in.
nicked frm here; http://www.gamedev.net/topic/594781-... mal-algorithm/
floatme =tex2d (Heightmapsampler,in.tex). x;floatn = tex2d (HEIGHTMAPSAMPLER,FLOAT2 (in.tex.x,in.tex.y+1.0/Heightmapsizey)). x;floats = tex2d (Heightmapsampler,float2 (in.tex.x,in.tex.y-1.0/Heightmapsizey)). x;floatE = tex2d (HEIGHTMAPSAMPLER,FLOAT2 (in.tex.x+1.0/heightmapsizex,in.tex.y)). x;floatW = tex2d (Heightmapsampler,float2 (in.tex.x-1.0/heightmapsizex,in.tex.y)). X //find perpendicular vector to norm:FLOAT3 temp = norm;//a temporary vector that's not parallel to normif(norm.x==1) Temp.y+=0.5;Elsetemp.x+=0.5;//form a basis with norm being one of the axes:FLOAT3 PERP1 =Normalize (Cross (norm,temp)); FLOAT3 Perp2=Normalize (Cross (NORM,PERP1));//Use the basis-to-move the normal in their own space by the offsetFLOAT3 Normaloffset =-bumpheightscale* (((n-me)-(s-me)) *perp1 + ((e-me)-(w-me)) *perp2); Norm+=Normaloffset;norm= normalize (norm);
Gave it a try out of curiosity.
Here's the Multi-sample method in a stripped-down surface shader.
I had to the handedness from the code above to match Unity (changing the sign of the operation when sampling the E and W values from + to-and vice versa).
Shader"debug/normal Map from Height"{Properties {_color ("Main Color", Color) = (1,1,1,1) _maintex ("Diffuse (RGB) Alpha (A)", 2D) =" White"{} _bumpmap ("Normal (normal)", 2D) ="Bump"{} _heightmap ("heightmap (R)", 2D) ="Grey"{} _heightmapstrength ("Heightmap Strength", Float) =1.0_heightmapdimx ("heightmap Width", Float) =2048_heightmapdimy ("heightmap Height", Float) =2048} subshader{Tags {"Rendertype"="Opaque"} cgprogram#pragmaSurface Surf Normalsheight#pragmaTarget 3.0structInput {float2 Uv_maintex; }; Sampler2d _maintex, _bumpmap, _heightmap; float_heightmapstrength, _heightmapdimx, _heightmapdimy; voidSurf (Input in, InOut surfaceoutput o) {O.albedo= Fixed3 (0.5); FLOAT3 Normal=Unpacknormal (tex2d (_bumpmap, In.uv_maintex)); floatme =tex2d (_heightmap,in.uv_maintex). x; floatn = tex2d (_HEIGHTMAP,FLOAT2 (in.uv_maintex.x,in.uv_maintex.y+1.0/_heightmapdimy)). X floats = tex2d (_heightmap,float2 (in.uv_maintex.x,in.uv_maintex.y-1.0/_heightmapdimy)). X floatE = tex2d (_HEIGHTMAP,FLOAT2 (in.uv_maintex.x-1.0/_heightmapdimx,in.uv_maintex.y)). X floatW = tex2d (_heightmap,float2 (in.uv_maintex.x+1.0/_heightmapdimx,in.uv_maintex.y)). X FLOAT3 Norm=Normal; FLOAT3 Temp= Norm;//a temporary vector that's not parallel to norm if(norm.x==1) Temp.y+=0.5; Elsetemp.x+=0.5; //form a basis with norm being one of the axes:FLOAT3 PERP1 =Normalize (Cross (norm,temp)); FLOAT3 Perp2=Normalize (Cross (NORM,PERP1)); //Use the basis-to-move the normal in their own space by the offsetFLOAT3 Normaloffset =-_heightmapstrength * (((n-me)-(s-me)) * PERP1 + ((e-me)-(w-me)) *PERP2); Norm+=Normaloffset; Norm=normalize (norm); O.normal=Norm; } inline Fixed4 lightingnormalsheight (surfaceoutput s, fixed3 Lightdir, Fixed3 Viewdir,fixedatten) {Viewdir=normalize (Viewdir); Lightdir=normalize (Lightdir); S.normal=normalize (s.normal); floatNdotl =dot (s.normal, lightdir); _lightcolor0.rgb=_lightcolor0.rgb; Fixed4 C; C.rgb= FLOAT3 (0.5) * Saturate (NDOTL) * _lightcolor0.rgb *Atten; C.A=1.0; returnC; } ENDCG} FallBack"Vertexlit"}
Derivative method works, but it's fucking ugly ' cause it ' s in screen space-really noisy.
Ddx_fine might give better results in DX11, but it looks like crap in DX9.