three实现一个三维唱片碟片旋转播放曲线乐章效果代码

代码语言:html

所属分类:三维

代码描述:three实现一个三维唱片碟片旋转播放曲线乐章效果代码

代码标签: three 三维 唱片 碟片 旋转 播放 曲线 乐章

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

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

<head>

  <meta charset="UTF-8">
  

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



</head>

<body  >
    <script  async type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/es-module-shims.1.6.2.js"></script>

<script type="importmap">
  {
    "imports": {
      "three": "//repo.bfw.wiki/bfwrepo/js/module/three/build/146/three.module.js",
      "three/addons/": "//repo.bfw.wiki/bfwrepo/js/module/three/examples/jsm/"
    }
  }
</script>


  
      <script  type="module">
import * as THREE from "three";
import {OrbitControls} from "three/addons/controls/OrbitControls.js";
import {mergeBufferGeometries} from "three/addons/utils/BufferGeometryUtils.js";

import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';

console.clear();

class Postprocessing {
  constructor(scene, camera, renderer) {
    const renderScene = new RenderPass(scene, camera);
    const bloomPass = new UnrealBloomPass(
      new THREE.Vector2(window.innerWidth, window.innerHeight),
      1.25,
      0.25,
      0
    );
    let samples = 4;
    const target1 = new THREE.WebGLRenderTarget(
      window.innerWidth,
      window.innerHeight,
      {
        type: THREE.FloatType,
        format: THREE.RGBAFormat,
        encoding: THREE.sRGBEncoding,
        samples: samples
      }
    );
    this.bloomComposer = new EffectComposer(renderer, target1);
    this.bloomComposer.renderToScreen = false;
    this.bloomComposer.addPass(renderScene);
    this.bloomComposer.addPass(bloomPass);
    const finalPass = new ShaderPass(
      new THREE.ShaderMaterial({
        uniforms: {
          baseTexture: { value: null },
          bloomTexture: { value: this.bloomComposer.renderTarget2.texture }
        },
        vertexShader: `varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); }`,
        fragmentShader: `uniform sampler2D baseTexture; uniform sampler2D bloomTexture; varying vec2 vUv; void main() { gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) ); }`,
        defines: {}
      }),
      "baseTexture"
    );
    finalPass.needsSwap = true;
    const target2 = new THREE.WebGLRenderTarget(
      window.innerWidth,
      window.innerHeight,
      {
        type: THREE.FloatType,
        format: THREE.RGBAFormat,
        encoding: THREE.sRGBEncoding,
        samples: samples
      }
    );
    this.finalComposer = new EffectComposer(renderer, target2);
    this.finalComposer.addPass(renderScene);
    this.finalComposer.addPass(finalPass);
  }
}

class LightEmitterCurve extends THREE.Curve{
	constructor( radius, turns, height ) {
		super();
    this.radius = radius;
    this.height = height;
    this.turns = turns;
	}

	getPoint( t, optionalTarget = new THREE.Vector3() ) {

		return optionalTarget.setFromCylindricalCoords( this.radius, -Math.PI * 2 * this.turns * t, this.height * t );

	}

}

class LightEmitters extends THREE.Object3D{
  constructor(gu, count, maxR, height, turns, m){
    super();
    let gsBall = [];
    let gsEmitter = [];
    let start = maxR / 4;
    let totalWidth = maxR * 0.9 - start;
    let step = totalWidth / (count - 1);
    let v3 = new THREE.Vector3();
    let axis = new THREE.Vector3(0, 1, 0);
    for( let i = 0; i < count; i++){
      
      let shift = start + step * i;
      
      let gBall = new THREE.SphereGeometry(0.05, 64, 32, 0, Math.PI * 2, 0, Math.PI * 0.5);
      gBall.translate(0, 0, shift);
      gsBall.push(gBall);
      
      /*let gEmitter = new THREE.CylinderGeometry(0.03, 0.03, height, 16, 200);
      gEmitter.translate(shift, height * 0.5, 0);
      let pos = gEmitter.attributes.position;
      for(let i = 0; i < pos.count; i++){
        v3.fromBufferAttribute(pos, i);
        let ratio = v3.y / height;
        let angle = -ratio * Math.PI * 2 * turns;
        v3.applyAxisAngle(axis, angle);
        pos.setXYZ(i, v3.x, v3.y, v3.z);
      }
      gEmitter.computeVertexNormals();*/
      let lightEmitterCurve = new LightEmitterCurve(shift, turns, height);
      let gEmitter = new THREE.TubeGeometry(lightEmitterCurve, 200, 0.02, 16);
      gsEmitter.push(gEmitter);
    }
    
    let gBalls = mergeBufferGeometries(gsBall);
    let balls = new THREE.Mesh(gBalls, m.clone());
    balls.userData.nonGlowing = true;
    //balls.castShadow = true;
    this.add(balls);
    
    let gEmitters = mergeBufferGeometries(gsEmitter);
    let mEmitters = new THREE.MeshBasicMaterial({
      side: THREE.DoubleSide,
      color: new THREE.Color(1, 0.25, 0),
      onBeforeCompile: shader => {
        shader.uniforms.globalBloom = gu.globalBloom;
        shader.vertexShader = `
          varying vec3 vPos;
          ${shader.vertexShader}
        `.replace(
          `#include <begin_vertex>`,
          `#include <begin_vertex>
            vPos = position;
          `
        );
        //console.log(shader.vertexShader)
        shader.fragmentShader = `
          #define ss(a, b, c) smoothstep(a, b, c)
          uniform float globalBloom;
          varying vec3 vPos;
          ${shader.fragmentShader}
        `.replace(
        `#include <dithering_fragment>`,
        `#include <dithering_fragment>
          vec3 colNonGlow = vec3(1, 0.75, 0.75); // * pow((sin(vUv.x * 200. * PI2) * 0.5 + 0.5) * 0.6 + 0.4, 3.);
          vec3 colGlow = gl_FragColor.rgb;
          gl_FragColor.rgb = mix(colNonGlow, colGlow, globalBloom);
        `
      );
      }
    });
    mEmitters.defines = {"USE_UV" : ""};
    let emitters = new THREE.Mesh(gEmitters, mEmitters);
    //emitters.castShadow = true;
    this.add(emitters);
  }
}

class Belt extends THREE.Mesh{
  constructor(gu, mainSize, rBig, rSmall, width, m){
    let m1 = m.clone();
    m1.color.set("gray");
    //m1.side = THREE.DoubleSide;
    
    let hSize = mainSize;
    let path = new THREE.Shape()
    .absarc(0, 0, rBig, Math.PI * 1.5, Math.PI)
    .absarc(-hSize + rSmall, -hSize + rSmall, rSmall, Math.PI, Math.PI * 1.5)
    .lineTo(0, -hSize);
    
    const segs = 500;
    const hw = width * 0.5;
    let pathPts = path.getSpacedPoints(segs).reverse();
    /*
    let pg = new THREE.BufferGeometry().setFromPoints(pathPts);
    let pm = new THREE.PointsMaterial({color: "yellow", size: 0.05});
    let pp = new THREE.Points(pg, pm);
    */
    let g = new THREE.BoxGeometry(segs, 0.01, width, segs, 1, 1).translate(segs * 0.5, 0.005, 0);
    
    let vPrev = new THREE.Vector2(), vCurr = new THREE.Vector2(), vNext = new THREE.Vector2();
    let vCP = new THREE.Vector2(), vCN = new THREE.Vector2(), v2 = new THREE.Vector2(), cntr = new THREE.Vector2();
    
    let pos = g.attributes.position;
    for(let i = 0; i < pos.count; i++){
      let idxCurr = Math.round(pos.getX(i));
      let idxPrev = idxCurr == 0 ? segs - 1 : idxCurr - 1;
      let idxNext = idxCurr == segs ? 1 : idxCurr + 1;
      vPrev.copy(pathPts[idxPrev]);
      vCurr.copy(pathPts[idxCurr]);
      vNext.copy(pathPts[idxNext]);
      vCP.subVectors(vPrev, vCurr);
      vCN.subVectors(vNext, vCurr);
      let aCP = vCP.angle();
      let aCN = vCN.angle();
      let hA = Math.PI * 0.5 - (aCP - aCN) * 0.5;
      let aspect = Math.cos(hA);
      v2.set(vCurr.x, vCurr.y).multiplyScalar(pos.getY(i) / aspect);
      v2.rotateAround(cntr, hA).add(vCurr);
      pos.setXY(i, v2.x, v2.y);
    }
    g.rotateX(-Math.PI * 0.5);
    g.computeVertexNormals();
    super(g, m1);
    this.castShadow = true;
    this.receiveShadow = true;
    this.uniforms = {
      time: {value: 0},
      angularSpe.........完整代码请登录后点击上方下载按钮下载查看

网友评论0