OpenGl法向量计算

来源:互联网 发布:虎牙直播点歌软件 编辑:程序博客网 时间:2024/05/01 05:12

一、简介

顶点法向量的作用: 对渲染时光照的影响,造成不同的反射角度。

法向量:垂直于顶点所在的最小平面的单位向量,这个值是近似值。

二、目的

如何计算顶点法向量?

三、我的总结

网上对于法向量的计算方法有多种: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()便是计算法向量方法。


                                             
0 1