OpenGl法向量计算

一、简介

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

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

二、目的

如何计算顶点法向量?

三、我的总结

网上对于法向量的计算方法有多种:1.取顶点周围三角面片的法向量的平均值 2.加权算法 3.....等,大同小异,无法就是取个近似值,每种方法在不同的情景中,所得的近似值各有千秋。

本文参考外文代码,给出实现的demo。

先参看下图;

OpenGl法向量计算_第1张图片


代码是个加载地形的类:

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()便是计算法向量方法。


 

你可能感兴趣的:(顶点法向量)