持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情
写在前面
本文用vue+threejs写物体事件:滑过事件,监听鼠标滑过物体的事件。
鼠标滑过物品时对物品进行勾边操作。
下面是演示gif:
代码说明
- html
用于插入渲染器dom节点
<template>
<div class="item">
<div id="THREE63"></div>
</div>
</template>
- 引入threejs
引入threejs模块,引入轨道控制器OrbitControls,用于鼠标控制界面,引入后期处理EffectComposer,用于进行后期处理操作,RenderPass用于渲染,OutlinePass用于勾边
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.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";
- vue的mounted方法
在mounted方法中引入initThreejs方法
mounted() {
this.initThreejs();
},
- initThreejs方法全部代码和思路说明
思路说明:
- 相机
camera、场景scene、渲染器renderer的定义和创建 - 灯光
light、轨道控制器controls、地面ground、物体(redMesh、greenMesh、blueMesh)的创建 - 光线投射的使用
raycaster = new THREE.Raycaster();,并且将物体添加到响应光线投射的数组中objects.push(redMesh, greenMesh, blueMesh); - 后期处理的引入和使用
- 添加鼠标滑过事件
document.addEventListener("mousemove", onMouseMove);,鼠标有滑过物体就进行勾边操作outlinePass.selectedObjects = [intersect.object];,没有滑过物体就不进行勾边操作outlinePass.selectedObjects = []; - 最后使用后期处理渲染
composer.render();
initThreejs() {
let camera, scene, renderer;
let composer, outlinePass;
let raycaster, // 光线投射,用于鼠标拾取,返回鼠标在的位置的物体
pointer, // 二维向量,用于存放鼠标位置
objects = []; // 用于存放响应鼠标拾取的对象
init();
function init() {
// 创建场景
scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000); // 设置场景背景颜色
// 创建灯光
const light = new THREE.DirectionalLight(0xffffff); // 平行光
light.position.set(0.5, 1.0, 0.5).normalize(); // 设置平行光的方向,从(0.5, 1.0, 0.5)->target一般(0, 0, 0)
scene.add(light); // 将灯光添加到场景中
// 创建相机
camera = new THREE.PerspectiveCamera(
35,
(window.innerWidth - 201) / window.innerHeight,
1,
500
); // 透视相机
camera.position.x = 36;
camera.position.y = 67; // 设置相机的位置
camera.position.z = 67;
scene.add(camera); // 将相机添加到场景中
// 创建渲染器
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth - 201, window.innerHeight);
document.getElementById("THREE63").appendChild(renderer.domElement);
// 光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体),返回值就是鼠标在的物体的集合
raycaster = new THREE.Raycaster();
pointer = new THREE.Vector2(); // 定义一个二维向量
document.addEventListener("mousemove", onMouseMove);
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.addEventListener("change", render);
controls.update();
// 创建地面
const ground = new THREE.Mesh(
new THREE.BoxGeometry(50, 0.15, 50),
new THREE.MeshPhongMaterial({
color: 0x999999,
depthWrite: false,
transparent: true,
opacity: 1,
})
);
ground.receiveShadow = true;
scene.add(ground);
/**
* 后期处理
* OutlinePass就是勾边功能的主要模块
* 这在文章:用vue+threejs写物体效果:勾边中进行了详细说明,这里就不展开了
*/
composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
outlinePass = new OutlinePass(
new THREE.Vector2(window.innerWidth - 201, window.innerHeight),
scene,
camera
);
outlinePass.visibleEdgeColor.set(new THREE.Color(0xffff00));
outlinePass.edgeStrength = 3;
outlinePass.edgeThickness = 1;
composer.addPass(outlinePass);
// 创建红色立方体
let redMesh = new THREE.Mesh(
new THREE.BoxGeometry(2, 2, 2),
new THREE.MeshBasicMaterial({ color: 0xff0000 })
); // 网格模型
redMesh.position.y = 1;
scene.add(redMesh); // 将这个立方体添加到场景中
// 创建绿色立方体
let greenMesh = new THREE.Mesh(
new THREE.BoxGeometry(2, 2, 2),
new THREE.MeshBasicMaterial({ color: 0x00ff00 })
); // 网格模型
greenMesh.position.y = 1;
greenMesh.position.x = 5;
scene.add(greenMesh); // 将这个立方体添加到场景中
// 创建蓝色立方体
let blueMesh = new THREE.Mesh(
new THREE.BoxGeometry(2, 2, 2),
new THREE.MeshBasicMaterial({ color: 0x0000ff })
); // 网格模型
blueMesh.position.y = 1;
blueMesh.position.x = 6;
blueMesh.position.z = 9;
scene.add(blueMesh); // 将这个立方体添加到场景中
objects.push(redMesh, greenMesh, blueMesh);
render();
}
function onMouseMove(event) {
pointer.set(
(event.offsetX / (window.innerWidth - 201)) * 2 - 1,
-(event.offsetY / window.innerHeight) * 2 + 1
); // 将鼠标位置归一化为设备坐标 x 和 y 方向的取值范围是 (-1 to +1)
raycaster.setFromCamera(pointer, camera); // 通过相机和鼠标位置更新射线
const intersects = raycaster.intersectObjects(objects, false); // 获取光线投射的对象
if (intersects.length > 0) {
const intersect = intersects[0];
outlinePass.selectedObjects = [intersect.object]; // 第一个对象加上边框
} else {
outlinePass.selectedObjects = []; // 没有滑过的对象就置为空
}
render();
}
function render() {
composer.render();
}
},
写在最后
以上就是所有的代码和说明。