|
|
发表于 2008-4-22 00:48:00
|
显示全部楼层
Re:关于shader中像素的法向量的问题,求助
帮你在网上找了一个:
为任意网格的每个顶点计算切线空间的基向量
以下代码为一个任意网格计算每个顶点的切向量.要知道详细的数学推算,请跟贴。这段代码产生具有四个元素的切向量T(位于局部坐标系,w为第4元素,为标识使用左手还是右手坐标系),然后binormal 向量可以通过顶点法线N和T叉乘算出。
这段代码使用了Point2D, Vector3D, Point3D, Vector4D这几个类。
帮助理解:术语binormal(副法线)通常做为二次切线向量的替代名而被使用(此向量与面法线和切线为正交向量,可以共同组成一个切线坐标系,既切线空间)。这是一个不太适当的用词,副法线是二次切线向量而不是真的什么法线。术语binormal出现在曲线研究中。曲线只有一条切线,还有两条正交向量,就是normal和binormal。当讨论平面上一顶点的坐标系时,有一条法线,两条切线,这两条切线应叫主切线和二次切线。
就这样,有许多人错误的将bitangent叫成binormal,而且流行起来了。所以,一般在凹凸映射时为bitangent正名,使用它,而不是使用误叫的术语binormal.
代码如下:
#include "Vector4D.h"
//三角形结构,用于保存顶点索引。
struct Triangle
{
unsigned short index[3];
};
//计算切线。将其放入动态申请的内存中,注意有两条切线,一条为主切线,一条为二次切线。
//函数in值为顶点数vertexCount, 顶点信息数组vertex, 顶点法线数组,顶点纹理坐标数组,三角形数,
//三角形数组, 接收切线的数组指针。
void CalculateTangentArray(long vertexCount, const Point3D *vertex, const Vector3D *normal,
const Point2D *texcoord, long triangleCount, const Triangle *triangle, Vector4D *tangent)
{
//一个顶点对应两条切线,所以先在tan1中申请了2倍顶点数的3D向量空间。
//tan1为主切线存放地址起点
Vector3D *tan1 = new Vector3D[vertexCount * 2];
//tan2为二次切线存放地址起点
Vector3D *tan2 = tan1 + vertexCount;
//将两种切线存放空间清空先
ClearMemory(tan1, vertexCount * sizeof(Vector3D) * 2);
//对于每个三角形
for (long a = 0; a < triangleCount; a++)
{
//获取第a个三角形的三个顶点索引 i1, i2, i3。
long i1 = triangle->index[0];
long i2 = triangle->index[1];
long i3 = triangle->index[2];
//通过顶点索引获取3个真实顶点的位置信息。
const Point3D& v1 = vertex[i1];
const Point3D& v2 = vertex[i2];
const Point3D& v3 = vertex[i3];
//获取顶点的纹理坐标信息。
const Point2D& w1 = texcoord[i1];
const Point2D& w2 = texcoord[i2];
const Point2D& w3 = texcoord[i3];
//然后根据算法得切线数据
float x1 = v2.x - v1.x;
float x2 = v3.x - v1.x;
float y1 = v2.y - v1.y;
float y2 = v3.y - v1.y;
float z1 = v2.z - v1.z;
float z2 = v3.z - v1.z;
float s1 = w2.x - w1.x;
float s2 = w3.x - w1.x;
float t1 = w2.y - w1.y;
float t2 = w3.y - w1.y;
float r = 1.0F / (s1 * t2 - s2 * t1);
Vector3D sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
Vector3D tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
//将计算的第a个面的3个顶点的主切线保存
tan1[i1] += sdir;
tan1[i2] += sdir;
tan1[i3] += sdir;
//将计算的第a个面的3个顶点的二次切线保存
tan2[i1] += tdir;
tan2[i2] += tdir;
tan2[i3] += tdir;
//求下一个
triangle++;
}
for (long a = 0; a < vertexCount; a++)
{
const Vector3D& n = normal[a];
const Vector3D& t = tan1[a];
// Gram-Schmidt orthogonalize
tangent[a] = (t - n * Dot(n, t)).Normalize();
// 计算使用左手系还是右手系,情况保存在w元素中。
tangent[a].w = (Dot(Cross(n, t), tan2[a]) < 0.0F) ? -1.0F : 1.0F;
}
delete[] tan1;
}
此信息来自〖软工吧论坛http://www.gcs8.cn〗
查看原网址:http://www.gcs8.cn/htm_data/42/0710/10374.html |
|