WebGL:在没有 THREE.JS 帮助的情况下添加镜面光

WebGL: adding specular light without the help of THREE.JS

我正在 webgl 编程中迈出第一步。在 this tutorial 之后创建了一个简单的设置。设法添加了一些我自己的东西,尽管在添加光时遇到了困难,尤其是 - 镜面光。 正如我所假设的,大部分将在我的片段着色器中实现,并且可能在顶点着色器和 Light 模块中添加一些内容。这就是我在下面提供的代码。

顶点着色器:

attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
varying vec3 vNormal;
varying vec2 vUv;

void main() {
    vUv = uv;
    vNormal = (model * vec4(normal, 0.)).xyz;
    gl_Position = projection * view * model * vec4(position, 1.);
}

片段着色器:

#ifdef GL_ES
precision highp float;
#endif

uniform vec3 lightDirection;
uniform float ambientLight;
uniform sampler2D diffuse;
varying vec3 vNormal;
varying vec2 vUv;

void main() {
    float lightness = -clamp(dot(normalize(vNormal), normalize(lightDirection)), -1., 0.);
    lightness = ambientLight + (1. - ambientLight) * lightness;
    gl_FragColor = vec4(texture2D(diffuse, vUv).rgb * lightness, 1.);
}

Light.js模块:

function Light () {
  this.lightDirection = new Vector3(-1, -1, -1)
  this.ambientLight = 0.3
}

Light.prototype.use = function (shaderProgram) {
  var dir = this.lightDirection
  var gl = shaderProgram.gl
  gl.uniform3f(shaderProgram.lightDirection, dir.x, dir.y, dir.z)
  gl.uniform1f(shaderProgram.ambientLight, this.ambientLight)
}

非常感谢您的建议。提前致谢!

最常见和最简单的灯光模型是 Phong reflection model or the Blinn–Phong model 模型。

以下着色器代码基于您的原始代码并实现了 Blinn–Phong model 模型。与您的代码相比,光照计算是在视图 space 中完成的,因为镜面高光取决于视图位置,即视图 space 中的 (0, 0, 0)。所以光的方向要变换一下才能看space.

顶点着色器:

attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;

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

uniform vec3 lightDirection;

varying vec3 vPos;
varying vec3 vNormal;
varying vec2 vUv;
varying vec3 lightDirectionView;

void main() 
{
    lightDirectionView = (view * vec4(lightDirection, 0.)).xyz;

    mat4 modelView = view * model;
    vec4 viewPos   = modelView * vec4(position, 1.0)
    vPos           = viewPos.xyz;
    vUv            = uv;
    vNormal        = (modelView * vec4(normal, 0.)).xyz;
    gl_Position    = projection * viewPos;
}

片段着色器:

#ifdef GL_ES
precision highp float;
#endif

uniform float     shininess;
uniform float     ambientLight;
uniform sampler2D diffuse;

varying vec3 vPos;
varying vec3 vNormal;
varying vec2 vUv;
varying vec3 lightDirectionView;

void main()
{
    vec3  color     = texture2D(diffuse, vUv).rgb;

    vec3  N         = normalize( vNormal );
    vec3  L         = normalize( -lightDirectionView );
    vec3  V         = normalize( -vPos );
    vec3  H         = normalize( V + L );

    float NdotL     = dot(N, L);
    float NdotH     = dot(N, H);

    float kDiffuse  = max(0.0, NdotL);
    // float kSpecular = (shininess + 2.0) * pow(max(0.0, NdotH), shininess) / (2.0 * 3.14159265);
    float kSpecular = pow(max(0.0, NdotH), shininess);

    vec3 light_col  = color * (kDiffuse + kSpecular);
    gl_FragColor    = vec4(light_col, 1.0);
}

uniform shininess 的值必须是 [1, 100] 范围内的正值。

另见