<- OPENGL 10 NormalMAP ->

复习基础知识

1,GLSL Mat矩阵全部是列向量 优先构造矩阵。

2,GLM同样以列为主:

#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
ostream
& operator<<(ostream & os , const glm::mat4 &inputMat){ // col:1 row:1 col:2 row:1 col:3 row:1 col:4 row:1 cout << inputMat[0][0] <<" " <<inputMat[1][0] << " " <<inputMat[2][0] << " " << inputMat[3][0] << endl; // col:1 row:2 col:2 row:2 col:3 row:2 col:4 row:2 cout << inputMat[0][1] <<" " <<inputMat[1][1] << " " <<inputMat[2][1] << " " << inputMat[3][1] << endl; // col:1 row:3 col:2 row:3 col:3 row:3 col:4 row:3 cout << inputMat[0][2] <<" " <<inputMat[1][2] << " " <<inputMat[2][2] << " " << inputMat[3][2] << endl; // col:1 row:4 col:2 row:4 col:3 row:4 col:4 row:4 cout << inputMat[0][3] <<" " <<inputMat[1][3] << " " <<inputMat[2][3] << " " << inputMat[3][3] << endl; return os; } ostream & operator << (ostream &os , const glm::vec4 &vec){ cout << vec.x << " " << vec.y << " " << vec.z << " " <<vec.w ; return os; } void debug(const glm::mat4 &inputMat){ cout << "col 1->" <<inputMat[0] << endl; // access col 1 cout << "col 2->" <<inputMat[1] << endl; // access col 2 cout << "col 3->" <<inputMat[2] << endl; // access col 3 cout << "col 4->" <<inputMat[3] << endl; // access col 4 } int main() { glm::mat4 m01(1.0f); cout << m01 <<endl; // use array to construct matrix glm::mat4 m02(1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16); cout << m02 << endl; // Use vector to construct matrix glm::mat4 m03(glm::vec4(1,1,1,1), glm::vec4(2,2,2,2), glm::vec4(3,3,3,3), glm::vec4(4,4,4,4)); cout << m03 << endl; debug(m03); return 0; }

结果:

D:plugin_devopenglglm_testCP_01cmake-build-debugCP_01.exe
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16

1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4

col 1->1 1 1 1
col 2->2 2 2 2
col 3->3 3 3 3
col 4->4 4 4 4

Process finished with exit code 0

3,同样观查GLM源码,operator[]确实返回列为主得向量

4,把GLM向量放到vector中,展平访问:

#include <iostream>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/glm.hpp>
#include <vector>
using namespace std;

int main()
{
    vector <glm::vec3> points;
    points.emplace_back(glm::vec3(1,2,3));
    points.emplace_back(glm::vec3(4,5,6));
    points.emplace_back(glm::vec3(7,8,9));

    float *dataPointer = (float*) (points.data()); 

    cout << *( dataPointer + 0)  << endl; // -> 1
    cout << *( dataPointer + 1)  << endl; // -> 2
    cout << *( dataPointer + 2)  << endl; // -> 3
    cout << *( dataPointer + 3)  << endl; // -> 4
    return 0;
}

5,而我们houdini却是个用行向量。

6, NormalMap:

Houdini需要normalMalMap:

 OPENGL需要的NormalMap,可以看到Y轴向是反的:

https://learnopengl-cn.github.io/05%20Advanced%20Lighting/04%20Normal%20Mapping/ 给的贴图必须在Houdini下选择linear 模式。

首先 法线贴图是在切线空间,在切线空间法线全部对齐z轴向

用houdini理解最简单,平常一个物体比如box对齐到z轴向。如图:

如果把这玩意拷贝到球上:相当于将把长方体 转到 法线形成的正交矩阵空间,此时这个法线空间就是我们的世界空间,(一般用个up向量这个球上法线形成3个正交向量就行,但是也可以是TBN矩阵):

 当然转到 这个球的法线空间(世界物体法线空间),也可以形成TBN正交矩阵: 

Houdini IMP the normalMap at world space:

float blinn(vector cameraP; vector P; vector N; vector LgtP){
    vector wo = normalize(cameraP - P);
    vector wi = normalize(LgtP - P);
    vector nn = normalize(N);
    // cal the blinn specular
    vector h = normalize(wi + wo);
    float ndoth = max(dot(nn,h),0.0f);
    float blinn_brdf = pow(ndoth,60.0f) ;
    return blinn_brdf;
}


blinnbrdf = blinn(camP,P,N,lgtP);
blinn

所以:

1,只要把 TBN矩阵 * 法线贴图形成的vector   相当于把法线贴图转到真正的 世界空间可以直接用的法线,此时这个法线做灯光用,细节多的一批。 

2,也可以直接把世界空间的向量(比如灯光向量)变换到这个法线贴图所在的 切线空间。方法就是TBN的逆矩阵 * 灯光向量,而正交矩阵的逆矩阵=正交矩阵的转置矩阵,求逆矩阵运算量太大,所以教程中也是转到转置矩阵。接下来就是正常的材质运算。

原文地址:https://www.cnblogs.com/gearslogy/p/12545438.html