vertex shader normal generation

Started by
7 comments, last by murderv 15 years ago
hi. im using a vertex shader to generate different shapes (in this case a sphere) and trying to compute the normals aswell. what im doing is passing a grid mesh of size 100x100 (the plane coordinates are from 0.0 to 1.0) and in the shader i use the vertices to generate a sphere by this function:

float3 getSpherePoint( float u, float v )
{
	float x = cos(v) * sin(u);
	float y = sin(v) * sin(u);
	float z = cos(u);
	return float3( x, y, z );
}
the vertex shader follows:

vertexOutput VS_GoochySpecular( in vertexInput IN )
{
    vertexOutput OUT = (vertexOutput)0;

	float step = (1/100.0); // one step

        float u = (IN.position.x) * TWOPI;
        float v = (IN.position.y) * PI;

	float3 pos = getSpherePoint( u, v );

	// Compute tangents and normals
	float3 tangent = getSpherePoint( u-(step/2), v ) - getSpherePoint( u+(step/2), v );
	float3 bitangent = getSpherePoint( u, v-(step/2) ) - getSpherePoint( u, v+(step/2) );
	
	float3 normal = normalize( cross( tangent, bitangent ) );

	// scale sphere
	pos *= a;
	
    float4 Po = float4( pos, 1 );
    OUT.position = mul( worldViewProj, Po ); 
    float3 worldpos = mul(matWorld, Po).xyz;	// in "world" coordinates
    float3 viewpos = mul(matView, float4(worldpos,1.0)).xyz;	// in "view" coordinates
    OUT.worldPos = worldpos;

    OUT.normal = normalize( mul((float3x3)matViewIT, normal) );
    float3 L = viewL - (viewpos.xyz*lightPos.w);
    OUT.lightVec = L;

    OUT.viewVec = normalize( float3(matViewIT[0].w, matViewIT[1].w, matViewIT[2].w) - viewpos.xyz);


    return OUT;
}
the problem is that the bottom hemisphere of the sphere has the lighting inverted. i have disabled face culling. when enabled i can see the normals are inverted. my question is why everything below y=0 inverts ? check this shot: Free Image Hosting at www.ImageShack.us best regards,
Advertisement
Your getSpherePoint assumes u between 0 and PI and v between 0 and 2*PI.
Also, you don't have to compute a tangent vector and a bitangent vector to compute the normal of a sphere. The normal is simply getSpherePoint.
thank you. i was so blind i didnt even see that.

as for the normals thing, im trying to find a way to compute vertex normals for distorted objects that can be generated at the vertex shader.

im not sure if this method will work. im hoping it does. would you know anything about that ?
The method will work, but there's a better way to do it if you can.
Instead of sampling your function 5 times (once for position, 2 for the tangent and 2 for the bitangent), you can compute the normal by
n = cross(df/du, df/dv) (up to normalization),
where df/du and df/dv are the partial derivatives of your function (e.g. getSpherePoint) by u and v, resp.
In your example,
df/du = ( cos(v)*cos(u), sin(v)*cos(u), -sin(u) )
df/dv = ( -sin(v)*sin(u), cos(v)*sin(u), 0 ),
so that
n = ( sin(u)*sin(u)*cos(v), sin(u)*sin(u)*sin(v), (cos(v)*cos(v) + sin(v)*sin(v))*cos(u)*sin(u) )
n = sin(u) * (cos(v) * sin(u), sin(u)*sin(v), cos(u))
n = sin(u) * getSpherePoint(u,v)
This even works for stuff like Perlin noise (which comes in very handy).

- Lutz
hi lutz, i dont get that much on that derivative stuff.
are you telling me that

normal = sin(u) * getSpherePoint( u, v );

would give me correct normals for sphere mesh generated, and for perlin noise aswell ?

it looks too simple too me =)
No, that was just an example to illustrate how it works. I used this example to verify what we already knew - that the normal direction for a sphere matches the direction to the point on the sphere. This way we could check that the calculations are correct.

In general, the normal direction is different from the direction to the point on the surface. For other objects like ellipsoids or Perlin noise you'll get other results. But the general way to compute the normal is the same. Let's say you write Perlin noise as function pos = f(u,v). Then the normal is given by normalize(cross(dfdu(u,v), dudv(u,v))), where you'll have to compute the partial derivatives dfdu and dfdv yourself.
ok so it all depends on the formula. for example i am using a distorted version of a sphere formula here now:

float3 getSpherePoint( float u, float v )
{
// 0 <= u <= PI, 0 <= v <= TWOPI

float x = cos(v) * sin(u) + sin(20*u+count.x) * 0.075;
float y = sin(v) * sin(u) + cos(10*u+count.x) * 0.075;
float z = cos(u);

//r += sin(0.25*x * count.x + time + phase.x) * amount.x;
//r += cos(u*count.y + phase.y) * amount.y;

// multiply by radius
return float3( x*r, y*r, z*r );
}

i did not understand anything on the way you calculate the dfdu/dfdv. i would like to know if is there a general way to compute it for different functions, no matter what they are, ellipse, sphere, cone, perlin, etc

if its not, how would i compute it myself as you said? what would u recommend i should read/do to get myself working this out.

thanks
Computing derivatives is done by applying some simple rules to general functions. I can't explain that in this post, it's nothing you can learn in one hour. If you really want to, I recommend you grab a book about calculus and learn how to do it.
ok, thank you for your help.

This topic is closed to new replies.

Advertisement