通过three.js 模拟海洋

创建一个真实感强的海洋效果在 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 中创建一个动态且逼真的海洋效果。通过自定义着色器、使用纹理和添加光照,你可以创建出视觉上非常吸引人的海洋场景。进一步的优化和效果增强可以包括高质量的法线贴图、反射和折射效果,以及后处理效果,以实现更高水平的真实感。

  • 23
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值