记录一下学习three.js历程,我用的全是class,这里配置一下基础的class文件,由于目前也在学习ts就用了ts了
文件目录大概如下:common中写基础的配置,objects中写具体实例, scene中写具体逻辑创建调用
Base.ts
import { Scene } from "three"
export default class Base {
instance:any
constructor(){}
// 修改位置
setPosition (x:number,y:number,z:number) {
this.instance.position.set(x,y,z)
}
// 修改旋转
setRotation (x:number,y:number,z:number) {
this.instance.rotation.x = x
this.instance.rotation.y = y
this.instance.rotation.z = z
}
// 修改缩放
setScale (x:number,y:number,z:number) {
this.instance.scale.set(x,y,z); //缩放
}
// 修改名称
setName (name:string) {
this.instance.name = name; // 命名
}
// 添加到scene
addToScene (scene:Scene) {
scene.add(this.instance)
}
}
Template.ts
import {Scene, PerspectiveCamera, WebGLRenderer, Vector3, Color,
Vector2, AmbientLight, DirectionalLight, AxesHelper, Mesh, Raycaster,GridHelper
} from 'three'
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
import { CSS3DRenderer } from "three/examples/jsm/renderers/CSS3DRenderer.js";
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js"
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js"
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js"
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js"
import { FXAAShader } from "three/examples/jsm/shaders/FXAAShader.js"
interface PCamera{
fov:number
aspect:number
near:number
far:number
}
export default class Template {
scene: Scene = new Scene()
camera?: PerspectiveCamera
renderer?: WebGLRenderer
sceneBox: Scene = new Scene()
renderBox?: CSS3DRenderer
axesHelper?:AxesHelper
gridHelper?:GridHelper
ele:any = null
PCamera:PCamera = {
fov: 45,
aspect: 0,
near: 1,
far: 1000
}
cameraPostion:Vector3 = new Vector3(0, 0, 0)
cameraLookAt:Vector3 = new Vector3(0,0,0)
rendererColor:Color = new Color(0x000000)
rendererWidth:number = 0
rendererHeight:number = 0
intersects:any = []
meshList:any = []
composer?:EffectComposer
outlinePass?:OutlinePass
renderPass?:RenderPass
constructor () {
}
// 初始化scene
init <T>(ele:T) {
this.ele = ele
this.PCamera.aspect = this.ele.offsetWidth / this.ele.offsetHeight
this.rendererWidth = this.ele.offsetWidth
this.rendererHeight = this.ele.offsetHeight
this.initPerspectiveCamera()
this.initRenderer()
}
// 初始化弹窗scene
initBox () {
this.sceneBox = new Scene();
const renderBox = new CSS3DRenderer();
renderBox.setSize(this.rendererWidth, this.rendererHeight);
renderBox.domElement.style.position = "absolute";
renderBox.domElement.style.top = '0';
this.ele.appendChild(renderBox.domElement);
this.renderBox = renderBox
}
// 初始化相机
initPerspectiveCamera () {
const camera = new PerspectiveCamera(
this.PCamera.fov,
this.PCamera.aspect,
this.PCamera.near,
this.PCamera.far
)
camera.position.copy(this.cameraPostion)
camera.lookAt(this.cameraLookAt)
this.camera = camera
this.scene.add(camera)
}
// 初始化render
initRenderer () {
const renderer = new WebGLRenderer({
antialias: true
})
renderer.setClearColor(this.rendererColor)
renderer.setSize(this.rendererWidth, this.rendererHeight)
this.ele.appendChild(renderer.domElement)
this.renderer = renderer
}
// 添加光照
addAmbientLight (color:any) {
this.scene.add( new AmbientLight( color ) )
}
// 添加方向光照
addDirectionalLight (color:any,pos:{x:number,y:number,z:number},power?:number,castShadow?:boolean) {
const light = new DirectionalLight( color, power?power:1 )
light.position.set( pos.x, pos.y, pos.z )
light.castShadow = castShadow?castShadow:false
this.scene.add( light )
}
// 添加鼠标控制
addOrbitControls (camera:PerspectiveCamera, el:any) {
const controls = new OrbitControls( camera, el );
controls.maxPolarAngle = Math.PI * 0.45;
controls.enablePan = false
}
// 辅助坐标轴
addAxesHelper (num:number) {
this.axesHelper = new AxesHelper( num )
this.scene.add( this.axesHelper )
}
// 辅助网格
addGridHelper (w:number,h:number) {
this.gridHelper = new GridHelper( w,h )
this.scene.add( this.gridHelper )
}
// 高亮效果
outlineObj (selectedObjects:any) {
if(this.renderer && this.camera){
// 创建一个EffectComposer(效果组合器)对象,然后在该对象上添加后期处理通道。
this.composer = new EffectComposer(this.renderer)
// 新建一个场景通道 为了覆盖到原理来的场景上
this.renderPass = new RenderPass(this.scene, this.camera)
this.composer.addPass(this.renderPass);
// 物体边缘发光通道
this.outlinePass = new OutlinePass(new Vector2(this.ele.offsetWidth, this.ele.offsetHeight), this.scene, this.camera, selectedObjects)
this.outlinePass.selectedObjects = selectedObjects
this.outlinePass.edgeStrength = 10.0 // 边框的亮度
this.outlinePass.edgeGlow = 1// 光晕[0,1]
this.outlinePass.usePatternTexture = false // 是否使用父级的材质
this.outlinePass.edgeThickness = 1.0 // 边框宽度
this.outlinePass.downSampleRatio = 1 // 边框弯曲度
this.outlinePass.pulsePeriod = 5 // 呼吸闪烁的速度
this.outlinePass.visibleEdgeColor.set("#ffffff") // 呼吸显示的颜色
this.outlinePass.hiddenEdgeColor = new Color(0, 0, 0) // 呼吸消失的颜色
this.outlinePass.clear = true
this.composer.addPass(this.outlinePass)
// 自定义的着色器通道 作为参数
var effectFXAA = new ShaderPass(FXAAShader)
effectFXAA.uniforms.resolution.value.set(1 / this.ele.offsetWidth, 1 / this.ele.offsetHeight)
effectFXAA.renderToScreen = true
this.composer.addPass(effectFXAA)
}
}
// 鼠标点击
onMouseDown(callback:any){
// 监听鼠标点击
window.addEventListener('click', (event)=>{
if(this.camera){
let vector = new Vector3(
((event.clientX-this.ele.getBoundingClientRect().x) / this.ele.offsetWidth) * 2 - 1,
-((event.clientY-this.ele.getBoundingClientRect().y) / this.ele.offsetHeight) * 2 + 1,
0.5
)
vector = vector.unproject(this.camera)
const raycaster = new Raycaster(
this.camera.position,
vector.sub(this.camera.position).normalize()
)
this.intersects = raycaster.intersectObjects(this.meshList)
callback && callback()
}
})
}
}