openGL系列文章目录
前言
我们在openGL中绘制球体,或者圆环体的时候,经常可以到法线、切线、副切线这几个词,一脸疑惑,特别是副切线,这时什么鬼?
一、法线(normal)
物体模型由成百上千个平坦的三角形围成.三角形上附加纹理的方式来增加额外细节. 提升真实感.
但是近看时,就有问题了.变成平面.缺乏细节.原因:
物体表面并非平坦的. 而是表示出无数(凹凸不平的)细节.如果以光的视角来看这个问题:是什么使表面被视为完全平坦的表面来照亮?
这时就需要法线
法线定义
三维平面的法线是垂直于该平面的三维向量。曲面在某点P处的法线为垂直于该点切平面的向量。
二、切线(tangent)
切线定义
几何上,切线指的是一条刚好触碰到曲线上某一点的直线。更准确地说,当切线经过曲线上的某点(即切点)时,切线的方向与曲线上该点的方向是相同的。平面几何中,将和圆只有一个公共交点的直线叫做圆的切线。
副切线(bitangent)
副切线(Bitangent)有时也被叫作副法线(Binormal),不管怎样,说的都是同一个东西。
副切线是同时垂直于由法线与切线的向量,所以可以由法线与切线的叉积计算得出。
但是这样的向量有两条,那到底哪一条才是真正的副切线呢?
经过计算后的副切线向量(蓝色的线)。
在着色器中的描述和计算
vec3 tangent;
vec3 binormal;
vec3 c1 = cross(a_normal, vec3(0.0, 0.0, 1.0));
vec3 c2 = cross(a_normal, vec3(0.0, 1.0, 0.0));
if (length(c1)>length(c2))
{
tangent = c1;
}
else
{
tangent = c2;
}
tangent = normalize(tangent);
binormal = cross(v_nglNormal, tangent);
binormal = normalize(binormal);
法线,切线,副切线函数实现
Vector3 Math::calculateTangentSpaceVector(
const Vector3& position1, const Vector3& position2, const Vector3& position3,
Real u1, Real v1, Real u2, Real v2, Real u3, Real v3)
{
//side0 is the vector along one side of the triangle of vertices passed in,
//and side1 is the vector along another side. Taking the cross product of these returns the normal.
Vector3 side0 = position1 - position2;
Vector3 side1 = position3 - position1;
//Calculate face normal
Vector3 normal = side1.crossProduct(side0);
normal.normalise();
//Now we use a formula to calculate the tangent.
Real deltaV0 = v1 - v2;
Real deltaV1 = v3 - v1;
Vector3 tangent = deltaV1 * side0 - deltaV0 * side1;
tangent.normalise();
//Calculate binormal
Real deltaU0 = u1 - u2;
Real deltaU1 = u3 - u1;
Vector3 binormal = deltaU1 * side0 - deltaU0 * side1;
binormal.normalise();
//Now, we take the cross product of the tangents to get a vector which
//should point in the same direction as our normal calculated above.
//If it points in the opposite direction (the dot product between the normals is less than zero),
//then we need to reverse the s and t tangents.
//This is because the triangle has been mirrored when going from tangent space to object space.
//reverse tangents if necessary
Vector3 tangentCross = tangent.crossProduct(binormal);
if (tangentCross.dotProduct(normal) < 0.0f)
{
tangent = -tangent;
binormal = -binormal;
}
return tangent;
}