使用Phong着色模型渲染一个立方体

Phong着色是一种经典的计算机图形学着色模型,它结合了环境光、漫反射光和镜面反射光来模拟物体表面的光照效果。以下是一个更完整的WebGL代码示例,它使用了Phong着色模型来渲染一个简单的立方体。

HTML部分

HTML部分创建了一个canvas元素,用于WebGL渲染。

html

WebGL Phong Shading Example JavaScript部分(app.js)

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等函数来进行矩阵运算了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值