GLSL BlinnPhong优化到底有多少

James Blinn 发现Phong着色中求光线与平面的反射向量是不必要的,于是我的一本书《Computer Grapphics Programming in OpenGL with C++》说Blinn-Phong模型性能提升十分十分大,然而反射向量求解似乎也不是很难:

vec4 reflect(vec4 v,vec4 n){
  //求投影向量
  vec4 projV = dot(v,n)/(n.x*n.x+n.y*n.y+n.z*n.z)*n;
  return v - 2*projV;
}

现在随便一处不优化的code都比求reflect复杂

以下内容部分参考ChatGPT模型:


BlinnPhong着色模型的优化可以从多个方面入手,例如:

  1. 使用预计算的法向量:在每个片元中计算法向量是比较耗时的,可以在顶点着色器中计算好法向量并传递给片元着色器使用。

  2. 使用预计算的半向量:BlinnPhong模型中需要计算半向量,可以在顶点着色器中计算好并传递给片元着色器使用。

  3. 精简计算公式:BlinnPhong模型中的计算公式比较复杂,可以通过简化一些公式来提高性能,例如可以通过移除一些不必要的指数运算来减少计算量。

  4. 使用纹理采样:可以通过在纹理中存储反射率和粗糙度等信息,来减少对光照计算的依赖,从而提高性能。

  5. 光源优化:可以通过减少光源的数量、使用较小的光源范围、使用光源的阴影优化等方式来提高性能。

例子:

下面是一个简化了的BlinnPhong着色器代码,其中使用了预计算的法向量和半向量:

顶点着色器:

#version 330 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;

out vec3 FragPos;
out vec3 Normal;
out vec3 ViewDir;
out vec3 HalfDir;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    FragPos = vec3(model * vec4(aPos, 1.0));
    Normal = mat3(transpose(inverse(model))) * aNormal;
    ViewDir = vec3(0.0, 0.0, 1.0) - FragPos;
    HalfDir = normalize(ViewDir + vec3(0.0, 0.0, 1.0));
}

片元着色器:

#version 330 core

in vec3 FragPos;
in vec3 Normal;
in vec3 ViewDir;
in vec3 HalfDir;

out vec4 FragColor;

uniform vec3 lightPos;
uniform vec3 lightColor;
uniform vec3 viewPos;
uniform float shininess;

void main()
{
    vec3 lightDir = normalize(lightPos - FragPos);
    float diffuse = max(dot(Normal, lightDir), 0.0);
    vec3 reflectDir = reflect(-lightDir, Normal);
    float specular = pow(max(dot(HalfDir, reflectDir), 0.0), shininess);
    vec3 ambient = vec3(0.1, 0.1, 0.1);
    vec3 diffuseColor = vec3(1.0, 0.0, 0.0);
    vec3 specularColor = vec3(1.0, 1.0, 1.0);
    vec3 result = ambient + diffuseColor * diffuse + specularColor * specular;
    FragColor = vec4(result, 1.0);
}

如果我的建议对您有帮助、请点击采纳、祝您生活愉快