nicenote/docs/fea/webgl/demo/earth.tsx
2023-11-03 10:03:49 +08:00

143 lines
3.6 KiB
TypeScript

import React, { useRef, useEffect } from 'react';
import * as THREE from 'three';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
import { resizeRendererToDisplaySize, addControls } from '../utils'
class AxisGridHelper {
axes: any;
grid: any;
_visible: any;
constructor( node, units = 10 ) {
const axes = new THREE.AxesHelper();
axes.material.depthTest = false;
axes.renderOrder = 2; // after the grid
node.add( axes );
const grid = new THREE.GridHelper( units, units );
grid.material.depthTest = false;
grid.renderOrder = 1;
node.add( grid );
this.grid = grid;
this.axes = axes;
this.visible = false;
}
get visible() {
return this._visible;
}
set visible( v ) {
this._visible = v;
this.grid.visible = v;
this.axes.visible = v;
}
}
export default () => {
const ref = useRef(null)
useEffect(() => {
ref.current && init(ref.current)
})
const init = (dom: any) => {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(40, 2, 0.1, 1000)
camera.position.set(0, 50, 0)
camera.up.set(0, 0, 1)
camera.lookAt(0, 0, 0)
const gui = new GUI();
{
const light = new THREE.PointLight(0xffffff, 500)
scene.add(light)
}
// 创建球体实例
const radius = 1
const widthSegments = 6
const heightSegments = 6
const sphereGeometry = new THREE.SphereGeometry(radius, widthSegments, heightSegments)
const objects = []
const solarSystem = new THREE.Object3D()
scene.add(solarSystem)
objects.push(solarSystem)
// 太阳
const sunMaterial = new THREE.MeshPhongMaterial({ emissive: 0xffff00 })
const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial)
sunMesh.scale.set(5, 5, 5)
solarSystem.add(sunMesh)
objects.push(sunMesh)
// 地球
const earthOrbit = new THREE.Object3D()
earthOrbit.position.x = 10;
solarSystem.add(earthOrbit)
objects.push(earthOrbit)
const earthMaterial = new THREE.MeshPhongMaterial({
color: 0x2233ff,
emissive: 0x112244,
})
const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial)
earthOrbit.add(earthMesh)
objects.push(earthMesh)
// 月球
const moonOrbit = new THREE.Object3D()
moonOrbit.position.x = 2
earthOrbit.add(moonOrbit)
const moonMaterial = new THREE.MeshPhongMaterial({
color: 0x888888,
emissive: 0x222222
})
const moonMesh = new THREE.Mesh(sphereGeometry, moonMaterial)
moonMesh.scale.set(.5, .5, .5);
moonOrbit.add(moonMesh)
objects.push(moonMesh)
// 渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true, canvas: dom });
// 集体旋转
function makeAxisGrid(node, label, units) {
const helper = new AxisGridHelper( node, units );
gui.add(helper, 'visible').name(label);
}
makeAxisGrid(solarSystem, 'solarSystem', 25);
makeAxisGrid(sunMesh, 'sunMesh');
makeAxisGrid(earthOrbit, 'earthOrbit');
makeAxisGrid(earthMesh, 'earthMesh');
makeAxisGrid(moonOrbit, 'moonOrbit');
makeAxisGrid(moonMesh, 'moonMesh');
addControls(camera, renderer);
function render(time) {
time *= 0.001
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
objects.forEach((obj) => {
obj.rotation.y = time
})
renderer.setAnimationLoop(render)
renderer.render(scene, camera)
}
renderer.setAnimationLoop(render)
}
return (
<canvas ref={ref} id="earth" style={{ width: '100%', height: '500px'}} />
)
}