创建一个真实感强的海洋效果在 three.js
中涉及多个方面,包括着色器、物理模拟和后处理效果。下面是一个详细的教程,介绍如何使用 three.js
创建一个炫酷的海洋效果。
1. 基础设置
首先,确保你已经设置了一个基本的 three.js
环境。你可以使用以下基本的 three.js
代码创建一个简单的场景:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Three.js Ocean Simulation</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// Create the scene, camera, and renderer
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);
camera.position.z = 5;
// Render loop
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
2. 创建基本的海洋
接下来,我们将使用 PlaneGeometry
和自定义着色器来创建海洋效果。首先,需要定义海洋的着色器:
1.1 创建海洋着色器
// Vertex Shader
const vertexShader = `
uniform float time;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 pos = position;
pos.z += sin(uv.x * 10.0 + time) * 0.5;
pos.z += sin(uv.y * 10.0 + time) * 0.5;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`;
// Fragment Shader
const fragmentShader = `
varying vec2 vUv;
uniform sampler2D texture;
void main() {
vec4 color = texture2D(texture, vUv);
gl_FragColor = color;
}
`;
1.2 创建海洋材质和网格
// Load a water texture
const textureLoader = new THREE.TextureLoader();
const waterTexture = textureLoader.load('path/to/your/water/texture.jpg');
// Create the shader material
const waterMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0.0 },
texture: { value: waterTexture }
},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
side: THREE.DoubleSide
});
// Create the water plane
const waterGeometry = new THREE.PlaneGeometry(10, 10, 128, 128);
const waterMesh = new THREE.Mesh(waterGeometry, waterMaterial);
scene.add(waterMesh);
3. 动画效果
我们需要在 animate
函数中更新 time
变量,以产生动态的海洋效果:
function animate() {
requestAnimationFrame(animate);
// Update the time uniform
waterMaterial.uniforms.time.value += 0.01;
renderer.render(scene, camera);
}
4. 添加光照和环境
为了使海洋看起来更真实,我们可以添加一些环境光和方向光:
// Ambient light
const ambientLight = new THREE.AmbientLight(0x404040); // soft white light
scene.add(ambientLight);
// Directional light
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 5, 5).normalize();
scene.add(directionalLight);
5. 增强效果
5.1 添加反射和折射
海洋的真实感通常包括反射和折射效果。你可以使用 THREE.CubeTextureLoader
加载立方体纹理作为环境映射,来模拟这些效果。
const cubeTextureLoader = new THREE.CubeTextureLoader();
const envMap = cubeTextureLoader.load([
'path/to/your/skybox/px.jpg',
'path/to/your/skybox/nx.jpg',
'path/to/your/skybox/py.jpg',
'path/to/your/skybox/ny.jpg',
'path/to/your/skybox/pz.jpg',
'path/to/your/skybox/nz.jpg'
]);
scene.background = envMap;
waterMaterial.envMap = envMap;
5.2 添加波动效果
使用更高级的着色器可以创建更复杂的波动效果,例如利用傅里叶变换生成波浪:
const advancedVertexShader = `
uniform float time;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 pos = position;
pos.z = sin(pos.x * 10.0 + time) * 0.5 + sin(pos.y * 10.0 + time) * 0.5;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`;
const advancedFragmentShader = `
varying vec2 vUv;
uniform sampler2D texture;
void main() {
vec4 color = texture2D(texture, vUv);
gl_FragColor = color;
}
`;
const advancedWaterMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0.0 },
texture: { value: waterTexture }
},
vertexShader: advancedVertexShader,
fragmentShader: advancedFragmentShader,
side: THREE.DoubleSide
});
6. 优化和美化
为了提高性能和视觉效果,你可以考虑以下措施:
- 后处理效果: 使用
THREE.EffectComposer
和后处理材质来增加水面反射、折射等效果。 - 法线贴图: 使用法线贴图来增加细节,使水面看起来更有质感。
- 动态波动: 通过动态生成波动纹理进一步提升效果。
7. 完整代码示例
将所有代码片段整合起来,你可以获得一个完整的示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Three.js Ocean Simulation</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// Create the scene, camera, and renderer
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);
camera.position.z = 5;
// Load texture
const textureLoader = new THREE.TextureLoader();
const waterTexture = textureLoader.load('path/to/your/water/texture.jpg');
// Shaders
const vertexShader = `
uniform float time;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 pos = position;
pos.z += sin(uv.x * 10.0 + time) * 0.5;
pos.z += sin(uv.y * 10.0 + time) * 0.5;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`;
const fragmentShader = `
varying vec2 vUv;
uniform sampler2D texture;
void main() {
vec4 color = texture2D(texture, vUv);
gl_FragColor = color;
}
`;
// Create the water material
const waterMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0.0 },
texture: { value: waterTexture }
},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
side: THREE.DoubleSide
});
// Create the water plane
const waterGeometry = new THREE.PlaneGeometry(10, 10, 128, 128);
const waterMesh = new THREE.Mesh(waterGeometry, waterMaterial);
scene.add(waterMesh);
// Add lights
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 5, 5).normalize();
scene.add(directionalLight);
// Animation
loop
function animate() {
requestAnimationFrame(animate);
waterMaterial.uniforms.time.value += 0.01;
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
总结
这个教程展示了如何在 three.js
中创建一个动态且逼真的海洋效果。通过自定义着色器、使用纹理和添加光照,你可以创建出视觉上非常吸引人的海洋场景。进一步的优化和效果增强可以包括高质量的法线贴图、反射和折射效果,以及后处理效果,以实现更高水平的真实感。