图形学demo1:两个plane(一个basic材质,一个shader材质)由白变红,shader材质的mesh晚一秒开始

49 阅读1分钟

题目:两个plane(一个basic材质,一个shader材质)由白变红,shader材质的mesh晚一秒开始 App.tsx

import './App.css'
import Home from './pages/home'

function App() {

  return (
    <Home/>
  )
}

export default App

Home.tsx

import {useEffect,useRef,useState} from 'react'
import Stage from '../stage'
import './index.scss'
const Home : React.FC = () => {
    const canvasRef = useRef<HTMLCanvasElement>();
    const [size, setSize] = useState([1,1]);
    const [isInit, setInit] = useState(false)

    useEffect(() => {
        if(canvasRef.current){
            const canvas = canvasRef.current;
            setSize([canvas.clientWidth, canvas.clientHeight]);
            setInit(true);
        }
    }, [])

    useEffect(() => {
        if(isInit){
            const canvas = canvasRef.current as HTMLCanvasElement;
            const stage = new Stage(canvas);
            stage.start();
        }
    }, [isInit])

    return <canvas className={"canvas"} ref={canvasRef} width={size[0]} height={size[1]} />
}

export default Home;

Stage.ts

import * as THREE from 'three'
import { Global } from '@/utils/Global';
import ChangedPlanes from '../changed-planes';
import CheckerBoard from '../checkerboard';

export default class Stage {
    private renderer:THREE.WebGLRenderer;
    private scene:THREE.Scene;
    private camera:THREE.PerspectiveCamera;
    private changedPlanes: ChangedPlanes;
    private checkerBoard: CheckerBoard;
    constructor(canvas:HTMLCanvasElement){
        this.renderer = new THREE.WebGLRenderer({canvas,antialias:true,preserveDrawingBuffer:true});
        this.renderer.setClearColor( 0x6a6a6a, 1 )
        this.renderer.outputColorSpace = "";
        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera(75,canvas.width / canvas.height,0.1,1000);
        this.camera.position.set(0,0,10);
        this.camera.lookAt(0,0,-1);
        this.scene.add(this.camera);
        const directionalLight = new THREE.DirectionalLight(0xffffff,0.75);
        this.scene.add(directionalLight);
        const ambientLight = new THREE.AmbientLight(0xffffff,0.75);
        this.scene.add(ambientLight);

        Global.camera = this.camera;
        Global.renderer = this.renderer;
        Global.scene = this.scene;

        // this.changedPlanes = new ChangedPlanes();
        // this.changedPlanes.position.set(0,2,0);
        // this.scene.add(this.changedPlanes);
        this.checkerBoard = new CheckerBoard();
        this.scene.add(this.checkerBoard);

    }
    public start(){
        this.renderer.setAnimationLoop(this.render.bind(this))
    }
    private render(){
        // this.changedPlanes.update();
        Global.updateCallBacks();
        this.renderer.render(this.scene,this.camera);
    }
}

ChangedPlanes.ts

import * as THREE from 'three';

export default class ChangedPlanes extends THREE.Group {
  private startColor: THREE.Color;
  private endColor: THREE.Color;
  private currentTime: number;
  private duration: number;
  private shaderMesh: THREE.Mesh<THREE.PlaneGeometry, THREE.ShaderMaterial>;
  private basicMesh: THREE.Mesh<THREE.PlaneGeometry,THREE.MeshBasicMaterial>;
  private shaderStartFlag: boolean;
  private useColor=new THREE.Color();
  constructor() {
    super();
    this.startColor = new THREE.Color(0xffffff);
    this.endColor = new THREE.Color(0xff0000);
    this.currentTime = Date.now();
    this.duration = 1000;
    this.shaderStartFlag = false;

    const geometry = new THREE.PlaneGeometry(1, 1);
    const basicMaterial = new THREE.MeshBasicMaterial({color:this.startColor});
    this.basicMesh = new THREE.Mesh(geometry,basicMaterial);
    this.basicMesh.position.set(-1,0,0);
    this.add(this.basicMesh);

    const shaderMaterial = new THREE.ShaderMaterial({
        uniforms:{
            'color' : { value : this.startColor }
        },
        vertexShader:
            `
            void main(){
                gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
            }`,
        fragmentShader:
            `
            uniform vec3 color;
            
            void main(){
                gl_FragColor = vec4(color, 1.0);
            }`
    })
    this.shaderMesh = new THREE.Mesh(geometry, shaderMaterial);
    this.shaderMesh.position.set(1, 0, 0);
    this.add(this.shaderMesh)
  }
  public update(): void {
    const elapsed = Date.now() - this.currentTime;
    const progress = elapsed/this.duration % 1;
    this.useColor.copy(this.startColor).lerp(this.endColor,progress);
    this.basicMesh.material.color= this.useColor;
    if(this.shaderStartFlag){
      this.shaderMesh.material.uniforms.color.value = this.useColor;
    }
    this.shaderStartFlag= elapsed >= this.duration;
  } 
}