高级光照与着色器编程学习文档
1. 高级光照技术
1.1 基于物理的渲染(PBR)
1.1.1 什么是 PBR?
基于物理的渲染(Physically Based Rendering,PBR)是一种使用物理正确的光照模型来渲染物体的技术。PBR 模型考虑了光照在现实世界中的传播和反射方式,使得渲染效果更加真实。它基于两个主要参数:
- 粗糙度(Roughness):控制表面的光滑度和高光反射强度。
- 金属度(Metalness):决定物体是否像金属一样反射环境光。
1.1.2 使用 PBR 材质
Three.js 提供了 MeshStandardMaterial
和 MeshPhysicalMaterial
两种材质,支持 PBR 渲染。
const material = new THREE.MeshStandardMaterial({
color: 0xffffff,
roughness: 0.5, // 表面粗糙度
metalness: 1.0, // 金属度
});
const sphere = new THREE.Mesh(new THREE.SphereGeometry(), material);
scene.add(sphere);
1.2 环境贴图(Environment Mapping)
1.2.1 什么是环境贴图?
环境贴图是一种将周围环境映射到物体表面的方法,用于模拟反射和折射效果。常见的环境贴图类型包括立方体贴图(Cube Map)和球面贴图(Spherical Map)。
1.2.2 使用环境贴图
在 Three.js 中,你可以使用 CubeTextureLoader
加载立方体贴图,用于模拟反射效果。
const loader = new THREE.CubeTextureLoader();
const texture = loader.load([
'px.jpg', 'nx.jpg',
'py.jpg', 'ny.jpg',
'pz.jpg', 'nz.jpg'
]);
scene.background = texture;
const material = new THREE.MeshStandardMaterial({ envMap: texture });
const cube = new THREE.Mesh(new THREE.BoxGeometry(), material);
scene.add(cube);
1.3 全局光照(Global Illumination)
1.3.1 什么是全局光照?
全局光照模拟了光线在场景中的多次反射和散射效果,真实地再现了光线在现实世界中的传播。全局光照技术使得光线能够从一个物体反射到另一个物体,增加了场景的真实感。
1.3.2 使用环境光遮蔽(Ambient Occlusion)
Three.js 支持环境光遮蔽(Ambient Occlusion, AO)来增强阴影效果,特别是在物体之间的缝隙和边缘处。
import { SSAOPass } from 'https://cdn.skypack.dev/three/examples/jsm/postprocessing/SSAOPass.js';
// 添加环境光遮蔽通道
const ssaoPass = new SSAOPass(scene, camera);
composer.addPass(ssaoPass);
2. 着色器编程基础
2.1 什么是着色器?
着色器(Shader)是运行在 GPU 上的小程序,用于计算图像中的每个像素或顶点的颜色和亮度。着色器通常使用 GLSL(OpenGL Shading Language)编写。主要的着色器类型有两种:
- 顶点着色器(Vertex Shader):负责处理每个顶点的数据,决定它在屏幕上的位置。
- 片元着色器(Fragment Shader):负责计算每个像素的颜色值,应用光照和纹理效果。
2.2 顶点着色器示例
一个简单的顶点着色器,用于将三维顶点坐标转换为二维屏幕坐标:
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
position
:当前顶点的位置。modelViewMatrix
:将顶点从局部坐标系转换到相机视图坐标系的矩阵。projectionMatrix
:将顶点从相机视图坐标系转换到屏幕坐标系的矩阵。
2.3 片元着色器示例
一个简单的片元着色器,用于为所有像素上色:
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
}
gl_FragColor
:输出的片元颜色,格式为 RGBA(红绿蓝透明度)。
3. 自定义着色器应用
3.1 使用 ShaderMaterial
Three.js 提供了 ShaderMaterial
,允许你编写自定义的着色器。以下是一个自定义着色器示例,将顶点着色器和片元着色器结合使用。
const vertexShader = `
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
void main() {
gl_FragColor = vec4(0.0, 0.5, 0.8, 1.0); // 淡蓝色
}
`;
const material = new THREE.ShaderMaterial({
vertexShader: vertexShader,
fragmentShader: fragmentShader,
});
const geometry = new THREE.SphereGeometry();
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
3.2 实现动态效果
你可以使用 GLSL 的内置时间变量和三角函数来创建动态效果,例如脉动或变换颜色:
uniform float u_time; // 时间变量
void main() {
vec3 color = vec3(0.5 + 0.5 * cos(u_time), 0.5 + 0.5 * sin(u_time), 0.8);
gl_FragColor = vec4(color, 1.0);
}
在 JavaScript 中,每一帧更新时间:
const uniforms = {
u_time: { value: 1.0 },
};
const material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
});
function animate(time) {
requestAnimationFrame(animate);
uniforms.u_time.value = time / 1000; // 以秒为单位
renderer.render(scene, camera);
}
animate();
4. 高级着色器效果
4.1 法线贴图(Normal Mapping)
法线贴图用于增强物体的细节,使得它们在光照下看起来更加复杂。使用法线贴图,你可以在不增加几何体复杂度的情况下模拟表面细节。
const textureLoader = new THREE.TextureLoader();
const normalMap = textureLoader.load('path/to/normal-map.png');
const material = new THREE.MeshStandardMaterial({
color: 0x777777,
normalMap: normalMap,
});
4.2 自定义光照模型
你可以使用片元着色器来实现自定义的光照模型。例如,实现一种双面光照的效果:
uniform vec3 lightDirection; // 光源方向
varying vec3 vNormal; // 顶点法线
void main() {
float intensity = max(dot(normalize(vNormal), lightDirection), 0.0);
vec3 color = vec3(1.0, 1.0, 1.0) * intensity;
gl_FragColor = vec4(color, 1.0);
}
5. 综合光照与着色器应用
以下示例展示了如何结合基于物理的材质和自定义着色器效果来创建一个复杂的 3D 场景:
import * as THREE from 'https://cdn.skypack.dev/three@0.155.0';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建一个立方体,使用自定义着色器
const vertexShader = `
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
uniform float u_time;
void main() {
vec3 color = vec3(0.5 + 0.5 * cos(u_time), 0.5 + 0.5 * sin(u_time), 0.8);
gl_FragColor = vec4(color, 1.0);
}
`;
const uniforms = {
u_time: { value: 1.0 },
};
const shaderMaterial = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
});
const geometry = new THREE.BoxGeometry();
const cube = new THREE.Mesh(geometry, shaderMaterial);
scene.add(cube);
camera.position.z = 5;
function animate(time) {
requestAnimationFrame(animate);
uniforms.u_time.value = time / 1000;
renderer.render(scene, camera);
}
animate();
6. 进一步学习
在掌握了高级光照和着色器编程基础后,你可以进一步学习:
- 体积光照(Volumetric Lighting):模拟烟雾、光柱等效果。
- 屏幕空间特效(Screen Space Effects):如屏幕空间环境光遮蔽(SSAO)、屏幕空间反射(SSR)等。
- 几何着色器(Geometry Shader):动态生成或修改几何体,创建复杂的形状和特效。