如何使用Three.js在GLSL片段着色器中处理摄像头画面?
在Three.js的片段着色器中处理摄像头画面
核心思路
把摄像头的VideoTexture作为uniform变量传入ShaderMaterial,就能在片段着色器中直接采样并处理画面像素。
完整实现示例
1. 准备摄像头视频元素与纹理
// 获取页面中的video元素(需提前通过getUserMedia获取摄像头权限并绑定流) const video = document.getElementById('video'); // 创建视频纹理 const cameraTexture = new THREE.VideoTexture(video); cameraTexture.colorSpace = THREE.SRGBColorSpace; // 修正视频画面翻转问题,根据实际情况调整 cameraTexture.flipY = true;
2. 配置ShaderMaterial并传入纹理uniform
const vsh = await fetch('vertex-shader.glsl'); const fsh = await fetch('fragment-shader.glsl'); const material = new THREE.ShaderMaterial({ uniforms: { resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) }, time: { value: 0.0 }, // 添加摄像头纹理作为uniform变量 cameraTexture: { value: cameraTexture } }, vertexShader: await vsh.text(), fragmentShader: await fsh.text() }); // 创建平面网格并添加到场景 const geometry = new THREE.PlaneGeometry(1, 1); const plane = new THREE.Mesh(geometry, material); plane.position.set(0.5, 0.5, 0); scene.add(plane);
3. 顶点着色器(vertex-shader.glsl)
传递UV坐标给片段着色器即可:
varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }
4. 片段着色器(fragment-shader.glsl)
采样摄像头纹理并做自定义处理(示例:灰度化):
uniform vec2 resolution; uniform float time; uniform sampler2D cameraTexture; varying vec2 vUv; void main() { // 采样摄像头画面 vec4 cameraColor = texture2D(cameraTexture, vUv); // 灰度化处理:取RGB通道加权平均值 float gray = dot(cameraColor.rgb, vec3(0.299, 0.587, 0.114)); vec4 finalColor = vec4(vec3(gray), cameraColor.a); gl_FragColor = finalColor; }
注意事项
- 确保
video元素已成功获取摄像头流并开始播放,否则纹理会显示空白 - 若画面方向异常,可调整
cameraTexture.flipY的值 - 如需实时更新uniform(如
time),要在渲染循环中同步:
function animate() { requestAnimationFrame(animate); material.uniforms.time.value += 0.01; renderer.render(scene, camera); } animate();
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

