一、简介
顶点法向量的作用: 对渲染时光照的影响,造成不同的反射角度。
法向量:垂直于顶点所在的最小平面的单位向量,这个值是近似值。
二、目的
如何计算顶点法向量?
三、我的总结
网上对于法向量的计算方法有多种: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()便是计算法向量方法。