优化矢量的法线贴图旋转

时间:2013-12-30 17:08:47

标签: glsl libgdx quaternions

我使用四元数将网格的法线向量旋转到法线贴图向量的方向。我以为我可以使用Quaternion。所以我用网格法线和(0,0,1)之间的角度创建一个四元数。缩短了libgdx中的方法,Quaternion的创建看起来像这样

vec4 createQuaternion(vec3 normal) {
    float l_ang = acos(clamp(normal.z, -CONST_ONE, CONST_ONE))/CONST_TWO;
    float l_sin = sin(l_ang);
    return normalize(vec4(-normal.y * l_sin, normal.x * l_sin, CONST_ZERO, cos(l_ang)));
}

使用此四元数我可以在法线贴图的方向上旋转网格的法线。因此我使用了我在libgdx Quaternion中看到的方法(而v是法线贴图的法线,m是四元数):

vec3 rotateNormal(vec3 v, vec4 m) {
    vec4 tmp1 = vec4(v,CONST_ZERO);
    vec4 tmp2 = vec4(m);
    // conjugate
    tmp2.x = -tmp2.x;
    tmp2.y = -tmp2.y;
    tmp2.z = -tmp2.z;
    tmp2 = mulLeft(tmp1, tmp2);
    tmp1 = mulLeft(m, tmp2);
    v.x = tmp1.x;
    v.y = tmp1.y;
    v.z = tmp1.z;
    return v;
}

mulLeft方法看起来像这样:

vec4 mulLeft(vec4 q, vec4 a) {
    float newX = q.w * a.x + q.x * a.w + q.y * a.z - q.z * a.y;
    float newY = q.w * a.y + q.y * a.w + q.z * a.x - q.x * a.z;
    float newZ = q.w * a.z + q.z * a.w + q.x * a.y - q.y * a.x;
    float newW = q.w * a.w - q.x * a.x - q.y * a.y - q.z * a.z;
    a.x = newX;
    a.y = newY;
    a.z = newZ;
    a.w = newW;
    return a;
}

对于在着色器中的使用,我只需要调用:

normal = rotateNormal(normalMap, createQuaternion(normalMesh));

按预期工作

我唯一考虑的是,我可以想象有一种更短的方式来写它。特别是mulLeft方法。有吗?

您如何看待整个方法,通过四元数而不是使用NTB来转换矢量? 在动画网格时,ntb看起来有点像计算。

编辑: 这是我的源代码

的测试

My Code

这是Tenfour建议的测试

EDIT2:

我把整件事缩短为:

vec3 rotateNormal(vec3 normalMap, vec3 normal) {
    // create quaternion from cross(normal, vec3(0,0,1))
    float l_ang = acos(clamp(normal.z, -CONST_ONE, CONST_ONE))/CONST_TWO;
    float l_sin = sin(l_ang);
    vec4 quat = normalize(vec4(-normal.y * l_sin, normal.x * l_sin, CONST_ZERO, cos(l_ang)));

    // shortened function to double mulQuat the normalMap on the quaternion
    return vec3(
            quat.x*quat.x*normalMap.x - quat.y*quat.y*normalMap.x - quat.z*quat.z*normalMap.x + quat.w*quat.w*normalMap.x - CONST_TWO*quat.z*quat.w*normalMap.y + CONST_TWO*quat.y*quat.w*normalMap.z + CONST_TWO*quat.x *(quat.y*normalMap.y + quat.z*normalMap.z),
            -(quat.x*quat.x*normalMap.y) - quat.z*quat.z* normalMap.y + (quat.y*quat.y  + quat.w*quat.w ) * normalMap.y + CONST_TWO*quat.z *(quat.w*normalMap.x + quat.y*normalMap.z) + CONST_TWO*quat.x* (quat.y*normalMap.x - quat.w*normalMap.z),
            quat.y*(-CONST_TWO*quat.w*normalMap.x + CONST_TWO*quat.z*normalMap.y) + CONST_TWO*quat.x*(quat.z*normalMap.x + quat.w*normalMap.y) - quat.x*quat.x*normalMap.z - quat.y*quat.y*normalMap.z + (quat.z*quat.z  + quat.w*quat.w )* normalMap.z
    );
}

输入是法线贴图的法线和网格的法线。 我相信还有比这更好的东西。那可能是什么?

1 个答案:

答案 0 :(得分:0)

我发现了这个

vec3 rotate_vector( vec4 quat, vec3 vec )
{
    return vec + 2.0 * cross( cross( vec, quat.xyz ) + quat.w * vec, quat.xyz );
}

here。那样有用吗?不确定底层数学有多少,但内置的GLSL函数通常可以利用GPU优化。