Generating a Normal Map

Started by
51 comments, last by Geometrian 13 years, 6 months ago
//------- Constants --------float4x4 xView;float4x4 xProjection;float4x4 xWorld;float4x4 TangentMatrix;float3 xLightDirection;float xAmbient;bool xEnableLighting;float4 lightColor = float4(1,1,1,1);float3 ambientColor = float3(1,1,1);//------- Texture Samplers --------Texture xTexture1;sampler TextureSampler1 = sampler_state { texture = <xTexture1>; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = wrap; AddressV = wrap;};Texture xNormal1;sampler NormalSampler1 = sampler_state { texture = <xNormal1>; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = wrap; AddressV = wrap;};//------- Technique: Textured --------struct TexVertexToPixel{    float4 Position   	: POSITION0;        float4 Color		: COLOR0;    float LightingFactor: TEXCOORD0;    float2 TextureCoords: TEXCOORD1;    float3 vView        : TEXCOORD2;    float3 UP           : POSITION1;    float3 RIGHT        : POSITION2;    float3 NORMAL       : NORMAL0;};struct TexPixelToFrame{    float4 Color : COLOR0;};TexVertexToPixel TexturedVS( float4 inPos : POSITION0, float3 inNormal: NORMAL0, float4 inUp : POSITION1, float4 inRight : POSITION2 ,float2 inTexCoords: TEXCOORD0){		TexVertexToPixel Output = (TexVertexToPixel)0;	float4x4 preViewProjection = mul (xView, xProjection);	float4x4 preWorldViewProjection = mul (xWorld, preViewProjection);    	Output.Position = mul(inPos, preWorldViewProjection);		Output.TextureCoords = inTexCoords;		//enable for better light...	float3 Normal = normalize(inNormal);		Output.LightingFactor = 1;	if (xEnableLighting)		Output.LightingFactor = saturate(dot(Normal, xLightDirection));			Output.Color = float4(1.0f, 0.0f, 0.0f, 1.0f);		Output.vView = -xView[3].xyz - Output.Position;	        Matrix world2;        world2[0].x=xworld[0].x;        world2[0].y=xworld[0].y;        world2[0].z=xworld[0].z;        world2[1].x=xworld[1].x;        world2[1].y=xworld[1].y;        world2[1].z=xworld[1].z;        world2[2].x=xworld[2].x;        world2[2].y=xworld[2].y;        world2[2].z=xworld[2].z;        world2[0].w=0;                world2[1].w=0;                world2[2].w=0;                world2[3].x=0;        world2[3].y=0;        world2[3].z=0;        world2[3].w=1;            Output.UP = mul(inUp, world2);	Output.RIGHT = mul(inRight, world2);    Output.NORMAL = mul(inNormal, world2);    	return Output;     }TexPixelToFrame GDPS(TexVertexToPixel PSIn) {	TexPixelToFrame Output = (TexPixelToFrame)0;	        float3 right=normalize(PSIn.RIGHT);        float3 up=normalize(PSIn.UP);        float3 front=normalize(PSIn.NORMAL);	//float4x4 TangentMatrix;	TangentMatrix[0].x=right.x;  TangentMatrix[0].y=right.y;  TangentMatrix[0].z=right.z;   TangentMatrix[0].w=0;	TangentMatrix[1].x=up.x;     TangentMatrix[1].y=up.y;     TangentMatrix[1].z=up.z;      TangentMatrix[1].w=0;	TangentMatrix[2].x=front.x; TangentMatrix[2].y=front.y; TangentMatrix[2].z=front.z;  TangentMatrix[2].w=0;	TangentMatrix[3].x=0;             TangentMatrix[3].y=0;             TangentMatrix[3].z=0;              TangentMatrix[3].w=1;		float3 lightdir_in_tangent_space = mul(xLightDirection, TangentMatrix);	float3 nor=tex2D(NormalSampler1, float2(PSIn.TextureCoords)).rgb*2-1; 	float pixel_light=dot(lightdir_in_tangent_space, -nor);	Output.Color.rgb = tex2D(TextureSampler1, float2(PSIn.TextureCoords)).rgb;	//Output.Color *= float4(pixel_light.r,pixel_light.g,pixel_light.b, 1);	Output.Color *= pixel_light;		//Output.Color.rgb *= saturate(PSIn.LightingFactor);	Output.Color.a = 1;		return Output;}technique Textured{	pass Pass0    {       	VertexShader = compile vs_3_0 TexturedVS();        PixelShader  = compile ps_3_0 GDPS();    }}


then if that gives you bad results, play with the cross products before you think this doesnt work!
Advertisement
Damn you certainly know your stuff. It worked a charm. By stripping out that row of information from the original world matrix, what has that actually changed. Just so I'm still following whats actually going on.

Apart from that do you know what causes the soft S line in this shadow and what causes the big black circle to appear?

image

So in the case of whats happening with these then, would it be something to do with all this cross producting stuff thats going on?

image
I take it your looking up at the pole of the planet, this is because the top and bottom tangent values arent applying properly. fetch me the part where you build the sphere and form the tangent space, ill fix it for you. :)

Hey my pleasure man, its just a thrill watching a newer guy learn all this stuff! :)

Not sure whats causing the s-curve tho, Just let me have a look and think about this tangent space creation.

The information stripped out of the world matrix is the translation and scaling row and column, the orientation (which is all you need to transform a normal by) is in the rest of the matrix without the rest.

The problem comes down to "translating" or "scaling" a normal when your transforming one, really all you want to do is "rotate" it.

So your effectively rotating the tangents as you rotate the sphere, like you should.
Thought i'd try to make this a little neater for you.

My planet.cs is this one on line 98 is where the normal map is generated.
http://pastebin.com/twnRyT3G

I generate my sphere in this one on line 99, so you should be able to just check this one out if anything and see my sphere creation.
http://pastebin.com/AtYRZzJy

So do you work as a programmer now, in the games industry or anything? I'm currently at the end of my course studying game programming :)
I consider myself an experienced hobbyest, maybe i could have had a job sometime and still might, but I only ever figured out stuff myself for fun...

If you could only render a movie, then id have a better idea!


public void CreateSphere(ref VertexPositionNormalUpRightTexture[] vpnt, ref int[] indices, int m_NumSlices, int m_NumStacks, float m_Radius)        {            int tDiv = m_NumSlices;            int pDiv = m_NumStacks;            float dt = ((float)Math.PI * 2) / tDiv;            float dp = (float)Math.PI / pDiv;             int vertex = 0;            for (int pi = 0; pi <= pDiv; pi++)            {                float phi = pi * dp;                 for (int ti = 0; ti <= tDiv; ti++)                {                    // we want to start the mesh on the x axis                    float theta = ti * dt;                     vpnt[vertex].Position = GetPosition(theta, phi, m_Radius);                    vpnt[vertex].Normal = GetNormal(theta, phi);                    vpnt[vertex].Texture = GetTextureCoordinate(theta, phi);                    vertex++;                }            }             int index = 0;            for (int pi = 0; pi < pDiv; pi++)            {                for (int ti = 0; ti < tDiv; ti++)                {                    int x0 = ti;                    int x1 = (ti + 1);                    int y0 = pi * (tDiv + 1);                    int y1 = (pi + 1) * (tDiv + 1);                     indices[index] = x0 + y0;                    indices[index + 1] = x0 + y1;                    indices[index + 2] = x1 + y0;                     indices[index + 3] = x1 + y0;                    indices[index + 4] = x0 + y1;                    indices[index + 5] = x1 + y1;                   index += 6;                }            }            for (int i = 0; i < vertex; i++)            {                Vector3.Normalize(ref vpnt.Position, out vpnt.Normal);                vpnt.Up = new Vector3(0, 1, 0);                if(acosf(Vector3.Dot(vpnt.Up,vpnt.Normal))<0.1f)                {                 vpnt.Up = new Vector3(0, 0, 1);                }                if(acosf(Vector3.Dot(-vpnt.Up,vpnt.Normal))<0.1f)                {                 vpnt.Up = new Vector3(0, 0, 1);                }                Vector3 cross = Vector3.Cross(vpnt.Normal, vpnt.Up);                Vector3.Normalize(ref cross, out vpnt.Right);                vpnt.Up = Vector3.Cross(vpnt.Normal, vpnt.Right);            }        }
Man I don't know how you even managed to think of a way around it like that lol. Last thing I would of thought of doing. It fixes the pole issues 100% :)

Only thing now is the weird way the shadow is applying itself, I'd gather thats back in the shader that this problem is?

image

EDIT:
You do all this for fun! Far out, you must either really enjoy learning this stuff or find a lot of it is pretty natural for you?

EDIT:
Thanks for all your help today :) I've learnt a few new things now that I'm quite happy with. Thanks for the effort you put into showing me how to do some of these techniques. Hopefully I can figure this shadow stuff out at some stage as it can look pretty weird from afar. Apart from that time to watch some Stargate and hit the sack :)

[Edited by - Scottehy on October 21, 2010 9:35:56 AM]
Im not sure, try mucking around with the cross products when it makes the tangent vectors (up, right and normal)

I think im about out of ideas now, im not sure what could be going wrong!
ok np... see u tomorrow?
Back and ready for action, I'm going to have a little play with the tangent matrix to see if that is any of the possible causes for whats happening with the shadows?
Quote:Original post by rouncED
I think im about out of ideas now, im not sure what could be going wrong!
Nothing, apart from the fact that you two are trying to normal-map a sphere in tangent space. AFAIK, there is no way to completely eliminate the artefacts at the poles.

Is there any particular reason why you don't want to normal-map in object-space? This has typically been my solution in the past.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

This topic is closed to new replies.

Advertisement