如何无需Raycaster在Three.js对象上放置Decal?
无需Raycaster手动放置Three.js Decal贴纸
你不需要Raycaster也能轻松在模型上固定Decal,核心是明确DecalGeometry的位置参数是世界空间坐标,同时给贴纸设置贴合目标表面的旋转角度。以下是具体实现方法和修改后的代码:
核心思路
- 确定贴纸在目标网格局部空间的位置(比如盒子的正面、顶部、侧面中心)
- 将局部坐标转换为世界空间坐标(适配网格的位移、旋转)
- 设置贴纸的旋转角度,让它完全贴合目标表面
修改后的代码示例
import * as THREE from "three"; import { DecalGeometry } from "three/examples/jsm/geometries/DecalGeometry"; // Renderer const renderer = new THREE.WebGLRenderer(); document.body.appendChild(renderer.domElement); const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(); camera.position.z = 10; // 目标网格(带旋转,模拟复杂场景) const geometry = new THREE.BoxGeometry(2, 2, 2); const material = new THREE.MeshStandardMaterial({ color: "lightblue", flatShading: true }); const mesh = new THREE.Mesh(geometry, material); mesh.rotation.y = Math.PI/4; // 给网格加个旋转,测试坐标转换 scene.add(mesh); // 函数:创建并添加Decal function createDecal(localPos, rotation, size, color) { // 把局部坐标转成世界坐标(适配网格的位移、旋转) const worldPos = mesh.localToWorld(localPos.clone()); const decalGeometry = new DecalGeometry( mesh, worldPos, rotation, size ); const decalMaterial = new THREE.MeshStandardMaterial({ color, polygonOffset: true, polygonOffsetFactor: -4, transparent: true // 可选:如果用带透明的贴图需要开启 }); const decal = new THREE.Mesh(decalGeometry, decalMaterial); scene.add(decal); } // 放置多个Decal示例 // 1. 正面(局部z=1,贴合z轴方向) createDecal( new THREE.Vector3(0, 0, 1), new THREE.Euler(0, 0, 0), new THREE.Vector3(1, 1, 1), "pink" ); // 2. 顶部(局部y=1,旋转-90度贴合顶面) createDecal( new THREE.Vector3(0, 1, 0), new THREE.Euler(-Math.PI/2, 0, 0), new THREE.Vector3(1, 1, 1), "yellow" ); // 3. 右侧(局部x=1,旋转90度贴合右侧面) createDecal( new THREE.Vector3(1, 0, 0), new THREE.Euler(0, Math.PI/2, 0), new THREE.Vector3(1, 1, 1), "cyan" ); // Light const dlight = new THREE.DirectionalLight(); dlight.position.z = 10; scene.add(dlight); // Resize function resize() { const width = document.documentElement.clientWidth; const height = window.innerHeight; camera.aspect = width / height; camera.updateProjectionMatrix(); renderer.setPixelRatio(Math.min(2, devicePixelRatio)); renderer.setSize(width, height); } window.addEventListener("resize", resize); resize(); // Tick function tick(t) { requestAnimationFrame(tick); mesh.rotation.y = t * 0.001; renderer.render(scene, camera); } requestAnimationFrame(tick);
关键细节说明
mesh.localToWorld(localPos.clone()):必须用clone(),否则会修改原局部坐标向量- 旋转角度的设置:根据目标表面的法向量调整Euler角,比如顶面的法向量是y轴正方向,所以需要把贴纸绕x轴旋转-90度,让贴纸正面朝向y轴正方向
polygonOffset参数:避免贴纸和目标网格的Z轴冲突,防止闪烁
内容的提问来源于stack exchange,提问作者imfbnt
相关产品推荐
相关产品推荐

