效果:
代码:
<template>
<div>
<el-container>
<el-main>
<div class="box-card-left">
<div id="threejs" style="border: 1px solid red"></div>
<div class="box-right" style="text-align: left; padding: 10px">
<div style="text-align: left">标准设备坐标系:</div>
<div>
three.js Canvas
画布具有一个标准设备坐标系,该坐标系的坐标原点是在canvas画布的中间位置,x轴水平向右,y轴竖直向上,标准设备坐标系的坐标值不是绝对值,
是相对值,范围是[-1,1],
也就是说canvas画布上任何一个位置的坐标,如果用标准设备坐标取衡量,那么坐标的所有值都在-1
和 1之间;
</div>
<div style="text-align: left; margin-top: 10px">
屏幕坐标转为 标准设备坐标:
</div>
<div style="text-align: left">
<pre>
// 坐标转化公式
addEventListener('click',function(event){
const px = event.offsetX;
const py = event.offsetY;
//屏幕坐标px、py转标准设备坐标x、y
//width、height表示canvas画布宽高度
const x = (px / width) * 2 - 1;
const y = -(py / height) * 2 + 1;
})
</pre>
</div>
</div>
</div>
</el-main>
</el-container>
</div>
</template>
<script>
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
// 效果制作器
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
// 渲染通道
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
// 发光描边OutlinePass
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";
export default {
data() {
return {
name: "",
scene: null,
camera: null,
renderer: null,
effectComposer: null,
mesh: null,
geometry: null,
group: null,
material: null,
texture: null,
position: null,
outlinePass: null,
canvasWidth: 1000,
canvasHeight: 800,
color: [],
meshArr: [],
};
},
created() {},
mounted() {
this.name = this.$route.query.name;
const numbers = Array.from({ length: 255 }, (_, i) => i);
// const uppercaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
this.color = [...numbers];
this.init();
},
methods: {
goBack() {
this.$router.go(-1);
},
addEventListenerFn() {
// canvas画布添加监听事件
document.getElementById("threejs").addEventListener("click", (event) => {
// 1,坐标转换
const point_x = event.offsetX; // 获取x方向当前点击点距离原点的距离;向右为正(原点是当前元素的左上角点)
const point_y = event.offsetY; // 获取y方向当前点击点距离原点的距离;向下为正(原点是当前元素的左上角点)
const x = (point_x / this.canvasWidth) * 2 - 1;
const y = -(point_y / this.canvasHeight) * 2 + 1;
// 2,创建射线投射器对象,
const raycaster = new this.$three.Raycaster();
// 3,射线计算,(参数是鼠标点击位置,相机参数)
raycaster.setFromCamera(new this.$three.Vector2(x, y), this.camera);
// 4,射线交叉计算
// const mesh_arr = []
// if(!this.scene)return;
// this.scene.traverse(m => {
// console.log('m',m);
// if(m.isMesh != undefined && m.isMesh) {
// mesh_arr.push(m);
// }
// })
const intersects = raycaster.intersectObjects(this.meshArr);
if (intersects.length > 0) {
if (this.effectComposer) {
// intersects[0].object.material.color.set(0xff0000);
this.outlinePass.selectedObjects = [intersects[0].object];
this.renderFun();
}
}
});
},
// 随机颜色
randomColor() {
// 要生成min-max之间的随机数,公式为:Math.random()*(max-min+1)+min
let i = Math.floor(Math.random() * (this.color.length - 0 + 1) + 0);
let j = Math.floor(Math.random() * (this.color.length - 0 + 1) + 0);
let k = Math.floor(Math.random() * (this.color.length - 0 + 1) + 0);
this.position = new this.$three.Vector3(i, j, k);
return new this.$three.Color(
"rgb(" +
this.color[i] +
", " +
this.color[j] +
", " +
this.color[k] +
")"
);
},
init() {
// 创建场景对象
this.scene = new this.$three.Scene();
// 创建立方缓存几何体对象
for (let i = 0; i < 3; i++) {
this.boxGeometry();
}
// 创建辅助坐标轴对象
const axesHelper = new this.$three.AxesHelper(200);
this.scene.add(axesHelper);
// 创建正交投影相机对象
// this.camera = new this.$three.PerspectiveCamera(60,1,0.01,1000);
// this.camera.position.set(600,600,600);
// this.camera.lookAt(0,0,0);
// 创建透视投影相机对象
this.camera = new this.$three.OrthographicCamera(
-500,
500,
400,
-400,
0,
1000
);
this.camera.position.set(200, 200, 200);
this.camera.lookAt(0, 0, 0);
// const helper = new this.$three.CameraHelper( this.camera );
// this.scene.add( helper );
// 创建渲染器对象
this.renderer = new this.$three.WebGLRenderer();
this.renderer.setSize(this.canvasWidth, this.canvasHeight);
this.renderer.render(this.scene, this.camera);
window.document
.getElementById("threejs")
.appendChild(this.renderer.domElement);
// 创建相机空间轨道控制器
const controls = new OrbitControls(this.camera, this.renderer.domElement);
controls.addEventListener("change", () => {
// this.renderer.render(this.scene, this.camera);
this.effectComposer.render();
});
// 调用后处理方法
this.effectComposerFn();
// 调用 监听 点击事件的方法
this.addEventListenerFn();
},
// 创建盒模型的方法
boxGeometry() {
// 创建网格基础材质对象
const material = new this.$three.MeshBasicMaterial({
color: this.randomColor(),
});
// 创建立方几何体对象
const geometry = new this.$three.BoxGeometry(
this.position.x,
this.position.y,
this.position.z
);
// 创建网格模型对象
const mesh = new this.$three.Mesh(geometry, material);
if (this.position) {
// 网格模型设置位置
mesh.position.set(this.position.x, this.position.y, this.position.z);
}
this.meshArr.push(mesh);
this.scene.add(mesh);
},
// 后处理方法
effectComposerFn() {
// 创建后处理对象
this.effectComposer = new EffectComposer(this.renderer);
// 创建后处理渲染器通道对象
const renderPass = new RenderPass(this.scene, this.camera);
// 后处理对象 添加渲染器通道
this.effectComposer.addPass(renderPass);
// 创建发光描边对象
this.outlinePass = new OutlinePass(
new this.$three.Vector2(this.canvasWidth, this.canvasHeight),
this.scene,
this.camera
);
// 设置发光描边颜色
this.outlinePass.visibleEdgeColor.set(0xE0F409);
// 设置发光描边厚度
this.outlinePass.edgeThickness = 5;
// 描边亮度
this.outlinePass.edgeStrength = 20;
// 设置发光描边频率
this.outlinePass.pulsePeriod = 2;
this.effectComposer.addPass(this.outlinePass);
},
renderFun() {
// 调用后处理对象的render方法进行渲染,
this.effectComposer.render();
window.requestAnimationFrame(this.renderFun);
},
},
};
</script>
//
<style lang="less" scoped>
.box-card-left {
display: flex;
align-items: flex-start;
flex-direction: row;
width: 100%;
.box-right {
}
}
</style>