three模拟液体流动动画效果代码

代码语言:html

所属分类:动画

代码描述:three模拟液体流动动画效果代码

代码标签: three 模拟 液体 流动 动画

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  

  
  
  
  
<style>
body {margin:0px; padding:0px; overflow: hidden}
</style>


  
  
</head>

<body >
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/three.156.js"></script>
  
      <script >
let fluid,paint,count = 0,canvas;
function init() {
  const renderer = new
  THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  canvas = renderer.domElement;
  document.body.appendChild(canvas);

  // Calculate half fov radians for camera setup
  const fov = 65;
  const hFovRadian = fov / 2 / 180 * Math.PI;
  const cz = window.innerHeight / 2 / Math.tan(hFovRadian);

  // Setup camera
  const camera = new THREE.PerspectiveCamera(fov, window.innerWidth / window.innerHeight, 0.1, cz * 4);
  camera.position.z = cz;

  // Create context object to hold renderer, camera and dimensions
  const context = { renderer, camera, width: window.innerWidth, height: window.innerHeight };

  // Initialize fluid and paint simulations
  fluid = new Fluid(context);
  paint = new Paint(context);
}

async function animate() {
  if (count % 640 == 0) {
    fluid.init();
    paint.init();
  }
  count++;

  fluid.update();
  fluid.draw();
  paint.update(fluid.getVelocity());
  paint.draw();
  requestAnimationFrame(animate);
}


//----------------------------------------

class Fluid {
  constructor(context) {
    this.context = context;
    this.speed = 4;
    this.forceInitMaterial = this.createShaderMaterial(forceInitFrag);
    this.divergenceMaterial = this.createShaderMaterial(divergenceFrag);
    this.advectionMaterial = this.createShaderMaterial(advectionFrag);
    this.pressureMaterial = this.createShaderMaterial(pressureFrag);
    this.updateMaterial = this.createShaderMaterial(forceUpdateFrag);
    this.renderMaterial = this.createShaderMaterial(forceRenderFrag);
    this.velocity = [this.createRenderTarget(), this.createRenderTarget()];
    this.pressure = [this.createRenderTarget(), this.createRenderTarget()];
    this.divergence = this.createRenderTarget();
    this.advection = this.createRenderTarget();
    this.blank = this.createRenderTarget();

    // Main Scene
    this.mainScene = new THREE.Scene();
    this.mainMesh = this.createMesh(0, 0, this.context.width, this.context.height);
    this.mainScene.add(this.mainMesh);

    this.init();
  }

  init() {
    this.velocityIndex = 0;
    this.context.renderer.setRenderTarget(this.velocity[0]);
    this.mainMesh.material = this.forceInitMaterial;
    this.forceInitMaterial.uniforms.seed = { value: Math.random() * 100.0 };
    this.context.renderer.render(this.mainScene, this.context.camera);
    this.context.renderer.setRenderTarget(null);
  }

  createShaderMaterial(frag) {
    return new THREE.ShaderMaterial({
      vertexShader: vert,
      fragmentShader: frag,
      uniforms: { tex: { value: null }, res: { value: [this.context.width, this.context.height] }, speed: { value: this.speed } } });

  }

  createRenderTarget() {
    return new THREE.WebGLRenderTarget(this.context.width, this.context.height, {
      format: THREE.RGBAFormat,
      type: THREE.FloatType });

  }

  createMesh(cx, cy, w, h) {
    const geometry = new THREE.PlaneGeometry(w, h);
    const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
    const mesh = new THREE.Mesh(geometry, material);
    mesh.position.x = cx;
    mesh.position.y = cy;
    return mesh;
  }

  update() {
    this.updateAdvection();
    this.updateDivergence();
    this.updatepPressure();
    this.updateVelocity();
  }

  updateAdvection() {
    this.context.renderer.setRenderTarget(this.advection);
    this.mainMesh.material = this.advectionMaterial;
    this.advectionMaterial.uniforms.tex = { value: this.velocity[this.velocityIndex].texture };
    this.context.renderer.render(this.mainScene, this.context.camera);
    this.context.renderer.setRenderTarget(null);
  }

  updateDivergence() {
    this.context.renderer.setRenderTarget(this.divergence);
    this.mainMesh.material = this.divergenceMaterial;
    this.divergenceMaterial.uniforms.tex = { value: this.advection.texture };
    this.context.renderer.render(this.mainScene, this.context.camera);
    this.context.renderer.setRenderTarget(null);
  }

  updatepPressure() {
    this.context.renderer.setRenderTarget(this.pressure[0]);
    this.context.renderer.clear();
    this.context.renderer.setRenderTarget(null);

    for (let i = 0; i < 4; i++) {
      let i0 = i % 2;
      let i1 = (i + 1) % 2;
      const prevPressure = this.pressure[i0];
      const nextPressure = this.pressure[i1];

      this.context.renderer.setRenderTarget(nextPressure);
      this.mainMesh.material = this.pressureMaterial;
      this.pressureMaterial.uniforms.tex = { value: prevPressure.texture };
      this.pressureMaterial.uniforms.divergence = { value: this.divergence.texture };
      this.context.renderer.render(this.mainScene, this.context.camera);
      this.context.renderer.setRenderTarget(null);
    }
  }

  updateVelocity() {
    const i1 = (this.velocityIndex + 1) % 2;
    const nextVelocity = this.velocity[i1];
    this.velocityIndex = i1;

    this.context.renderer.setRenderTarget(nextVelocity);
    this.mainMesh.material = this.updateMaterial;
    this.updateMaterial.uniforms.pressure = { value: this.pressure[1].texture };
    this.updateMaterial.uniforms.advection = { value: this.advection.texture };
    this.context.renderer.render(this.mainScene, this.context.camera);
    this.context.renderer.setRenderTarget(null);
  }

  draw() {
    this.mainMesh.material = this.renderMaterial;
    this.renderMaterial.uniforms.tex = { value: this.getVelocity().texture };
    this.context.renderer.render(this.mainScene, this.context.camera);
  }

  getVelocity() {
    return this.velocity[this.velocityIndex];
  }}


class Paint {
  constructor(context) {
    this.context = context;
    this.speed = 4;
    this.initMaterial = this.createShaderMaterial(paintInitFrag);
    this.updateMaterial = this.createShaderMaterial(paintUpdateFrag);
    this.renderMaterial = this.createShaderMaterial(paintRenderFrag);
    this.paint = [this.createRenderTarget(), this.createRenderTarget()];

    // Main Scene
    this.mainScene = new THREE.Scene();
    this.mainMesh = this.createMesh(0, 0, this.context.width, this.context.height);
    this.mainScene.add(this.mainMesh);

    this.init();
  }

  init() {
    this.paintIndex = 0;
    this.context.renderer.setRenderTarget(this.paint[0]);
    this.mainMesh.material = this.initMaterial;
    this.initMaterial.uniforms.seed = { value: Math.random() * 100.0 };
    this.context.renderer.render(this.mainScene, this.context.camera);
    this.context.renderer.setRenderTarget(null);
  }

  createShaderMaterial(frag) {
    return new THREE.ShaderMaterial({
      vertexShader: vert,
      fragmentShader: frag,
      uniforms: { tex: { value: null }, res: { value: [this.context.width, this.context.height] }, speed: { value: this.speed } } });

  }

  createRenderTarget() {
    return new THREE.WebGLRenderTarget(this.context.width, this.context.height, {
      format: THREE.RGBAFormat,
      type: THREE.FloatType });

  }

  createMesh(cx, cy, w, h) {
    const geometry = new THREE.PlaneGeometry(w, h);
    const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
    const mesh = new THREE.Mesh(geometry, material);
    mesh.position.x = cx;
    mesh.position.y = cy;
    return mesh;
  }

  update(velocity) {
    const i0 = this.paintIndex % 2;
    const i1 = (this.paintIndex + 1) % 2;
    const prevPaint = this.paint[i0];
    const nextPaint = this.paint[i1];
    this.paintIndex = i1;

    this.context.renderer.setRenderTarget(nextPaint);
    this.mainMesh.material = this.updateMaterial;
    this.updateMaterial.uniforms.tex = { value: prevPaint.texture };
    this.updateMaterial.uniforms.velocity = { value: velocity.texture };
    this.context.renderer.render(this.mainScene, this.context.camera);
    this.context.renderer.setRenderTarget(null);
  }

  draw() {
    this.mainMesh.material = this.renderMaterial;
    this.renderMaterial.uniforms.tex = { value: this.getPaint().texture };
    this.context.renderer.render(this.mainScene, this.context.camera);
  }

  getPaint() {
    return this.paint[this.paintIndex];
  }}


// SHADERS


const noise = `
/*
Simplex Noise code is from:
(Shader Library) Simplex Noise in GLSL
http://www.geeks3d.com/20110317/shader-library-simplex-noise-glsl-opengl/
*/

#define  NORMALIZE_GRADIENTS
#undef  USE_CIRCLE
#define COLLAPSE_SORTNET

    float permute(float x0,vec3 p) {
        float x1 = mod(x0 * p.y, p.x);
        return floor(  mod( (x1 + p.z) *x0, p.x ));
    }
    vec2 permute(vec2 x0,vec3 p) {
        vec2 x1 = mod(x0 * p.y, p.x);
        return floor(  mod( (x1 + p.z) *x0, p.x ));
    }
    vec3 permute(vec3 x0,vec3 p) {
        vec3 x1 = mod(x0 * p.y, p.x);
        return floor(  mod( (x1 + p.z) *x0, p.x ));
    }
    vec4 permute(vec4 x0,vec3 p) {
        vec4 x1 = mod(x0 * p.y, p.x);
        return floor(  mod( (x1 + p.z) *x0, p.x ));
    }

    //uniform vec4 pParam;
    // Example constant with a 289 element permutation
    const vec4 pParam = vec4( 17.0*17.0, 34.0, 1.0, 7.0);

    float taylorInvSqrt(float r)
    {
        return ( 0.83666002653408 + 0.7*0.85373472095314 - 0.85373472095314 * r );
    }

    float simplexNoise2(vec2 v)
    {
        const vec2 C = vec2(0.211324865405187134, // (3.0-sqrt(3.0))/6.;
                            0.366025403784438597); // 0.5*(sqrt(3.0)-1.);
        const vec3 D = vec3( 0., 0.5, 2.0) * 3.14159265358979312;
        // First corner
        vec2 i  = floor(v + dot(v, C.yy) );
        vec2 x0 = v -   i + dot(i, C.xx);

        // Other corners
        vec2 i1  =  (x0.x > x0.y) ? vec2(1.,0.) : vec2(0.,1.) ;

        //  x0 = x0 - 0. + 0. * C
        vec2 x1 = x0 - i1 + 1. * C.xx ;
        vec2 x2 = x0 - 1. + 2. * C.xx ;

        // Permutations
        i = mod(i, pParam.x);
        vec3 p = permute( permute(
                                  i.y + vec3(0., i1.y, 1. ), pParam.xyz)
                         + i.x + vec3(0., i1.x, 1. ), pParam.xyz);

#ifndef USE_CIRCLE
        // ( N points uniformly over a line, mapped onto a diamond.)
        vec3 x = fract(p / pParam.w) ;
        vec3 h = 0.5 - abs(x) ;

        vec3 sx = vec3(lessThan(x,D.xxx)) *2. -1.;
        vec3 sh = vec3(lessThan(h,D.xxx));

        vec3 a0 = x + sx*sh;
        vec2 p0 = vec2(a0.x,h.x);
        vec2 p1 = vec2(a0.y,h.y);
        vec2 p2 = vec2(a0.z,h.z);

#ifdef NORMALISE_GRADIENTS
        p0 *= taylorInvSqrt(dot(p0,p0));
        p1 *= taylorInvSqrt(dot(p1,p1));
        p2 *= taylorInvSqrt(dot(p2,p2));
#endif

        vec3 g = 2.0 * vec3( dot(p0, x0), dot(p1, x1), dot(p2, x2) );
#else
        // N points around a unit circle.
        vec3 phi = D.z * mod(p,pParam.w) /pParam.w ;
        vec4 a0 = sin(phi.xxyy+D.xyxy);
        vec2 a1 = sin(phi.zz  +D.xy);
        vec3 g = vec3( dot(a0.xy, x0), dot(a0.zw, x1), dot(a1.xy, x2) );
#endif
        // mix
        vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.);
        m = m*m ;
        return 1.66666* 70.*dot(m*m, g);
    }

    float simplexNoise3(vec3 v)
    {
        .........完整代码请登录后点击上方下载按钮下载查看

网友评论0