WebGLFundamentals.org

Fix, Fork, Contribute

WebGL 三维方向光源

drag the points

rotate the direction

法向量

``````function setNormals(gl) {
var normals = new Float32Array([
// 正面左竖
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,

// 正面上横
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,

// 正面中横
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,

// 背面左竖
0, 0, -1,
0, 0, -1,
0, 0, -1,
0, 0, -1,
0, 0, -1,
0, 0, -1,

// 背面上横
0, 0, -1,
0, 0, -1,
0, 0, -1,
0, 0, -1,
0, 0, -1,
0, 0, -1,

// 背面中横
0, 0, -1,
0, 0, -1,
0, 0, -1,
0, 0, -1,
0, 0, -1,
0, 0, -1,

// 顶部
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,

// 上横右面
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,

// 上横下面
0, -1, 0,
0, -1, 0,
0, -1, 0,
0, -1, 0,
0, -1, 0,
0, -1, 0,

// 上横和中横之间
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,

// 中横上面
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,

// 中横右面
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,

// 中横底面
0, -1, 0,
0, -1, 0,
0, -1, 0,
0, -1, 0,
0, -1, 0,
0, -1, 0,

// 底部右侧
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,

// 底面
0, -1, 0,
0, -1, 0,
0, -1, 0,
0, -1, 0,
0, -1, 0,
0, -1, 0,

// 左面
-1, 0, 0,
-1, 0, 0,
-1, 0, 0,
-1, 0, 0,
-1, 0, 0,
-1, 0, 0]);
gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW);
}
``````

``````// 找顶点着色器中的属性
var positionLocation = gl.getAttribLocation(program, "a_position");
-var colorLocation = gl.getAttribLocation(program, "a_color");
+var normalLocation = gl.getAttribLocation(program, "a_normal");

...

-// 创建一个缓冲存储颜色
-var colorBuffer = gl.createBuffer();
-// 绑定到 ARRAY_BUFFER
-gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
-// 将几何数据放入缓冲
-setColors(gl);

+// 创建缓冲存储法向量
+var normalBuffer = gl.createBuffer();
+// 绑定到 ARRAY_BUFFER (可以看作 ARRAY_BUFFER = normalBuffer)
+gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
+// 将法向量存入缓冲
+setNormals(gl);
``````

``````-// 启用颜色属性
-gl.enableVertexAttribArray(colorLocation);
-
-// 绑定颜色缓冲
-gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
-
-// 告诉颜色属性怎么从 colorBuffer (ARRAY_BUFFER) 中读取颜色值
-var size = 3;                 // 每次迭代使用3个单位的数据
-var type = gl.UNSIGNED_BYTE;  // 单位数据类型是无符号 8 位整数
-var normalize = true;         // 标准化数据 (从 0-255 转换到 0.0-1.0)
-var stride = 0;               // 0 = 移动距离 * 单位距离长度sizeof(type)  每次迭代跳多少距离到下一个数据
-var offset = 0;               // 从绑定缓冲的起始处开始
-gl.vertexAttribPointer(
-    colorLocation, size, type, normalize, stride, offset)

+// 启用法向量属性
+gl.enableVertexAttribArray(normalLocation);
+
+// 绑定法向量缓冲
+gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
+
+// 告诉法向量属性怎么从 normalBuffer (ARRAY_BUFFER) 中读取值
+var size = 3;          // 每次迭代使用3个单位的数据
+var type = gl.FLOAT;   // 单位数据类型是 32 位浮点型
+var normalize = false; // 单位化 (从 0-255 转换到 0-1)
+var stride = 0;        // 0 = 移动距离 * 单位距离长度sizeof(type)  每次迭代跳多少距离到下一个数据
+var offset = 0;        // 从绑定缓冲的起始处开始
+gl.vertexAttribPointer(
+    normalLocation, size, type, normalize, stride, offset)
``````

``````attribute vec4 a_position;
-attribute vec4 a_color;
+attribute vec3 a_normal;

uniform mat4 u_matrix;

-varying vec4 v_color;
+varying vec3 v_normal;

void main() {
// 将位置和矩阵相乘
gl_Position = u_matrix * a_position;

-  // 将颜色传到片段着色器
-  v_color = a_color;

+  // 将法向量传到片段着色器
+  v_normal = a_normal;
}
``````

``````precision mediump float;

// 从顶点着色器中传入的值
-varying vec4 v_color;
+varying vec3 v_normal;

+uniform vec3 u_reverseLightDirection;
+uniform vec4 u_color;

void main() {
+   // 由于 v_normal 是插值出来的，和有可能不是单位向量，
+   // 可以用 normalize 将其单位化。
+   vec3 normal = normalize(v_normal);
+
+   float light = dot(normal, u_reverseLightDirection);

*   gl_FragColor = u_color;

+   // 将颜色部分（不包括 alpha）和 光照相乘
+   gl_FragColor.rgb *= light;
}
``````

``````  // 寻找全局变量
var matrixLocation = gl.getUniformLocation(program, "u_matrix");
+  var colorLocation = gl.getUniformLocation(program, "u_color");
+  var reverseLightDirectionLocation =
+      gl.getUniformLocation(program, "u_reverseLightDirection");
``````

``````  // 设置矩阵
gl.uniformMatrix4fv(matrixLocation, false, worldViewProjectionMatrix);

+  // 设置使用的颜色
+  gl.uniform4fv(colorLocation, [0.2, 1, 0.2, 1]); // green
+
+  // 设置光线方向
+  gl.uniform3fv(reverseLightDirectionLocation, m4.normalize([0.5, 0.7, 1]));
``````

``````attribute vec4 a_position;
attribute vec3 a_normal;

*uniform mat4 u_worldViewProjection;
+uniform mat4 u_world;

varying vec3 v_normal;

void main() {
// 将位置和矩阵相乘
*  gl_Position = u_worldViewProjection * a_position;

*  // 重定向法向量并传递给片段着色器
*  v_normal = mat3(u_world) * a_normal;
}
``````

``````  // 寻找全局变量
*  var worldViewProjectionLocation =
*      gl.getUniformLocation(program, "u_worldViewProjection");
+  var worldLocation = gl.getUniformLocation(program, "u_world");
``````

``````*// 设置矩阵
*gl.uniformMatrix4fv(
*    worldViewProjectionLocation, false,
*    worldViewProjectionMatrix);
*gl.uniformMatrix4fv(worldLocation, false, worldMatrix);
``````

click to toggle normals

``````attribute vec4 a_position;
attribute vec3 a_normal;

uniform mat4 u_worldViewProjection;
*uniform mat4 u_worldInverseTranspose;

varying vec3 v_normal;

void main() {
// 将位置和矩阵相乘
gl_Position = u_worldViewProjection * a_position;

// 重定向法向量并传递给片段着色器
*  v_normal = mat3(u_worldInverseTranspose) * a_normal;
}
``````

``````-  var worldLocation = gl.getUniformLocation(program, "u_world");
+  var worldInverseTransposeLocation =
+      gl.getUniformLocation(program, "u_worldInverseTranspose");
``````

``````var worldViewProjectionMatrix = m4.multiply(viewProjectionMatrix, worldMatrix);
var worldInverseMatrix = m4.inverse(worldMatrix);
var worldInverseTransposeMatrix = m4.transpose(worldInverseMatrix);

// 设置矩阵
gl.uniformMatrix4fv(
worldViewProjectionLocation, false,
worldViewProjectionMatrix);
-gl.uniformMatrix4fv(worldLocation, false, worldMatrix);
+gl.uniformMatrix4fv(
+    worldInverseTransposeLocation, false,
+    worldInverseTransposeMatrix);
``````

``````var m4 = {
transpose: function(m) {
return [
m[0], m[4], m[8], m[12],
m[1], m[5], m[9], m[13],
m[2], m[6], m[10], m[14],
m[3], m[7], m[11], m[15],
];
},

...
``````

mat3(u_worldInverseTranspose) * a_normal 的可选方案

```v_normal = mat3(u_worldInverseTranspose) * a_normal;
```

```v_normal = (u_worldInverseTranspose * vec4(a_normal, 0)).xyz;
```

• 基础概念
• 图像处理
• 二维平移，旋转，缩放和矩阵运算
• 三维
• 光照
• 组织和重构
• 几何
• 纹理
• 渲染到纹理
• 阴影
• 技术
• 建议
• 优化
• 杂项
• 参考

Issue/Bug? 在GitHub上提issue.