ThreeJS 官方案例学习(webgl_camera)
1.效果图

2.源码
<template>
<div>
<div id="container"></div>
</div>
</template>
<script>
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';
import Stats from 'three/examples/jsm/libs/stats.module.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
import gsap from 'gsap';
export default {
data() {
return {
container: null,
scene: null,
camera: null,
renderer: null,
controller: null,
stats: null,
mixer: null,
model: null,
cameraRig: null,
activeCamera: null,
activeHelper: null,
cameraPerspective: null,
cameraOrtho: null,
cameraPerspectiveHelper: null,
cameraOrthoHelper: null,
mesh: null,
frustumSize: 600,
clock: new THREE.Clock()
};
},
mounted() {
this.init()
this.animate()
window.addEventListener("resize", this.onWindowSize)
document.addEventListener('keydown', this.onKeyDown);
},
beforeUnmount() {
console.log('beforeUnmount===============');
this.container = null
this.scene = null
this.camera = null
this.renderer = null
this.controller = null
this.stats = null
this.mixer = null
this.model = null
},
methods: {
init() {
this.container = document.getElementById('container')
this.setScene()
this.setCamera()
this.setRenderer()
this.setController()
this.addHelper()
this.setPMREMGenerator()
this.setLight()
this.addStatus()
this.setMesh()
},
setScene() {
this.scene = new THREE.Scene()
},
setCamera() {
const aspect = this.container.clientWidth / this.container.clientHeight
this.camera = new THREE.PerspectiveCamera(50, 0.5 * aspect, 1, 10000)
this.camera.position.set(0, 0, 2500)
this.camera.aspect = aspect;
this.camera.updateProjectionMatrix();
this.camera.lookAt(new THREE.Vector3(0, 0, 0))
this.scene.add(this.camera)
this.cameraPerspective = new THREE.PerspectiveCamera(50, 0.5 * aspect, 150, 1000);
this.cameraPerspectiveHelper = new THREE.CameraHelper(this.cameraPerspective);
this.scene.add(this.cameraPerspectiveHelper);
this.cameraOrtho = new THREE.OrthographicCamera(0.5 * this.frustumSize * aspect / - 2, 0.5 * this.frustumSize * aspect / 2, this.frustumSize / 2, this.frustumSize / - 2, 150, 1000);
this.cameraOrthoHelper = new THREE.CameraHelper(this.cameraOrtho);
this.scene.add(this.cameraOrthoHelper);
this.activeCamera = this.cameraPerspective;
this.activeHelper = this.cameraPerspectiveHelper;
this.cameraOrtho.rotation.y = Math.PI;
this.cameraPerspective.rotation.y = Math.PI;
this.cameraRig = new THREE.Group();
this.cameraRig.add(this.cameraPerspective);
this.cameraRig.add(this.cameraOrtho);
this.scene.add(this.cameraRig);
},
setRenderer() {
this.renderer = new THREE.WebGLRenderer({
antialias: true,
logarithmicDepthBuffer: true,
})
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.autoClear = false;
this.container.appendChild(this.renderer.domElement);
},
setController() {
this.controller = new OrbitControls(this.camera, this.renderer.domElement);
this.controller.enableDamping = true;
this.controller.dampingFactor = 0.04;
this.controller.target.set(0, 0, 0);
},
setGltfLoader() {
let that = this
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("./draco/gltf/");
loader.setDRACOLoader(dracoLoader);
loader.load('./model/gltf/LittlestTokyo.glb', (gltf) => {
that.model = gltf.scene
that.model.position.set(1, 1, 0)
that.model.scale.set(0.01, 0.01, 0.01)
that.scene.add(that.model)
that.mixer = new THREE.AnimationMixer(that.model)
that.mixer.clipAction(gltf.animations[0]).play()
that.animate();
}, undefined, (err => {
console.error(err)
}))
},
addHelper() {
let helper = new THREE.CameraHelper(this.camera);
let axisHelper = new THREE.AxesHelper(150);
this.scene.add(axisHelper)
let gridHelper = new THREE.GridHelper(100, 30, 0x2C2C2C, 0x888888);
this.scene.add(gridHelper);
},
setPMREMGenerator() {
const pmremGenerator = new THREE.PMREMGenerator(this.renderer);
this.scene.environment = pmremGenerator.fromScene(new RoomEnvironment(this.renderer), 0.04).texture;
},
setLight() {
const ambientLight = new THREE.AmbientLight(0x404040, 4);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
this.scene.add(directionalLight);
const test = new THREE.PointLight("#ffffff", 10, 2);
const testHelperMap = new THREE.PointLightHelper(test);
},
addStatus() {
this.stats = new Stats();
this.container.appendChild(this.stats.dom);
},
setMesh() {
this.mesh = new THREE.Mesh(
new THREE.SphereGeometry(100, 16, 8),
new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true })
)
this.scene.add(this.mesh)
const mesh2 = new THREE.Mesh(
new THREE.SphereGeometry(50, 16, 8),
new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true })
)
mesh2.position.y = 150;
this.mesh.add(mesh2);
const mesh3 = new THREE.Mesh(
new THREE.SphereGeometry(5, 16, 8),
new THREE.MeshBasicMaterial({ color: 0x0000ff, wireframe: true })
)
mesh3.position.z = 150;
this.cameraRig.add(mesh3);
const geometry = new THREE.BufferGeometry();
const vertices = [];
const colorList = [];
for (let i = 0; i < 10000; i++) {
vertices.push(THREE.MathUtils.randFloatSpread(2000));
vertices.push(THREE.MathUtils.randFloatSpread(2000));
vertices.push(THREE.MathUtils.randFloatSpread(2000));
colorList.push(THREE.MathUtils.randInt(0, 1));
colorList.push(THREE.MathUtils.randInt(0, 1));
colorList.push(THREE.MathUtils.randInt(0, 1));
}
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colorList, 3));
const particles = new THREE.Points(
geometry,
new THREE.PointsMaterial({
size: 2,
}));
this.scene.add(particles);
},
onWindowSize() {
const aspect = this.container.clientWidth / this.container.clientHeight
this.camera.aspect = aspect;
this.camera.updateProjectionMatrix();
this.cameraPerspective.aspect = 0.5 * aspect;
this.cameraPerspective.updateProjectionMatrix();
this.cameraOrtho.left = - 0.5 * this.frustumSize * aspect / 2;
this.cameraOrtho.right = 0.5 * this.frustumSize * aspect / 2;
this.cameraOrtho.top = this.frustumSize / 2;
this.cameraOrtho.bottom = - this.frustumSize / 2;
this.cameraOrtho.updateProjectionMatrix();
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
this.renderer.setPixelRatio(window.devicePixelRatio)
},
animate() {
const delta = this.clock.getDelta();
if (this.mixer) {
this.mixer.update(delta);
}
requestAnimationFrame(this.animate);
this.render()
this.stats.update();
this.renderer.render(this.scene, this.camera);
},
render() {
const SCREEN_WIDTH = this.container.clientWidth
const SCREEN_HEIGHT = this.container.clientHeight
const r = Date.now() * 0.0005;
this.mesh.position.x = 700 * Math.cos(r);
this.mesh.position.z = 700 * Math.sin(r);
this.mesh.position.y = 700 * Math.sin(r);
this.mesh.children[0].position.x = 70 * Math.cos(2 * r);
this.mesh.children[0].position.z = 70 * Math.sin(r);
if (this.activeCamera === this.cameraPerspective) {
this.cameraPerspective.fov = 35 + 30 * Math.sin(0.5 * r);
this.cameraPerspective.far = this.mesh.position.length();
this.cameraPerspective.updateProjectionMatrix();
this.cameraPerspectiveHelper.update();
this.cameraPerspectiveHelper.visible = true;
this.cameraOrthoHelper.visible = false;
} else {
this.cameraOrtho.far = this.mesh.position.length();
this.cameraOrtho.updateProjectionMatrix();
this.cameraOrthoHelper.update();
this.cameraOrthoHelper.visible = true;
this.cameraPerspectiveHelper.visible = false;
}
this.cameraRig.lookAt(this.mesh.position);
this.renderer.clear();
this.activeHelper.visible = false;
this.renderer.setViewport(0, 0, SCREEN_WIDTH / 2, SCREEN_HEIGHT);
this.renderer.render(this.scene, this.activeCamera);
this.activeHelper.visible = true;
this.renderer.setViewport(SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2, SCREEN_HEIGHT);
this.renderer.render(this.scene, this.camera);
},
onKeyDown(event) {
switch (event.keyCode) {
case 79:
this.activeCamera = this.cameraOrtho;
this.activeHelper = this.cameraOrthoHelper;
break;
case 80:
this.activeCamera = this.cameraPerspective;
this.activeHelper = this.cameraPerspectiveHelper;
break;
}
},
},
};
</script>
<style>
#container {
position: absolute;
width: 100%;
height: 100%;
}
</style>