当前位置: 首页 > news >正文

Three.js 海面教程

海面 ·Ocean Shader· ▶ 在线运行案例

  • 案例合集:三维可视化功能案例(threehub.cn)
  • 开源仓库github地址:https://github.com/z2586300277/three-cesium-examples
  • 400个案例代码:网盘链接

你将学到什么

  • 官方Water对象(examples/jsm/objects/Water.js
  • waterNormals法线贴图 +RepeatWrapping
  • uniforms.time驱动波浪
  • lil-gui 调waterColor / sunColor / sunDirection

效果说明

万级平面海面荡漾,天空盒反射;GLTF 挖掘机模型设envMap与环境一致;GUI 实时改水体与太阳参数。

核心概念

import { Water } from 'three/examples/jsm/objects/Water.js';

const water = new Water(waterGeometry, { textureWidth: 512, textureHeight: 512, waterNormals: new THREE.TextureLoader().load('waternormals.jpg', t => { t.wrapS = t.wrapT = THREE.RepeatWrapping; }), sunDirection: new THREE.Vector3(), sunColor: 0xffffff, waterColor: 0x001e0f, distortionScale: 3.7, fog: scene.fog !== undefined, }); water.rotation.x = -Math.PI / 2;

动画

water.material.uniforms['time'].value += 1.0 / 60.0;

每帧递增time,Water 内部 shader 算法线偏移与反射。

GUI

gui.addColor(water.material.uniforms['waterColor'], 'value');

gui.add(water.material.uniforms['sunDirection'].value, 'x', -1, 1);

实现步骤

  • PlaneGeometry 10000×10000 创建 Water
  • CubeTexture 天空盒 → background + 模型 envMap
  • GLTFLoader 加载场景模型
  • animate 更新 time + controls + render
  • 代码要点

    import * as THREE from 'three'

    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' import { Water } from 'three/examples/jsm/objects/Water.js'; import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js' import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'

    const box = document.getElementById('box')

    const scene = new THREE.Scene()

    const camera = new THREE.PerspectiveCamera(50, box.clientWidth / box.clientHeight, 0.1, 1000000)

    camera.position.set(6, 3, 15)

    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true })

    renderer.setSize(box.clientWidth, box.clientHeight)

    box.appendChild(renderer.domElement)

    const controls = new OrbitControls(camera, renderer.domElement)

    controls.enableDamping = true

    const waterGeometry = new THREE.PlaneGeometry(10000, 10000);

    const water = new Water( waterGeometry, { textureWidth: 512, textureHeight: 512, waterNormals: new THREE.TextureLoader().load( FILE_HOST + '/images/texture/waternormals.jpg', function (texture) { texture.wrapS = texture.wrapT = THREE.RepeatWrapping;

    }), sunDirection: new THREE.Vector3(), sunColor: 0xffffff, waterColor: 0x001e0f, distortionScale: 3.7, fog: scene.fog !== undefined } );

    water.rotation.x = - Math.PI / 2;

    scene.add(water);

    // 文件地址 const urls = [0, 1, 2, 3, 4, 5].map(k => (FILE_HOST + 'files/sky/skyBox0/' + (k + 1) + '.png'));

    const textureCube = new THREE.CubeTextureLoader().load(urls);

    scene.background = textureCube;

    new GLTFLoader().load('https://z2586300277.github.io/3d-file-server/models/glb/wajueji.glb',

    gltf => {

    gltf.scene.traverse(child => {

    if (child.isMesh) {

    child.material.envMap = textureCube

    }

    })

    scene.add(gltf.scene)

    }

    )

    const gui = new GUI();

    gui.addColor(water.material.uniforms['waterColor'], 'value').name('waterColor');

    gui.addColor(water.material.uniforms['sunColor'], 'value').name('sunColor');

    gui.add(water.material.uniforms['sunDirection'].value, 'x', - 1, 1).name('sunX');

    animate()

    function animate() {

    water.material.uniforms['time'].value += 1.0 / 60.0;

    requestAnimationFrame(animate)

    controls.update()

    renderer.render(scene, camera)

    }

    window.onresize = () => {

    renderer.setSize(box.clientWidth, box.clientHeight)

    camera.aspect = box.clientWidth / box.clientHeight

    camera.updateProjectionMatrix()

    }

    完整源码:GitHub

    小结

    • 本文提供海面完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
    • 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库
http://www.jsqmd.com/news/1140651/

相关文章:

  • res-downloader:跨平台智能资源下载工具完全指南
  • SQL注入绕过实战:3种大小写过滤场景与sqlmap randomcase脚本应用
  • AI换装工具本地部署:硬件选型、批量处理与稳定性优化指南
  • 豆包千问同日关停自建智能体:从工程视角拆解确定性需求与概率性系统
  • LRCGET:如何让您的本地音乐库拥有完美同步歌词体验
  • 2026通关榜!好用的降AI率平台实测,过审成功率直接拉满
  • 炉石传说脚本终极指南:5分钟实现智能自动化对战
  • 低性能老旧设备改造PCDN,轻量化系统优化方案
  • Shell基础知识点完整知识框架体系
  • 【Autosar从入门到精通到进阶实战篇】08 CAN与CAN FD的兼容性设计——当“老车”遇上“新总线”
  • 艾尔登法环存档管理终极指南:EldenRingSaveCopier 完整使用教程
  • OpenClaw 高效数据采集与自动化应用场景
  • Windows 11 LTSC 微软商店终极安装指南:3分钟恢复完整应用生态
  • 终极崩坏星穹铁道自动化指南:3分钟学会解放双手的游戏辅助神器
  • HapTile:面向接触密集型操作的触觉-视觉-语言多模态机器人数据集
  • 3分钟掌握全网资源下载神器:res-downloader完整教程
  • 2026年重庆精品乡村民宿数据调研:排行榜上的优质之选
  • 客户案例 | 破解传统金融数仓困局:某商业银行构建云原生数仓实践
  • DeepJSCC 图像传输实战:PyTorch 实现 3 种信道模型下的端到端收发机
  • 中兴光猫权限解锁工具:5分钟获取设备完全控制权的终极指南
  • Navicat无限重置试用期:3种方法让Mac用户永久享受专业版功能
  • 格氏ACE模型电池首场“RC放肆野玩局”圆满落幕|让热爱更出格
  • 不会Python也能分析数据?这个CSV分析AI帮你3分钟搞定
  • ArcGIS Pro 3.6 天际线分析实战:ModelBuilder 批量计算20个观测点建筑高度控制
  • AI视频提示词设计:从基础概念到工程实践
  • 星穹铁道自动化助手:告别重复劳动的游戏管家
  • Kaggle Notebook 文件管理实战:3种保存与清理 /kaggle/working 目录的方法
  • 盘锦客厅地砖防滑性,看纹理也看清洁
  • Codex官方没说的秘密:一个小设置让额度变相翻倍
  • Apache Druid CVE-2021-36749 修复方案对比:4种安全加固策略与性能影响评估