首页 > 解决方案 > WebGL:在不借助 THREE.JS 的情况下添加镜面光

问题描述

我正在 webgl 编程中迈出第一步。按照本教程创建了一个简单的设置。设法添加了一些我自己的东西,虽然偶然添加了光,特别是镜面光。正如我所假设的,其中大部分将在我的片段着色器中实现,并且可能在顶点着色器和 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)
}

我真的很感谢你在这里的建议。提前致谢!

标签: glslwebglshaderfragment-shadervertex-shader

解决方案


最常见和最简单的光照模型是Phong 反射模型Blinn-Phong模型。

以下着色器代码基于您的原始代码并实现了Blinn-Phong 模型模型。与您的代码相比,光照计算是在视图空间中完成的,因为镜面高光取决于视图位置,即视图空间中的 (0, 0, 0)。因此,必须将光的方向转换为视图空间。

顶点着色器

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] 范围内的正值。

另请参阅Phong 和 Gouraud 着色 WebGL


推荐阅读