v3+three.js触碰物体加载模型边缘高亮

官方文档示例
https://github.com/mrdoob/three.js/blob/master/examples/webgl_postprocessing_outline.html

<template>
  <div ref="threeRef"></div>
</template>

<script setup>
import {onMounted, ref} from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import {GLTFLoader} from "three/addons/loaders/GLTFLoader.js";
import {TransformControls} from "three/examples/jsm/controls/TransformControls.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"

let threeRef=ref()
const scene=new THREE.Scene()
scene.background=new THREE.Color('#2fa799')
const camera=new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000)
camera.position.y=200 // 40
camera.position.x=0
camera.position.z=100 // 30
// 相机朝向
camera.lookAt(scene.position)
// 坐标轴
const axes=new THREE.AxesHelper(50)
scene.add(axes)
// 渲染器
const renderer=new THREE.WebGLRenderer({antialias:true})
renderer.setSize(window.innerWidth,window.innerHeight)
renderer.render( scene, camera );
renderer.outputEncoding=THREE.sRGBEncoding
// 监听窗口变化
window.addEventListener('resize',()=>{
  camera.aspect=window.innerWidth/window.innerHeight
  camera.updateProjectionMatrix()
  renderer.setSize(window.innerWidth,window.innerHeight)
},false)
// 相机
const controls=new OrbitControls(camera,renderer.domElement)
// 环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// 点光源
const pointLight = new THREE.PointLight(0xffffff, 0.5);
pointLight.position.set(0, 3, 0);
scene.add(pointLight);
// 初始射线发射器
const transformControls=new TransformControls(camera,renderer.domElement)
scene.add(transformControls)

let model
// 加载模型
const gltfloader = new GLTFLoader()
gltfloader.load('./dwendwen.gltf',event=>{
  model=event.scene
  model.scale.set(8*10,8*10,8*10)// 缩放
  model.translateZ(7*10)// 平移
  model.position.y=4*10// 位置
  model.rotateX(Math.PI/-4)// 旋转
  scene.add(model)
  model.traverse(child => {
    if (child.isMesh) {
      child.material.basicMaterial = child.material;
    }
  });
})


let outlinePass,
    renderPass
// 调用此方法传入数组
const outlineObj=(selectedObjects)=>{
  // 创建一个EffectComposer(效果组合器)对象,然后在该对象上添加后期处理通道。
  window.composer = new EffectComposer(renderer)
  // 新建一个场景通道  为了覆盖到原理来的场景上
  renderPass = new RenderPass(scene, camera)
  window.composer.addPass(renderPass);
  // 物体边缘发光通道
  outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera, selectedObjects)
  outlinePass.selectedObjects = selectedObjects
  outlinePass.edgeStrength = 10.0 // 边框的亮度
  outlinePass.edgeGlow = 1// 光晕[0,1]
  outlinePass.usePatternTexture = false // 是否使用父级的材质
  outlinePass.edgeThickness = 1.0 // 边框宽度
  outlinePass.downSampleRatio = 1 // 边框弯曲度
  outlinePass.pulsePeriod = 5 // 呼吸闪烁的速度
  outlinePass.visibleEdgeColor.set(parseInt(0x00ff00)) // 呼吸显示的颜色
  outlinePass.hiddenEdgeColor = new THREE.Color(222,222,222) // 呼吸消失的颜色,0,0,0
  outlinePass.clear = true
  window.composer.addPass(outlinePass)
  // 自定义的着色器通道 作为参数
  let effectFXAA = new ShaderPass(FXAAShader)
  effectFXAA.uniforms.resolution.value.set(1 / window.innerWidth, 1 / window.innerHeight)
  effectFXAA.renderToScreen = true
  window.composer.addPass(effectFXAA)
}

renderer.domElement.addEventListener('mousemove', function(event) {
  let mouse = new THREE.Vector2();
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  let raycaster = new THREE.Raycaster();
  raycaster.setFromCamera(mouse, camera);
  let intersects = raycaster.intersectObjects(scene.children, true);


  if (intersects.length > 0) {
    outlineObj([intersects[0].object])
  }

});


// 地图
{
  const planeSize = 30;
  const loader = new THREE.TextureLoader();
  const texture = loader.load('https://threejs.org/manual/examples/resources/images/checker.png');
  texture.wrapS = THREE.RepeatWrapping;
  texture.wrapT = THREE.RepeatWrapping;
  texture.magFilter = THREE.NearestFilter;
  const repeats = planeSize / 2;
  texture.repeat.set(repeats, repeats);
  const planeGeo = new THREE.PlaneGeometry(100, 100);
  const planeMat = new THREE.MeshPhongMaterial({
    map: texture,
    side: THREE.DoubleSide,
  });
  const mesh = new THREE.Mesh(planeGeo, planeMat);
  mesh.rotation.x = Math.PI * -.5;
  scene.add(mesh);
}
// 方块
{
  const pieceJ = new THREE.BoxGeometry(100, 40, 100)
  const pieceC = new THREE.MeshBasicMaterial({color: '#808080'})
  const pieceW = new THREE.Mesh(pieceJ, pieceC)
  pieceW.position.x = -25
  pieceW.position.y = -25
  pieceW.position.z = 50
  scene.add(pieceW)
}

const init=()=>{
  threeRef.value?.appendChild(renderer.domElement)
  controls.update()
  requestAnimationFrame(init)
  renderer.render( scene, camera );
  if (window.composer) {
    window.composer.render()
  }

}
onMounted(()=>{
  init()
})
</script>

<style scoped lang="less">

</style>

示例中composer挂到window上也会卡,慎用,有时间再研究叭

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值