threejs 选中模型生成精灵图

threejs 选中模型生成精灵图


例子

(简易版)
请添加图片描述

场景选中生成精灵图(例子是在三维场景内)


代码

当作工具类放入代码段,直接可用

import THREE from 'three';
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const clickPosition = new THREE.Vector2();

class modelPicking {
 _CAMERA;
 dom; // 场景视图

 constructor(domElement, camera) {
   this.dom = domElement;
   this._CAMERA = camera;
 }

 // 射线
 collectHandle(event, objects, edge = true) {
   const array = this.getEdgePosition(this.dom, event.clientX, event.clientY);
   clickPosition.fromArray(array);
   let raycasterIntersects = this.getIntersects(clickPosition);
   return raycasterIntersects.intersectObjects(objects, edge);
 }

 // 射线适应
 getEdgePosition(dom, x, y) {
   // 环境判断包围盒的边距(简单规避射线不准确)
   const rect = dom.getBoundingClientRect();
   return [(x - rect.left) / rect.width, (y - rect.top) / rect.height];
 }

 // 射线判定
 getIntersects(point) {
   mouse.set(point.x * 2 - 1, -(point.y * 2) + 1);
   raycaster.setFromCamera(mouse, this._CAMERA);
   return raycaster;
 }

 /**
  * param : {width,height,value,image}
  * 简易生成canvas文字图片 当作贴图放置到精灵图(有特殊需求自行设计)
  */
 showMaterial(param) {
   let { width, height, value, image } = param;
   let canvas = document.createElement('canvas');
   let ctx = canvas.getContext('2d');
   canvas.width = width;
   canvas.height = height;
   ctx.fillStyle = 'rgba(0, 0, 0,1)';
   if (image) {
     ctx.drawImage(image, 0, 0, width, height);
   }
   //设置文字 
   if (value) {
     value.forEach((val) => {
       ctx.fillStyle = val.color ? val.color : '#fff';
       val.font && (ctx.font = val.font)
       ctx.fillText(val.textbox, val.coordX, val.coordY);
     })
   }
   let url = canvas.toDataURL('image/png');
   return url
 }
 /**
  * coordBox : {x,y,z}
  */
 createSprite(coordBox, url = './') {
   let { x, y, z } = coordBox;
   var spriteMaterial = new THREE.SpriteMaterial({
     map: new THREE.TextureLoader().load(url), //设置精灵纹理贴图
     transparent: true, //开启透明(纹理图片png有透明信息)
   });
   // 创建精灵模型对象,不需要几何体geometry参数
   var sprite = new THREE.Sprite(spriteMaterial);
   // 这里是为了配合点击模型 生成精灵图到模型位置
   sprite.position.set(x, y + 2, z);
   return sprite
 }
}

export default modelPicking;

调用工具类

let camera;// 假设是相机
let dom; //假设是场景载体
let pickingTool = modelPicking(dom ,camera);
// 点击事件
onClickModel(event){
	//scene.children = 你想射线判定的模型列表
	const intersects = pickingTool.collectHandle(event,scene.children);
	//根据需求判定
	if(intersects){
		let targetWorld = new THREE.Vector3();
    	intersects[0].object.getWorldPosition(targetWorld);
    	let textValue = [ 
      			{ textbox: "测试文字1", coordX: 20, coordY: 50,font:'100 24px Arial',color:'#47F4FF' },
      			{ textbox: "我是文字", coordX: 20, coordY: 80,font:'100 14px Arial',color:'#DFF0FF' }, 
    	]; 
   		let param = {
	      value: textValue,
	      width: 200,
	      height: 200, 
	      image: 'https://img-blog.csdnimg.cn/2d39572277b24ac78455d15f69589cc4.png'//图片路径
	    }; 
	    let canvasImg = pickingTool.showMaterial(param);
	    let sprite = pickingTool.createSprite(targetWorld,canvasImg.toDataURL('image/png'));
	    scene.add(sprite);
	}
}

射线简单理解

请添加图片描述
以平面来说x,y轴 ,选中某一个物体(比如正方形)只需要计算该点是否属于范围内
请添加图片描述
傻瓜式理解,吧三维场景脑补成 平面。射线换算成点。
请添加图片描述

分享

注:比较实用的小技巧之一,开始一件事可以把它想简单一些,以简单的思维去创建一个dom。和想要的效果有那么一点点挂钩的时候再去考虑如何扩展及丰富后续。(万事开头难,想半天头绪。也许可以试试实现一个简单的)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值