一、简介
顶点法向量的作用: 对渲染时光照的影响,造成不同的反射角度。
法向量:垂直于顶点所在的最小平面的单位向量,这个值是近似值。
二、目的
如何计算顶点法向量?
三、我的总结
网上对于法向量的计算方法有多种:1.取顶点周围三角面片的法向量的平均值 2.加权算法 3.....等,大同小异,无法就是取个近似值,每种方法在不同的情景中,所得的近似值各有千秋。
本文参考外文代码,给出实现的demo。
先参看下图;
代码是个加载地形的类:
class Terrain{ private: int w; int l; float** hs; Vec3f** normals; bool computedNormals; public: Terrain(int w2, int l2){ w = w2; l = l2; hs = new float*[l]; for (int i = 0; i < l; i++){ hs[i] = new float[w]; } normals = new Vec3f*[l]; for (int i = 0; i < l; i++){ normals[i] = new Vec3f[w]; } computedNormals = false; } ~Terrain(){ for (int i = 0; i < l; i++){ delete [] hs[i]; } delete[] hs; for(int i = 0; i < l; i++){ delete[] normals[i]; } delete[] normals; } int width(){ return w; } int length(){ return l; } void setHeight(int x, int z, float y){ hs[z][x] = y; computedNormals = false; } float getHeight(int x, int z){ return hs[z][x]; } void computeNormals(){ if(computedNormals){ return; } Vec3f** normals2 = new Vec3f*[l]; for (int i = 0; i < l; i++) { normals2[i] = new Vec3f[w]; } for(int z = 0; z < l; z++){ for (int x = 0; x < w; x++){ Vec3f sum(0.0f, 0.0f, 0.0f); Vec3f out; if (z > 0) { out = Vec3f(0.0f, hs[z-1][x] - hs[z][x], -1.0f); } Vec3f in; if(z < l - 1){ in = Vec3f(0.0f, hs[z + 1][x] - hs[z][x], 1.0f); } Vec3f left; if (x > 0){ left = Vec3f(-1.0f, hs[z][x-1] - hs[z][x], 0.0f); } Vec3f right; if (x < w - 1){ right = Vec3f(1.0f, hs[z][x+1] - hs[z][x], 0.0f); } if (x > 0 && z > 0){ sum += out.cross(left).normalize(); } if (x > 0 && z < l - 1){ sum += left.cross(in).normalize(); } if(x < w - 1 && z < l - 1){ sum += in.cross(right).normalize(); } if (x < w - 1 && z > 0){ sum += right.cross(out).normalize(); } normals2[z][x] = sum; } } const float FALLOUT_RATIO = 0.5f; for (int z = 0; z < l; z++) { for(int x = 0; x < w; x++){ Vec3f sum = normals2[z][x]; if(x > 0){ sum += normals2[z][x-1] * FALLOUT_RATIO; } if(x < w - 1){ sum += normals2[z][x+1] * FALLOUT_RATIO; } if(z > 0){ sum += normals2[z-1][x] * FALLOUT_RATIO; } if(z < l -1){ sum += normals2[z+1][x] * FALLOUT_RATIO; } if(sum.magnitude() == 0){ sum = Vec3f(0.0f, 1.0f, 0.0f); } normals[z][x] = sum; } } for (int i = 0; i < l; i++) { delete[] normals2[i]; } delete[] normals2; computedNormals = true; } Vec3f getNormal(int x, int z){ if (!computedNormals){ computeNormals(); } return normals[z][x]; } };
函数void computeNormals()便是计算法向量方法。