threejs使用精灵Sprite模型给场景3D模型打标签实例

精灵图Sprite效果是不管场景如何旋转,标签总是对着屏幕,可以用作对模型打标记,显示模型信息作用

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="http://www.yanhuangxueyuan.com/3D/example/three.min.js"></script>
  <script src="./js/dat.gui.js"></script>
  <script src="./js/OrbitControls.js"></script>
  <script src="./js/makeTextSprite.js"></script>
  <title>sence</title>
  <style>
    *{margin:0;padding:0;}
    body{overflow:hidden;}
  </style>
</head>
<body>
</body>
<script>
  const FRESH_TIME = 3000; // 数据刷新时间
  // 创建场景
  let Scene = new THREE.Scene(); 

  // 创建相机
  let camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
  camera.position.x = -50;
  camera.position.y = 30;
  camera.position.z = 50;
  camera.lookAt(Scene.position);  // 视角

  // 创建渲染器
  let renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setClearColor(new THREE.Color(0x000000));
  renderer.shadowMap.enabled = true;
  document.body.appendChild(renderer.domElement);


  // 创建平面
  let planeGeometry = new THREE.PlaneGeometry(60, 60, 1, 1); // 平面网格
  let textureLoader = new THREE.TextureLoader();
  let texture = textureLoader.load('./img/3.jpg');
  var textureNormal = textureLoader.load('./img/3.jpg');
  // 加载高光贴图
  let planeMaterial = new THREE.MeshPhongMaterial({
    // specular: 0xff0000,//高光部分的颜色
    shininess: 30,//高光部分的亮度,默认30
    map: texture,// 普通纹理贴图
    roughness:0.3,
    lightMap:textureNormal,
    // normalMap: textureNormal, //法线贴图
    bumpScale: 3
  }); //材质对象Material

  

  // let planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
  let plane = new THREE.Mesh(planeGeometry, planeMaterial);
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.x = 0;
  plane.name = '平面物体ID=' + 1;
  plane.position.y = 0;
  plane.position.z = 0;
  plane.receiveShadow = true;
  Scene.add(plane);

  // 创建立方体
  let boxGeometry = new THREE.BoxGeometry(10, 10, 10, 200);
  let texture1 = textureLoader.load('./img/tim.jpg');
  let boxGeometryMaterial = new THREE.MeshLambertMaterial({
  // specular: 0xff0000,//高光部分的颜色
    shininess: 30,//高光部分的亮度,默认30
    normalScale: new THREE.Vector2(2.2, 2.2),
    map: texture1,// 普通纹理贴图
    normalMap: textureNormal, //法线贴图
    bumpMap: textureNormal,
    bumpScale: 0.3
  });
  let box = new THREE.Mesh(boxGeometry, boxGeometryMaterial);
  box.name = '正方物体ID=' + 2;
  box.position.x = 10;
  box.position.y = 5;
  box.position.z = 0;
  box.castShadow = true;
  Scene.add(box);

    // 点击事件
  let raycaster = new THREE.Raycaster();
  let mouse = new THREE.Vector2();
  // 点击了哪个模型
  function clickEvent () {
    if (event.target.tagName == 'CANVAS') {
      mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
      mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
      Scene.updateMatrixWorld(true);
      // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
      raycaster.setFromCamera(mouse, camera);
      // 获取raycaster直线和所有模型相交的数组集合
      let intersects = raycaster.intersectObjects(Scene.children, true);
      if (intersects[0]) {
        console.log(intersects[0]);
      }
    }
  }
  window.addEventListener('click', clickEvent, false);
  // 创建灯光

  // 点光源
  let spotLight = new THREE.SpotLight(0xffffff);
  spotLight.position.set(-60, 40, -20);
  spotLight.castShadow = true;
  Scene.add(spotLight);

  // 平行光
  let directionalLight = new THREE.DirectionalLight(0xffffff, 1);
  // 设置光源的方向:通过光源position属性和目标指向对象的position属性计算
  directionalLight.position.set(-90, 80, -20);
  // 方向光指向对象网格模型mesh2,可以不设置,默认的位置是0,0,0
  directionalLight.target = box;
  Scene.add(directionalLight);

  // 环境光
  let ambient = new THREE.AmbientLight(0x444444);
  Scene.add(ambient);//环境光对象添加到scene场景中

  let gui = {
    bump:0.03,
    animation:false
  };
  let datGui = new dat.GUI();
  //将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值)
  datGui.add(gui, "bump", -1, 1).onChange(function (e) {
    box.material.bumpScale = e;
  });
  datGui.add(gui, "animation");

  //创建控件对象
  let controls = new THREE.OrbitControls(camera,renderer.domElement);

  // 添加辅助坐标轴
  let axisHelper = new THREE.AxisHelper(250);
  Scene.add(axisHelper);

  // 清空雪碧图
  function clearSprite (type = 'Sprite') {
    const children = [];
    (Scene.children || []).forEach((v, idx) => {
      if (v.type !== type) {
        children.push(v);
      }
    });
    Scene.children = children;
  }

  // 循环数据,添加精灵标签
  function loopData () {
    clearSprite();
    (Scene.children || []).forEach((v, idx) => {
      if (v.type == 'Mesh') {
        const text = v.name + new Date().getTime();
        const color = new Date().getTime() % 2 == 1 ? 'rgba(234, 42, 6, 1)' : 'rgba(0, 0, 0, 1.0)'
        let sprite = makeTextSprite(text, {
          color: color
        });
        sprite.center = new THREE.Vector2(0, 0);
        Scene.add(sprite);
        sprite.position.set(v.position.x, v.position.y + 5, v.position.z);
      }
    });
  }

  const timeId = setInterval(_ => {
    loopData();
  }, FRESH_TIME);
  
  loopData();

  function render () {
    renderer.render(Scene, camera);
    requestAnimationFrame(render);
  }
  render();

</script>
</html>

makeTextSpritejs代码

/* 创建字体精灵 */
function makeTextSprite(message, parameters) {
  if (parameters === undefined) parameters = {}
  let fontface = parameters.hasOwnProperty("fontface") ?
    parameters["fontface"] : "Arial"
  /* 字体大小 */
  let fontsize = parameters.hasOwnProperty("fontsize") ?
    parameters["fontsize"] : 18

  let color = parameters.hasOwnProperty("color") ?
    parameters["color"]: 'rgba(0, 0, 0, 1.0)'
  /* 边框厚度 */
  let borderThickness = parameters.hasOwnProperty("borderThickness") ?
    parameters["borderThickness"] : 4
  /* 边框颜色 */
  let borderColor = parameters.hasOwnProperty("borderColor") ?
    parameters["borderColor"] : {
      r: 0,
      g: 0,
      b: 0,
      a: 1.0
    }
  /* 背景颜色 */
  let backgroundColor = parameters.hasOwnProperty("backgroundColor") ?
    parameters["backgroundColor"] : {
      r: 255,
      g: 255,
      b: 255,
      a: 1.0
    }
  /* 创建画布 */
  let canvas = document.createElement('canvas');
  let context = canvas.getContext('2d')
  /* 字体加粗 */
  context.font = "Bold " + fontsize + "px " + fontface
  /* 获取文字的大小数据,高度取决于文字的大小 */
  let metrics = context.measureText(message);
  let textWidth = metrics.width
  /* 背景颜色 */
  context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + "," +
    backgroundColor.b + "," + backgroundColor.a + ")"
  /* 边框的颜色 */
  context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + "," +
    borderColor.b + "," + borderColor.a + ")";
  context.lineWidth = borderThickness
  /* 绘制圆角矩形 */
  roundRect(context, borderThickness / 2, borderThickness / 2, textWidth + borderThickness, fontsize * 1.4 +
    borderThickness,
    6)
  /* 字体颜色 */
  context.fillStyle = color;
  context.fillText(message, borderThickness, fontsize + borderThickness)
  /* 画布内容用于纹理贴图 */
  let texture = new THREE.Texture(canvas);
  texture.needsUpdate = true
  let spriteMaterial = new THREE.SpriteMaterial({
    map: texture
  });
  let sprite = new THREE.Sprite(spriteMaterial)
  console.log(sprite.spriteMaterial)
  /* 缩放比例 */
  sprite.scale.set(10, 5, 0)
  return sprite
};

/* 绘制圆角矩形 */
function roundRect(ctx, x, y, w, h, r) {

  ctx.beginPath();
  ctx.moveTo(x + r, y);
  ctx.lineTo(x + w - r, y);
  ctx.quadraticCurveTo(x + w, y, x + w, y + r);
  ctx.lineTo(x + w, y + h - r);
  ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
  ctx.lineTo(x + r, y + h);
  ctx.quadraticCurveTo(x, y + h, x, y + h - r);
  ctx.lineTo(x, y + r);
  ctx.quadraticCurveTo(x, y, x + r, y);
  ctx.closePath();
  ctx.fill();
  ctx.stroke();

}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值