glsl - 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)
}
我真的很感谢你在这里的建议。提前致谢!
解决方案
最常见和最简单的光照模型是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] 范围内的正值。
推荐阅读
- typescript - 如何在 TypeScript 中将函数的返回类型指定为命名空间类型,以便提出建议
- python - 如何在 pybind11 中正确公开从 Eigen::Matrix 派生的自定义 Vector 类?
- java - 我无法在 JENA 中获得 Restriction 的特征
- python - 竞争性编程:我的代码有什么问题?我的代码运行成功,但代码不会提交
- php - 嵌套数组,用数字替换字母键并保持结构
- firebase - Google Cloud Platform 中的 Firebase 实时数据库
- python - % 增加数字记录中的值
- javascript - React - 在 renderProps 函数上使用回调抛出错误
- mysql - MySQL中主表的某些列如何与子表同步?
- arrays - iOS 如何转换字典
查询包含数组的参数