题目:两个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;
}
}