onMouseClick()方法实现射线拾取
创建模型的时候可以将mesh的group特别提出来
gltf.scene.traverse((child) => {
if (child.isGroup) {
child.name = 'dikuai'
this.groups.push(child);
}
});
下面是完整代码👇👇
<template>
<div class="main-3d">
<div id="scene-container" ref="sceneContainer"></div>
<div class="tool-box">
<div class="tool-site flexC" @click="show">隐身</div>
<div class="tool-site flexC" @click="isRotate=!isRotate">旋转</div>
</div>
</div>
</template>
<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
export default {
name: 'HelloWorld',
data () {
return {
container: null,
scene: null,
camera: null,
controls: null,
renderer: null,
stats: null,
models:null,
isRotate:false,
groups:[]
}
},
methods: {
onMouseClick() {
let that = this;
debugger
function onMouseClick(event) {
let a = document.getElementsByTagName("canvas")
var canvas
for(let i of a){
if(i.parentElement&&i.parentElement.id&&i.parentElement.id =="scene-container"){
canvas = i
}
}
let x =
((event.clientX - canvas.getBoundingClientRect().left) /
canvas.offsetWidth) *
2 -
1; // 标准设备横坐标
// 这里的mainCanvas是个dom元素,getBoundingClientRectangle会返回当前元素的视口大小.
let y =
-(
(event.clientY - canvas.getBoundingClientRect().top) /
canvas.offsetHeight
) *
2 +
1; // 标准设备纵坐标
let standardVector = new THREE.Vector3(x, y, 1); // 标准设备坐标
// 标准设备坐标转世界坐标
let worldVector = standardVector.unproject(that.camera);
// 射线投射方向单位向量(worldVector坐标减相机位置坐标)
let ray = worldVector.sub(that.camera.position).normalize();
// 创建射线投射器对象
let raycaster = new THREE.Raycaster(that.camera.position, ray);
// 获取raycaster直线和所有模型相交的数组集合
var intersects = raycaster.intersectObjects(that.scene.children, true);
if (intersects.length > 0) {
console.log(1);
}
}
//这个地方一定用renderer.domElement千万别用window!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!坑
that.renderer.domElement.addEventListener("click", onMouseClick, false);
},
show(){
},
hide(){
let a = this.groups.find( item => item.name=='dikuai')
a.children.forEach(element => {
element.material.transparent = true
element.material.opacity = 0
});
},
init () {
// set container
this.container = this.$refs.sceneContainer
// add stats
// add camera
const fov = 60 // Field of view
const aspect = this.container.clientWidth / this.container.clientHeight
const near = 20 // the near clipping plane
const far = 300 // the far clipping plane
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far)
camera.position.set(0, 50, 100)
this.camera = camera
// create scene
this.scene = new THREE.Scene()
this.scene.background = new THREE.Color('skyblue')
var hemiLight = new THREE.HemisphereLight( 0xffff55, 0x00ffff, 0.6 );
hemiLight.position.set(0,-100,0)
var helper = new THREE.HemisphereLightHelper( hemiLight, 5 );
this.scene.add( helper );
const mainLight = new THREE.DirectionalLight(0xffffff, 4.0)
mainLight.position.set(10, 50, 10)
this.scene.add(mainLight,hemiLight)
const mainLight2 = new THREE.DirectionalLight(0xffffff, 4.0)
mainLight2.position.set(-10, -50, -10)
this.scene.add(mainLight2,hemiLight)
// add controls
this.controls = new OrbitControls(this.camera, this.container)
// create renderer
this.renderer = new THREE.WebGLRenderer({ antialias: true })
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight)
this.renderer.setPixelRatio(window.devicePixelRatio)
this.renderer.gammaFactor = 2.2
this.renderer.outputEncoding = THREE.sRGBEncoding
this.renderer.physicallyCorrectLights = true
this.container.appendChild(this.renderer.domElement)
// set aspect ratio to match the new browser window aspect ratio
this.camera.aspect = this.container.clientWidth / this.container.clientHeight
this.camera.updateProjectionMatrix()
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight)
const loader = new GLTFLoader()
loader.load(
'/glb/aaa.glb',
gltf => {
debugger
this.models = gltf.scene
this.scene.add(this.models)
gltf.scene.traverse((child) => {
if (child.isGroup) {
child.name = 'dikuai'
this.groups.push(child);
}
});
console.log(this.groups);
},
undefined,
undefined
)
this.renderer.setAnimationLoop(() => {
this.rotate()
this.render()
})
},
render () {
this.renderer.render(this.scene, this.camera)
},
rotate() {
if(!this.isRotate){return false}
// this.models.rotation.z += 0.01;
// this.models.rotation.x += 0.01;
// this.models.rotation.y += 0.01;
this.models.rotateY(0.01);
}
},
mounted () {
this.init()
this.onMouseClick()
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.main-3d{
width: 100%;
height: 100%;
.tool-box{
position: fixed;
bottom: 10px;
right: 10px;
.tool-site{
width: 48px;
height: 36px;
background: red;
cursor: pointer;
}
}
}
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
#scene-container {
height: 100%;
}
</style>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。