根据模型顶点坐标计算法线

虽然读取了3ds文件,但是3ds文件里并不包含顶点法线。为了计算光照,我们需要手工计算法线。过程如下:

三个不共线点构成一个三角形:

计算方法:向量ab与向量ac的叉乘得到过点a垂直于三角形abc所在平面的一条直线,这条垂线就是顶点a的法线。

下面就是代码:【修正了法线计算bug,2012.04.04】

 1 void CModel3ds::CalcNormals()
2 {
3 for(int i = 0; i<m_PolygonNum; ++i)
4 {
5 Vector3 v1 = Vector3_Sub(Vector3(m_pVBbuff[m_pIBbuff[i].p1].X, m_pVBbuff[m_pIBbuff[i].p1].Y, m_pVBbuff[m_pIBbuff[i].p1].Z),
6 Vector3(m_pVBbuff[m_pIBbuff[i].p2].X, m_pVBbuff[m_pIBbuff[i].p2].Y, m_pVBbuff[m_pIBbuff[i].p2].Z));
7 Vector3 v2 = Vector3_Sub(Vector3(m_pVBbuff[m_pIBbuff[i].p1].X, m_pVBbuff[m_pIBbuff[i].p1].Y, m_pVBbuff[m_pIBbuff[i].p1].Z),
8 Vector3(m_pVBbuff[m_pIBbuff[i].p3].X, m_pVBbuff[m_pIBbuff[i].p3].Y, m_pVBbuff[m_pIBbuff[i].p3].Z));
9 Vector3 tmp1 = Vector3_cross(v1,v2);
10 m_pVBbuff[m_pIBbuff[i].p1].nx += tmp1.x;
11 m_pVBbuff[m_pIBbuff[i].p1].ny += tmp1.y;
12 m_pVBbuff[m_pIBbuff[i].p1].nz += tmp1.z;
19 m_pVBbuff[m_pIBbuff[i].p2].nx += tmp1.x;
20 m_pVBbuff[m_pIBbuff[i].p2].ny += tmp1.y;
21 m_pVBbuff[m_pIBbuff[i].p2].nz += tmp1.z;
28 m_pVBbuff[m_pIBbuff[i].p3].nx += tmp1.x;
29 m_pVBbuff[m_pIBbuff[i].p3].ny += tmp1.y;
30 m_pVBbuff[m_pIBbuff[i].p3].nz += tmp1.z;
31 }
32
33 for(int i = 0; i < m_VertexNum; ++i)
34 {
35 Vector3_norm(m_pVBbuff[i].nx,m_pVBbuff[i].ny,m_pVBbuff[i].nz);
36 }
37 }

上面这段代码简单来说就是求共顶点的三角形在其公共顶点的法线的平均值,他的结果当然不是精确的,但是大多数时候都是正常工作的:)


代码中定义的向量运算用到了我写的一个数学库中的函数,这个数学库不是为了效率,只是为了让上面的代码跟dx解耦,避免发代码还要包含一堆头文件。不然的话拷贝这段代码就很肯能因为头文件的问题导致不能编译,这又会导致一大堆麻烦事,所以下面这个库代码,仅仅就是保证正常工作(或许也有bug,但我会努力去fix和避免这种情况):

View Code
 1 #ifndef myVector_h__
2 #define myVector_h__
3
4 namespace MY_MATH
5 {
6 class Vector3
7 {
8 public:
9 Vector3():x(0),y(0),z(0){}
10 Vector3(float _x, float _y, float _z):x(_x),y(_y),z(_z){}
11 float x;
12 float y;
13 float z;
14 };
15
16 Vector3 Vector3_Sub(Vector3 src,Vector3 dest)
17 {
18 return Vector3(src.x - dest.x,src.y - dest.y,src.z - dest.z);
19 }
20
21 void Vector3_norm(float& x, float& y, float& z)
22 {
23 float tmp = sqrtf(x*x+y*y+z*z);
24 x = x/tmp;y = y/tmp; z=z/tmp;
25 }
26
27 void Vector3_norm(Vector3& vec)
28 {
29 float tmp = sqrtf(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
30 vec.x = vec.x/tmp;
31 vec.y = vec.y/tmp;
32 vec.z = vec.z/tmp;
33 }
34
35 Vector3 Vector3_cross(Vector3& v1, Vector3& v2)
36 {
37 return Vector3(v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x);
38 }
39 }
40
41
42
43 #endif // myVector_h__



这个就是根据我们计算出来的法线进行基本光照渲染出来的截图,HLSL版本shader如下:

cbuffer mybuff
{
uniform row_major float4x4 world_matrix;
uniform row_major float4x4 view_matrix;
uniform row_major float4x4 proj_matrix;
uniform float4 light_pos;
};

struct VS_INPUT
{
float4 Position : POSITION;
float3 Norm : NORMAL0;
float2 Tex : TEXCOORD0;
};

struct VS_OUTPUT
{
float4 Position : SV_POSITION;
float3 lt : TEXCOORD0;
float3 norm : TEXCOORD1;
};

VS_OUTPUT VS_MAIN(VS_INPUT In)
{
VS_OUTPUT Output;
float4x4 tmp = mul(world_matrix,view_matrix);
tmp = mul(tmp,proj_matrix);
Output.Position = mul(In.Position, tmp);

Output.lt = normalize(light_pos - In.Position);
Output.norm = normalize(mul(In.Norm, world_matrix));

return Output;
}

float4 PS_MAIN(VS_OUTPUT In) : SV_Target
{
float4 diff = {1.0,1.0,1.0,1.0};
float4 ambient = {0.1,0.1,0.1,1.0};
return ambient + diff*saturate(dot(In.lt,In.norm));
}



posted on 2012-04-01 15:34  Meta.Grfx  阅读(8413)  评论(4编辑  收藏  举报

导航