Phong着色是一种经典的计算机图形学着色模型,它结合了环境光、漫反射光和镜面反射光来模拟物体表面的光照效果。以下是一个更完整的WebGL代码示例,它使用了Phong着色模型来渲染一个简单的立方体。
HTML部分
HTML部分创建了一个canvas元素,用于WebGL渲染。
html
JavaScript部分包含了WebGL的初始化、着色器的编译、程序的链接、几何体和法线数据的定义、以及渲染循环。
javascript
// 初始化WebGL
const canvas = document.getElementById(‘glCanvas’);
const gl = canvas.getContext(‘webgl’);
if (!gl) {
console.error(‘Unable to initialize WebGL. Your browser may not support it.’);
return;
}
// 顶点着色器源代码
const vertexShaderSource = `
attribute vec4 aVertexPosition;
attribute vec3 aVertexNormal;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
uniform mat4 uNormalMatrix;
varying highp vec3 vLighting;
void main(void) {
gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
// 光照计算
highp vec3 ambientLight = vec3(0.3, 0.3, 0.3);
highp vec3 directionalLightColor = vec3(1, 1, 1);
highp vec3 directionalVector = normalize(vec3(0.85, 0.8, 0.75));
highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);
highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);
vLighting = ambientLight + (directionalLightColor * directional);
}
`;
// 片元着色器源代码
const fragmentShaderSource = `
varying highp vec3 vLighting;
void main(void) {
gl_FragColor = vec4(vec3(1, 1, 1) * vLighting, 1.0); // 使用白色材质和光照结果相乘
}
`;
// 编译着色器
function compileShader(source, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
// 链接程序
function createProgram(vertexShader, fragmentShader) {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(program));
return null;
}
return program;
}
// 创建着色器和程序
const vertexShader = compileShader(vertexShaderSource, gl.VERTEX_SHADER);
const fragmentShader = compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER);
const program = createProgram(vertexShader, fragmentShader);
// 获取属性位置
const positionLocation = gl.getAttribLocation(program, ‘aVertexPosition’);
const normalLocation = gl.getAttribLocation(program, ‘aVertexNormal’);
// 获取统一变量位置
const modelViewMatrixLocation = gl.getUniformLocation(program, ‘uModelViewMatrix’);
const projectionMatrixLocation = gl.getUniformLocation(program, ‘uProjectionMatrix’);
const normalMatrixLocation = gl.getUniformLocation(program, ‘uNormalMatrix’);
// 定义几何体和法线数据(这里使用一个简单的立方体)
// … (省略了具体的顶点和法线数据,可以参考前面的回答或相关教程)
// 创建缓冲区
// … (省略了创建缓冲区的代码,与前面的回答类似)
// 设置视口和清空颜色
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 启用深度测试
gl.enable(gl.DEPTH_TEST);
// 定义模型视图矩阵、投影矩阵和法线矩阵
const modelViewMatrix = mat4.create();
const projectionMatrix = mat4.create();
const normalMatrix = mat4.create();
// 初始化矩阵
mat4.perspective(projectionMatrix, 45 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.1, 100.0);
mat4.translate(modelViewMatrix, modelViewMatrix, [-0.0, 0.0, -6.0]);
// 计算法线矩阵
mat4.invert(normalMatrix, modelViewMatrix);
mat4.transpose(normalMatrix, normalMatrix);
// 渲染函数
function render() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.useProgram(program);
// 绑定顶点和法线缓冲区,并启用相应的属性
// ... (省略了绑定缓冲区和启用属性的代码,与前面的回答类似)
// 设置统一变量
gl.uniformMatrix4fv(modelViewMatrixLocation, false, modelViewMatrix);
gl.uniformMatrix4fv(projectionMatrixLocation, false, projectionMatrix);
gl.uniformMatrix4fv(normalMatrixLocation, false, normalMatrix);
// 绘制立方体
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
}
// 请求动画帧,开始渲染循环
function animate() {
render();
requestAnimationFrame(animate);
}
// 开始渲染循环
animate();
请注意,这个示例中省略了具体的顶点和法线数据,以及创建缓冲区和启用属性的部分代码,因为这些内容在前面的回答中已经给出过。此外,这个示例使用了一个简单的立方体几何体,并且没有包含任何动画或交互逻辑。你可以根据自己的需求扩展这个示例,添加更多的几何体、纹理、动画等。
另外,请确保你在HTML文件中包含了适当的数学库(如gl-matrix),以便在JavaScript中使用矩阵运算。你可以通过CDN或本地文件来引入这个库。例如,在HTML的部分添加以下代码来引入gl-matrix库:
html
这样,你就可以在JavaScript中使用mat4等函数来进行矩阵运算了。