WebGL高级实例--利用WebGL+Three.js实现海水波浪场景

通过对webgl和three.js的基础知识学习,发现在三维场景应用实现过程中,完全采用webgl编写需要的工作量非常大,具体可参见我上一篇文章,而且由于片元着色器和顶点着色器是强类型语法,类似C语言,编程过程中有任何的小错误都不好调试与定位。因此,大家经常使用的做法是采用一个开源引擎框架结合webgl开展,目前大部分浏览器都支持webgl,比如采用three.js+webgl编写本文提到的海水波浪应用,当然也可以完全基于three.js来实现,而完全利用three.js实现动态的三维管道效果,请参考另一篇文章

开发环境:vue-2.5.2,Three.js-0.142.0,开发工具webstorm2021.2.3,前端用chrome109.0.5414.120,其他默认。

以下是海水波浪场景示例的功能描述和关键核心代码。

1.实现功能简述:在浏览器中实现海浪波动的三维效果,不能安装插件,支持旋转、放大缩小,并支持在线调整海浪的各类参数,比如波高、波频、波速等等。

2.海浪效果:

  

3.关键代码如下(完整代码请联系我):

在three.js中通过import引入webgl编写的两个着色器:顶点着色器和片元着色器。

import * as THREE from "three"; //引入Threejs
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import waterVertexShader from './shaders/vertex0.glsl';//引入顶点着色器的GLSL文件
import waterFragmentShader from './shaders/fragment0.glsl';//引入片元着色器的GLSL文件

在thee.js中的init方法中构建原始材质,关键代码如下:

// 构建材质贴图
const textureLoader = new THREE.TextureLoader();
const flagTexture = textureLoader.load( '/static/data/waternormals.jpg', function ( texture ) {
  texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
});

// 构建材质,以便后续
const planeMaterial = new THREE.RawShaderMaterial({
  vertexShader: waterVertexShader,
  fragmentShader: waterFragmentShader,
  // transparent: true,
  uniforms:
  {
    //uFrequency: { value: 20 },
    side:THREE.DoubleSide,
    uBigWavesElevation: { value: 0.2 },//波高
    uBigWavesSpeed: { value: 0.75 },//波速
    uFrequency: { value: new THREE.Vector2(5, 7)},
    uTime: { value:10 },
    uColor: { value: new THREE.Color('orange') },
    uTexture: { value: flagTexture }
  }

// 创建三维水面Mesh,并加载的场景中。
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.material.opacity = 0.3;
plane.material.transparent = true;
that.scene.add(plane);

// 创建右上角的gui控制面板
let gui=new GUI();
gui.add(planeMaterial.uniforms.uBigWavesElevation, 'value')
  .min(0)
  .max(1)
  .step(0.001)
  .name('uBigWavesElevation')
gui.add(planeMaterial.uniforms.uBigWavesSpeed, 'value')
  .min(0)
  .max(4)
  .step(0.001)
  .name('uBigWavesSpeed')

// 同时为了让水面动起来,需要创建animate和tick方法,与init方法类似
animate() {
  this.tick();
  requestAnimationFrame( this.animate );//调用自己
  const delta = this.clock.getDelta();
  if ( this.mixer ) this.mixer.update( delta );
  this.renderer.render( this.scene, this.camera );
  this.controls.update();
  this.stats.update();
},

// 循环执行
tick() {
  let elapsedTime = this.clock.getElapsedTime()*2;
  // Update material
  this.material.uniforms.uTime.value = elapsedTime;
}

 

扫描二维码关注公众号,回复: 14792657 查看本文章

猜你喜欢

转载自blog.csdn.net/hhue2007/article/details/128989997
今日推荐