webgl-expert

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

WebGL Expert

WebGL 专家指南

Expert guide for WebGL (Web Graphics Library) API development, covering both WebGL 1.0 and WebGL 2.0 for high-performance 2D and 3D graphics rendering in web browsers.
WebGL(Web Graphics Library)API开发专家指南,涵盖WebGL 1.0和WebGL 2.0,用于在网页浏览器中实现高性能2D和3D图形渲染。

Overview

概述

WebGL is a JavaScript API that enables hardware-accelerated 3D graphics rendering within HTML canvas elements without requiring plugins. It closely conforms to OpenGL ES 2.0 (WebGL 1.0) and OpenGL ES 3.0 (WebGL 2.0) standards.
Key capabilities:
  • Hardware-accelerated 2D and 3D rendering
  • Programmable shader pipeline (GLSL)
  • Texture mapping and advanced materials
  • Lighting and transformation systems
  • High-performance graphics for games and visualizations
  • Cross-platform compatibility (all modern browsers)
WebGL是一款JavaScript API,无需插件即可在HTML canvas元素中实现硬件加速的3D图形渲染。它严格遵循OpenGL ES 2.0(对应WebGL 1.0)和OpenGL ES 3.0(对应WebGL 2.0)标准。
核心功能:
  • 硬件加速的2D和3D渲染
  • 可编程着色器管线(GLSL)
  • 纹理映射与高级材质
  • 光照与变换系统
  • 适用于游戏和可视化场景的高性能图形
  • 跨平台兼容性(支持所有现代浏览器)

Core Interfaces

核心接口

WebGLRenderingContext (WebGL 1.0)

WebGLRenderingContext(WebGL 1.0)

The foundational interface for WebGL operations, obtained via canvas context:
javascript
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');

if (!gl) {
    console.error('WebGL not supported');
}
WebGL操作的基础接口,通过canvas上下文获取:
javascript
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');

if (!gl) {
    console.error('WebGL not supported');
}

WebGL2RenderingContext (WebGL 2.0)

WebGL2RenderingContext(WebGL 2.0)

Enhanced interface with advanced features:
javascript
const gl = canvas.getContext('webgl2');

if (!gl) {
    console.log('WebGL 2 not supported, falling back to WebGL 1');
    gl = canvas.getContext('webgl');
}
WebGL 2 exclusive features:
  • 3D textures
  • Sampler objects
  • Uniform Buffer Objects (UBO)
  • Transform Feedback
  • Vertex Array Objects (VAO) - core feature
  • Instanced rendering
  • Multiple render targets
  • Integer textures and attributes
  • Query objects
  • Occlusion queries
增强版接口,具备更多高级功能:
javascript
const gl = canvas.getContext('webgl2');

if (!gl) {
    console.log('WebGL 2 not supported, falling back to WebGL 1');
    gl = canvas.getContext('webgl');
}
WebGL 2专属特性:
  • 3D纹理
  • 采样器对象
  • 统一缓冲区对象(UBO)
  • 变换反馈
  • 顶点数组对象(VAO)- 核心功能
  • 实例化渲染
  • 多渲染目标
  • 整数纹理与属性
  • 查询对象
  • 遮挡查询

Rendering Pipeline

渲染管线

1. Shader Creation and Compilation

1. 着色器创建与编译

Shaders are programs written in GLSL (OpenGL Shading Language) that run on the GPU:
Vertex Shader - Processes each vertex:
glsl
attribute vec3 aPosition;
attribute vec2 aTexCoord;
uniform mat4 uModelViewProjection;
varying vec2 vTexCoord;

void main() {
    gl_Position = uModelViewProjection * vec4(aPosition, 1.0);
    vTexCoord = aTexCoord;
}
Fragment Shader - Determines pixel colors:
glsl
precision mediump float;
varying vec2 vTexCoord;
uniform sampler2D uTexture;

void main() {
    gl_FragColor = texture2D(uTexture, vTexCoord);
}
JavaScript shader setup:
javascript
function createShader(gl, type, source) {
    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        console.error('Shader compilation error:', gl.getShaderInfoLog(shader));
        gl.deleteShader(shader);
        return null;
    }
    return shader;
}

function createProgram(gl, 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('Program linking error:', gl.getProgramInfoLog(program));
        gl.deleteProgram(program);
        return null;
    }
    return program;
}
着色器是运行在GPU上、使用GLSL(OpenGL着色语言)编写的程序:
顶点着色器 - 处理每个顶点:
glsl
attribute vec3 aPosition;
attribute vec2 aTexCoord;
uniform mat4 uModelViewProjection;
varying vec2 vTexCoord;

void main() {
    gl_Position = uModelViewProjection * vec4(aPosition, 1.0);
    vTexCoord = aTexCoord;
}
片元着色器 - 确定像素颜色:
glsl
precision mediump float;
varying vec2 vTexCoord;
uniform sampler2D uTexture;

void main() {
    gl_FragColor = texture2D(uTexture, vTexCoord);
}
JavaScript着色器配置:
javascript
function createShader(gl, type, source) {
    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        console.error('Shader compilation error:', gl.getShaderInfoLog(shader));
        gl.deleteShader(shader);
        return null;
    }
    return shader;
}

function createProgram(gl, 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('Program linking error:', gl.getProgramInfoLog(program));
        gl.deleteProgram(program);
        return null;
    }
    return program;
}

2. Buffer Management

2. 缓冲区管理

Buffers store vertex data (positions, colors, normals, texture coordinates):
javascript
// Create buffer
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

// Upload data
const positions = new Float32Array([
    -1.0, -1.0, 0.0,
     1.0, -1.0, 0.0,
     0.0,  1.0, 0.0
]);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);

// Set up attribute pointer
const positionLocation = gl.getAttribLocation(program, 'aPosition');
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
Buffer usage patterns:
  • gl.STATIC_DRAW
    - Data doesn't change
  • gl.DYNAMIC_DRAW
    - Data changes occasionally
  • gl.STREAM_DRAW
    - Data changes every frame
缓冲区用于存储顶点数据(位置、颜色、法线、纹理坐标):
javascript
// 创建缓冲区
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

// 上传数据
const positions = new Float32Array([
    -1.0, -1.0, 0.0,
     1.0, -1.0, 0.0,
     0.0,  1.0, 0.0
]);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);

// 设置属性指针
const positionLocation = gl.getAttribLocation(program, 'aPosition');
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
缓冲区使用模式:
  • gl.STATIC_DRAW
    - 数据不发生变化
  • gl.DYNAMIC_DRAW
    - 数据偶尔变化
  • gl.STREAM_DRAW
    - 数据每帧都变化

3. Texture Handling

3. 纹理处理

javascript
function loadTexture(gl, url) {
    const texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);

    // Placeholder until image loads
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
                  new Uint8Array([255, 0, 255, 255]));

    const image = new Image();
    image.onload = () => {
        gl.bindTexture(gl.TEXTURE_2D, texture);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

        // Generate mipmaps if power of 2
        if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
            gl.generateMipmap(gl.TEXTURE_2D);
        } else {
            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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        }
    };
    image.src = url;
    return texture;
}

function isPowerOf2(value) {
    return (value & (value - 1)) === 0;
}
javascript
function loadTexture(gl, url) {
    const texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);

    // 图片加载完成前的占位图
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
                  new Uint8Array([255, 0, 255, 255]));

    const image = new Image();
    image.onload = () => {
        gl.bindTexture(gl.TEXTURE_2D, texture);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

        // 若尺寸为2的幂则生成mipmap
        if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
            gl.generateMipmap(gl.TEXTURE_2D);
        } else {
            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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        }
    };
    image.src = url;
    return texture;
}

function isPowerOf2(value) {
    return (value & (value - 1)) === 0;
}

4. Rendering Loop

4. 渲染循环

javascript
function render(gl, program) {
    // Clear canvas
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    // Enable depth testing
    gl.enable(gl.DEPTH_TEST);
    gl.depthFunc(gl.LEQUAL);

    // Use program
    gl.useProgram(program);

    // Set uniforms
    const projectionMatrix = mat4.create();
    mat4.perspective(projectionMatrix, Math.PI / 4, canvas.width / canvas.height, 0.1, 100.0);

    const uniformLocation = gl.getUniformLocation(program, 'uModelViewProjection');
    gl.uniformMatrix4fv(uniformLocation, false, projectionMatrix);

    // Draw
    gl.drawArrays(gl.TRIANGLES, 0, 3);

    // Animation loop
    requestAnimationFrame(() => render(gl, program));
}
javascript
function render(gl, program) {
    // 清空画布
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    // 启用深度测试
    gl.enable(gl.DEPTH_TEST);
    gl.depthFunc(gl.LEQUAL);

    // 使用着色器程序
    gl.useProgram(program);

    // 设置uniform变量
    const projectionMatrix = mat4.create();
    mat4.perspective(projectionMatrix, Math.PI / 4, canvas.width / canvas.height, 0.1, 100.0);

    const uniformLocation = gl.getUniformLocation(program, 'uModelViewProjection');
    gl.uniformMatrix4fv(uniformLocation, false, projectionMatrix);

    // 绘制图形
    gl.drawArrays(gl.TRIANGLES, 0, 3);

    // 动画循环
    requestAnimationFrame(() => render(gl, program));
}

Matrix Mathematics

矩阵运算

WebGL uses column-major matrices for transformations. Recommended libraries:
  • glMatrix - Fast matrix/vector operations
  • three.js - High-level 3D library with built-in math
Common transformations:
javascript
// Model matrix (object transform)
const modelMatrix = mat4.create();
mat4.translate(modelMatrix, modelMatrix, [x, y, z]);
mat4.rotate(modelMatrix, modelMatrix, angle, [0, 1, 0]);
mat4.scale(modelMatrix, modelMatrix, [sx, sy, sz]);

// View matrix (camera)
const viewMatrix = mat4.create();
mat4.lookAt(viewMatrix, eyePosition, targetPosition, upVector);

// Projection matrix
const projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, fov, aspect, near, far);

// Combined MVP matrix
const mvpMatrix = mat4.create();
mat4.multiply(mvpMatrix, projectionMatrix, viewMatrix);
mat4.multiply(mvpMatrix, mvpMatrix, modelMatrix);
WebGL使用列主序矩阵进行变换。推荐使用以下库:
  • glMatrix - 快速矩阵/向量运算库
  • three.js - 内置数学工具的高级3D库
常见变换:
javascript
// 模型矩阵(物体变换)
const modelMatrix = mat4.create();
mat4.translate(modelMatrix, modelMatrix, [x, y, z]);
mat4.rotate(modelMatrix, modelMatrix, angle, [0, 1, 0]);
mat4.scale(modelMatrix, modelMatrix, [sx, sy, sz]);

// 视图矩阵(相机)
const viewMatrix = mat4.create();
mat4.lookAt(viewMatrix, eyePosition, targetPosition, upVector);

// 投影矩阵
const projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, fov, aspect, near, far);

// 组合MVP矩阵
const mvpMatrix = mat4.create();
mat4.multiply(mvpMatrix, projectionMatrix, viewMatrix);
mat4.multiply(mvpMatrix, mvpMatrix, modelMatrix);

Performance Optimization

性能优化

Best Practices

最佳实践

  1. Minimize state changes - Batch draw calls with similar state
  2. Use Vertex Array Objects (VAO) - Reduce attribute setup overhead
  3. Texture atlases - Combine multiple textures into one
  4. Instanced rendering - Draw many similar objects efficiently
  5. Frustum culling - Don't render objects outside view
  6. Level of Detail (LOD) - Use simpler models at distance
  7. Texture compression - Use compressed texture formats (DXT, ETC, ASTC)
  8. Minimize shader complexity - Keep fragment shaders simple
  9. Use uniform buffers (WebGL 2) - Efficient uniform data sharing
  10. Avoid CPU-GPU synchronization - Don't read back data frequently
  1. 减少状态切换 - 批量处理状态相似的绘制调用
  2. 使用顶点数组对象(VAO) - 减少属性配置开销
  3. 纹理图集 - 将多张纹理合并为一张
  4. 实例化渲染 - 高效绘制大量相似物体
  5. 视锥体剔除 - 不渲染视野外的物体
  6. 细节层次(LOD) - 远处使用简化模型
  7. 纹理压缩 - 使用压缩纹理格式(DXT、ETC、ASTC)
  8. 简化着色器复杂度 - 尽量简化片元着色器
  9. 使用统一缓冲区(WebGL 2)- 高效共享uniform数据
  10. 避免CPU-GPU同步 - 避免频繁回读数据

Instanced Rendering (WebGL 2)

实例化渲染(WebGL 2)

javascript
const ext = gl.getExtension('ANGLE_instanced_arrays'); // WebGL 1
// or use gl.drawArraysInstanced directly in WebGL 2

// Set up per-instance attribute
const instanceOffsetBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, instanceOffsetBuffer);
gl.bufferData(gl.ARRAY_BUFFER, offsetData, gl.STATIC_DRAW);

const offsetLocation = gl.getAttribLocation(program, 'aInstanceOffset');
gl.enableVertexAttribArray(offsetLocation);
gl.vertexAttribPointer(offsetLocation, 3, gl.FLOAT, false, 0, 0);
gl.vertexAttribDivisor(offsetLocation, 1); // Advance per instance

// Draw multiple instances
gl.drawArraysInstanced(gl.TRIANGLES, 0, vertexCount, instanceCount);
javascript
const ext = gl.getExtension('ANGLE_instanced_arrays'); // WebGL 1兼容扩展
// 或在WebGL 2中直接使用gl.drawArraysInstanced

// 设置实例化属性
const instanceOffsetBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, instanceOffsetBuffer);
gl.bufferData(gl.ARRAY_BUFFER, offsetData, gl.STATIC_DRAW);

const offsetLocation = gl.getAttribLocation(program, 'aInstanceOffset');
gl.enableVertexAttribArray(offsetLocation);
gl.vertexAttribPointer(offsetLocation, 3, gl.FLOAT, false, 0, 0);
gl.vertexAttribDivisor(offsetLocation, 1); // 每个实例更新一次

// 绘制多个实例
gl.drawArraysInstanced(gl.TRIANGLES, 0, vertexCount, instanceCount);

Extension System

扩展系统

Check for and use extensions to access advanced features:
javascript
function getExtension(gl, name) {
    const ext = gl.getExtension(name);
    if (!ext) {
        console.warn(`Extension ${name} not supported`);
    }
    return ext;
}

// Common extensions
const anisotropic = getExtension(gl, 'EXT_texture_filter_anisotropic');
const floatTextures = getExtension(gl, 'OES_texture_float');
const depthTexture = getExtension(gl, 'WEBGL_depth_texture');
const drawBuffers = getExtension(gl, 'WEBGL_draw_buffers');
const loseContext = getExtension(gl, 'WEBGL_lose_context'); // for testing
Important extension categories:
  • Texture formats: WEBGL_compressed_texture_s3tc, WEBGL_compressed_texture_etc
  • Rendering: WEBGL_draw_buffers, EXT_blend_minmax, EXT_frag_depth
  • Precision: OES_texture_float, OES_texture_half_float
  • Instancing: ANGLE_instanced_arrays (WebGL 1)
  • Debugging: WEBGL_debug_renderer_info, WEBGL_debug_shaders
检测并使用扩展以获取高级功能:
javascript
function getExtension(gl, name) {
    const ext = gl.getExtension(name);
    if (!ext) {
        console.warn(`扩展 ${name} 不受支持`);
    }
    return ext;
}

// 常见扩展
const anisotropic = getExtension(gl, 'EXT_texture_filter_anisotropic');
const floatTextures = getExtension(gl, 'OES_texture_float');
const depthTexture = getExtension(gl, 'WEBGL_depth_texture');
const drawBuffers = getExtension(gl, 'WEBGL_draw_buffers');
const loseContext = getExtension(gl, 'WEBGL_lose_context'); // 用于测试
重要扩展分类:
  • 纹理格式: WEBGL_compressed_texture_s3tc、WEBGL_compressed_texture_etc
  • 渲染: WEBGL_draw_buffers、EXT_blend_minmax、EXT_frag_depth
  • 精度: OES_texture_float、OES_texture_half_float
  • 实例化: ANGLE_instanced_arrays(WebGL 1)
  • 调试: WEBGL_debug_renderer_info、WEBGL_debug_shaders

Context Management

上下文管理

Context Loss Handling

上下文丢失处理

javascript
canvas.addEventListener('webglcontextlost', (event) => {
    event.preventDefault();
    console.log('WebGL context lost');
    cancelAnimationFrame(animationId);
}, false);

canvas.addEventListener('webglcontextrestored', () => {
    console.log('WebGL context restored');
    initWebGL(); // Recreate all resources
    render();
}, false);
javascript
canvas.addEventListener('webglcontextlost', (event) => {
    event.preventDefault();
    console.log('WebGL上下文丢失');
    cancelAnimationFrame(animationId);
}, false);

canvas.addEventListener('webglcontextrestored', () => {
    console.log('WebGL上下文恢复');
    initWebGL(); // 重建所有资源
    render();
}, false);

Context Creation Options

上下文创建选项

javascript
const gl = canvas.getContext('webgl2', {
    alpha: false,                    // No alpha channel (better performance)
    antialias: true,                 // Antialiasing (performance cost)
    depth: true,                     // Depth buffer
    stencil: false,                  // Stencil buffer
    premultipliedAlpha: true,        // Alpha premultiplication
    preserveDrawingBuffer: false,    // Keep buffer after render
    powerPreference: 'high-performance', // GPU preference
    failIfMajorPerformanceCaveat: false  // Fallback to software
});
javascript
const gl = canvas.getContext('webgl2', {
    alpha: false,                    // 禁用alpha通道(提升性能)
    antialias: true,                 // 启用抗锯齿(会消耗性能)
    depth: true,                     // 启用深度缓冲区
    stencil: false,                  // 禁用模板缓冲区
    premultipliedAlpha: true,        // 启用alpha预乘
    preserveDrawingBuffer: false,    // 渲染后不保留缓冲区
    powerPreference: 'high-performance', // 优先使用高性能GPU
    failIfMajorPerformanceCaveat: false  // 性能不足时回退到软件渲染
});

Common Patterns

常见模式

Framebuffer Rendering (Render to Texture)

帧缓冲区渲染(渲染到纹理)

javascript
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

const targetTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, targetTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, targetTexture, 0);

// Render to framebuffer
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.viewport(0, 0, width, height);
// ... render scene ...

// Render to canvas
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, canvas.width, canvas.height);
javascript
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

const targetTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, targetTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, targetTexture, 0);

// 渲染到帧缓冲区
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.viewport(0, 0, width, height);
// ... 渲染场景 ...

// 渲染到画布
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, canvas.width, canvas.height);

Multiple Render Targets (WebGL 2)

多渲染目标(WebGL 2)

javascript
const ext = gl.getExtension('WEBGL_draw_buffers'); // WebGL 1
// Fragment shader outputs to multiple targets
gl.drawBuffers([
    gl.COLOR_ATTACHMENT0,
    gl.COLOR_ATTACHMENT1,
    gl.COLOR_ATTACHMENT2
]);
javascript
const ext = gl.getExtension('WEBGL_draw_buffers'); // WebGL 1兼容扩展
// 片元着色器输出到多个目标
gl.drawBuffers([
    gl.COLOR_ATTACHMENT0,
    gl.COLOR_ATTACHMENT1,
    gl.COLOR_ATTACHMENT2
]);

Common Pitfalls

常见陷阱

  1. Not checking compilation/linking errors - Always check shader status
  2. Forgetting to enable attributes - Call
    gl.enableVertexAttribArray()
  3. Incorrect data types - Use
    Float32Array
    ,
    Uint16Array
    , etc.
  4. Not handling context loss - Add event listeners
  5. Mixing WebGL 1 and 2 APIs - Check version compatibility
  6. Power-of-2 texture assumptions - Handle non-POT textures correctly
  7. Z-fighting - Insufficient depth buffer precision
  8. Coordinate system confusion - WebGL uses clip space [-1, 1]
  9. Premature optimization - Profile before optimizing
  10. Not clearing buffers - Call
    gl.clear()
    each frame
  1. 未检查编译/链接错误 - 始终检查着色器状态
  2. 忘记启用属性 - 必须调用
    gl.enableVertexAttribArray()
  3. 数据类型错误 - 使用
    Float32Array
    Uint16Array
    等正确类型
  4. 未处理上下文丢失 - 添加事件监听器
  5. 混合WebGL 1和2 API - 检查版本兼容性
  6. 默认假设纹理尺寸为2的幂 - 正确处理非2的幂尺寸纹理
  7. Z轴冲突 - 深度缓冲区精度不足
  8. 坐标系混淆 - WebGL使用[-1,1]裁剪空间
  9. 过早优化 - 先分析再优化
  10. 未清空缓冲区 - 每帧调用
    gl.clear()

Debugging Tools

调试工具

  1. Browser DevTools - Check console for WebGL errors
  2. WebGL Inspector - Browser extension for frame capture
  3. Spector.js - WebGL debugging library
  4. gl.getError() - Check for runtime errors
  5. WEBGL_debug_shaders - Get translated shader source
javascript
// Error checking
const error = gl.getError();
if (error !== gl.NO_ERROR) {
    console.error('WebGL error:', error);
}
  1. 浏览器开发者工具 - 查看WebGL错误日志
  2. WebGL Inspector - 帧捕获浏览器扩展
  3. Spector.js - WebGL调试库
  4. gl.getError() - 检查运行时错误
  5. WEBGL_debug_shaders - 获取编译后的着色器源码
javascript
// 错误检查
const error = gl.getError();
if (error !== gl.NO_ERROR) {
    console.error('WebGL错误:', error);
}

Popular Libraries and Frameworks

热门库与框架

  • three.js - Comprehensive 3D library with scene graph
  • Babylon.js - Game engine with physics and VR support
  • PlayCanvas - Cloud-based game engine
  • Pixi.js - Fast 2D WebGL renderer
  • Phaser - 2D game framework
  • regl - Functional WebGL wrapper
  • twgl - Tiny WebGL helper library
  • glMatrix - High-performance matrix/vector library
  • three.js - 带场景图的全功能3D库
  • Babylon.js - 带物理和VR支持的游戏引擎
  • PlayCanvas - 云原生游戏引擎
  • Pixi.js - 高性能2D WebGL渲染器
  • Phaser - 2D游戏框架
  • regl - 函数式WebGL封装库
  • twgl - 轻量级WebGL工具库
  • glMatrix - 高性能矩阵/向量库

Learning Resources

学习资源

Quick Reference

快速参考

See reference.md for:
  • Complete constant reference
  • All WebGL methods
  • GLSL built-in functions
  • Extension compatibility matrix
See examples for:
  • Basic triangle rendering
  • Texture mapping
  • Lighting models
  • Advanced techniques
查看 reference.md 获取:
  • 完整常量参考
  • 所有WebGL方法
  • GLSL内置函数
  • 扩展兼容性矩阵
查看 examples 获取:
  • 基础三角形渲染
  • 纹理映射
  • 光照模型
  • 高级技术

Version Compatibility

版本兼容性

When supporting both WebGL 1 and 2:
javascript
function initWebGL(canvas) {
    const gl = canvas.getContext('webgl2');
    let version = 2;

    if (!gl) {
        gl = canvas.getContext('webgl');
        version = 1;
        console.log('Using WebGL 1');
    }

    // Feature detection
    const hasVAO = version === 2 || gl.getExtension('OES_vertex_array_object');
    const hasInstancing = version === 2 || gl.getExtension('ANGLE_instanced_arrays');

    return { gl, version, hasVAO, hasInstancing };
}
同时支持WebGL 1和2时的处理:
javascript
function initWebGL(canvas) {
    const gl = canvas.getContext('webgl2');
    let version = 2;

    if (!gl) {
        gl = canvas.getContext('webgl');
        version = 1;
        console.log('使用WebGL 1');
    }

    // 特性检测
    const hasVAO = version === 2 || gl.getExtension('OES_vertex_array_object');
    const hasInstancing = version === 2 || gl.getExtension('ANGLE_instanced_arrays');

    return { gl, version, hasVAO, hasInstancing };
}

Security Considerations

安全注意事项

  • Cross-origin textures - Use CORS properly
  • Shader validation - Validate user-provided shader code
  • Resource limits - Don't trust client-reported capabilities
  • Timing attacks - Be aware of shader compilation timing
  • Context fingerprinting - Users may block WebGL for privacy

When helping users with WebGL:
  1. Determine version - Check if WebGL 1 or 2 is needed
  2. Check requirements - Browser support, extensions needed
  3. Start simple - Basic rendering before advanced features
  4. Debug systematically - Check shaders, buffers, state in order
  5. Profile performance - Use browser tools to identify bottlenecks
  6. Consider libraries - Recommend three.js/Babylon.js for complex projects
  7. Validate inputs - Check for null contexts, compilation errors
  8. Handle context loss - Always implement recovery
  9. Optimize appropriately - Don't over-optimize early
  10. Test across devices - GPU capabilities vary significantly
  • 跨域纹理 - 正确使用CORS
  • 着色器验证 - 验证用户提供的着色器代码
  • 资源限制 - 不要信任客户端上报的性能参数
  • 计时攻击 - 注意着色器编译时间带来的风险
  • 上下文指纹识别 - 用户可能为隐私关闭WebGL

协助用户解决WebGL问题时的步骤:
  1. 确认版本 - 确定需要WebGL 1还是2
  2. 检查需求 - 浏览器支持情况、所需扩展
  3. 从简入手 - 先实现基础渲染再添加高级功能
  4. 系统调试 - 按着色器、缓冲区、状态顺序排查
  5. 性能分析 - 使用浏览器工具定位性能瓶颈
  6. 考虑使用库 - 复杂项目推荐three.js/Babylon.js
  7. 验证输入 - 检查空上下文、编译错误
  8. 处理上下文丢失 - 务必实现恢复逻辑
  9. 合理优化 - 不要过早过度优化
  10. 跨设备测试 - GPU性能差异较大