高级主题:帧缓冲区、阴影映射与WebGL 2.0
一、帧缓冲区(Frame Buffer Object, FBO)
帧缓冲区对象(FBO)是WebGL中用于离屏渲染的重要工具。它允许开发者将渲染结果存储到一个纹理或渲染缓冲中,而不是直接渲染到屏幕上。这在实现高级效果(如阴影映射、后期处理等)时非常有用。
创建帧缓冲区
创建帧缓冲对象:
javascriptconst fbo = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
创建纹理附件:
javascriptconst texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
将纹理附加到帧缓冲:
javascriptgl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
检查帧缓冲状态:
javascriptif (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) { console.error('Framebuffer is not complete'); }
解绑帧缓冲:
javascriptgl.bindFramebuffer(gl.FRAMEBUFFER, null);
二、阴影映射(Shadow Mapping)
阴影映射是一种实现阴影效果的技术。它通过从光源的视角渲染场景,生成一张深度贴图(Depth Map),然后在主渲染中使用这张深度贴图来计算阴影。
实现阴影映射的步骤
创建深度贴图:
javascriptconst SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024; const depthMapFBO = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, depthMapFBO); const depthMap = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, depthMap); gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, gl.DEPTH_COMPONENT, gl.FLOAT, null); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthMap, 0); gl.drawBuffer(gl.NONE); gl.readBuffer(gl.NONE); gl.bindFramebuffer(gl.FRAMEBUFFER, null);
从光源视角渲染场景:
javascriptgl.bindFramebuffer(gl.FRAMEBUFFER, depthMapFBO); gl.clear(gl.DEPTH_BUFFER_BIT); // 渲染场景 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
在主渲染中使用深度贴图:
javascriptconst depthMapLocation = gl.getUniformLocation(program, 'u_depthMap'); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, depthMap); gl.uniform1i(depthMapLocation, 0);
片段着色器中计算阴影:
glslprecision mediump float; varying vec4 v_position; uniform sampler2D u_depthMap; uniform mat4 u_lightSpaceMatrix; void main() { vec4 shadowCoord = u_lightSpaceMatrix * v_position; shadowCoord = shadowCoord / shadowCoord.w; float closestDepth = texture2D(u_depthMap, shadowCoord.xy).r; float currentDepth = shadowCoord.z; float shadow = currentDepth > closestDepth ? 1.0 : 0.0; gl_FragColor = vec4(shadow); }
三、WebGL 2.0
WebGL 2.0是WebGL的更新版本,基于OpenGL ES 3.0。它引入了许多新特性,提升了WebGL的性能和功能。
WebGL 2.0的新特性
- 更高级的着色器语言(GLSL ES 3.00):支持更复杂的着色器功能。
- 多渲染目标(Multiple Render Targets, MRT):允许同时渲染到多个颜色附件。
- 更高效的纹理操作:支持更多的纹理格式和操作。
- 更强大的缓冲区对象:支持更多的缓冲区操作和更高效的数据传输。
- 改进的帧缓冲对象:支持更多的附件类型和更灵活的配置。
示例代码
以下是一个简单的WebGL 2.0代码示例,展示如何创建一个帧缓冲对象并渲染到纹理:
javascript
const gl = canvas.getContext('webgl2');
if (!gl) {
console.error('WebGL 2.0 not supported');
}
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
console.error('Framebuffer is not complete');
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
通过这些高级主题的介绍和示例代码,你可以更好地理解和应用帧缓冲区、阴影映射和WebGL 2.0的新特性。