ThreeJS动态加载div标签

思路:
1.在页面中创建一个div标签;
2.确定标签在三维场景中的三维位置;
3.计算三维位置的屏幕坐标;
4.在每一帧的渲染中都计算一下这个三维坐标的屏幕位置,并把屏幕位置赋给标签。
具体实现:
1.创建div标签
标签样式:

  .tap{
            position: absolute;
            background-color: MidnightBlue;
            background-color:rgba(0,10,40);
            border-top-left-radius: 10px;
            border-bottom-right-radius:10px;
            opacity: 0.5;
            font-size: 4px;
            color: aqua;
            width: 36px;
            height: 44px;
            padding: 1px 1px 1px;
        }

div:

<div class="tag" id="tag">
    <span style="color:white;font-size: 10px;padding: 5px">楼宇名称:</span>
    <span style="font-size: 11px;font-weight: bold">XXX大厦</span>
    <p style="padding: 5px;margin-top: -3px;">占地面积:25541平方米</p>;
</div>

效果:
在这里插入图片描述
初始时我们可以将div的display设置为none,当确定它的位置后再设置为显示。
2.我们给标签指定一个场景中的位置,比如x y z为(20,30,50),要把三维坐标转换为屏幕坐标:
三维坐标转屏幕坐标的方法:

 function transPosition(position){
     let world_vector = new THREE.Vector3(position.x,position.y,position.z);
     let vector =world_vector.project(camera);
     let halfWidth = window.innerWidth / 2,
         halfHeight = window.innerHeight / 2;
     return {
         x: Math.round(vector.x * halfWidth + halfWidth),
         y: Math.round(-vector.y * halfHeight + halfHeight)
     };
 }

将指定的三维坐标转为屏幕坐标:

//计算三维坐标对应的屏幕坐标
        var position=new THREE.Vector3(20,30,50);
        var windowPosition=transPosition(position);
        var left=windowPosition.x;
        var top=windowPosition.y;

3.将屏幕坐标的位置赋给div,并将div的显示出来:

//设置div屏幕位置
        let div = document.getElementById('tag');
        div.style.display = "";
        div.style.left = left + 'px';
        div.style.top = top + 'px';

4.将div位置变换和赋值放入场景渲染频率中:

    function render() {
        divRender();
        renderer.render(scene, camera);
    }
 function divRender() {
        //计算三维坐标对应的屏幕坐标
        var position=new THREE.Vector3(20,30,50);
        var windowPosition=transPosition(position);
        var left=windowPosition.x;
        var top=windowPosition.y;
        //设置div屏幕位置
        let div = document.getElementById('tag');
        div.style.display = "";
        div.style.left = left + 'px';
        div.style.top = top + 'px';
    }

效果:
在这里插入图片描述
完整代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="css/style.css">
    <style>
        .tag {
            position: absolute;
            background-color: MidnightBlue;
            background-color: rgba(0, 10, 40);
            border-top-left-radius: 10px;
            border-bottom-right-radius: 10px;
            opacity: 0.5;
            font-size: 4px;
            color: aqua;
            padding: 1px 1px 1px;
        }
    </style>
</head>

<body onload="draw();">
    <div id="WebGL-output">
        <div class="tag" id="tag">
            <span style="color:white;font-size: 10px;padding: 5px">楼宇名称:</span>
            <span style="font-size: 11px;font-weight: bold">XXX大厦</span>
            <p style="padding: 5px;margin-top: -3px;">占地面积:25541平方米</p>
        </div>
    </div>
</body>
<script src="js/threer94.js"></script>
<script src="js/jquery.js "></script>
<script src="js/OrbitControls.js "></script>
<script src="js/stats.min.js "></script>
<script src="js/dat.gui.min.js "></script>
<script>
    var scene;
    var camera;
    var renderer;
  
  
    function init() {       
        scene = new THREE.Scene();        
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100000);
        renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });      
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMap.enabled = true; //打开阴影
        renderer.setClearAlpha(0.2);      
        var axis=new THREE.AxesHelper(200);;
        scene.add(axis)        
        //添加环境光
        var hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 1);
        hemiLight.position.set(0, 500, 0);
        scene.add(hemiLight);
        //设置相机位置
        camera.position.x = -300;
        camera.position.y = 400;
        camera.position.z = 300;
        camera.lookAt(scene.position);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);
        //鼠标控制器
        initControls();
        animate();
        window.addEventListener('resize', onResize, false); //添加窗口大小监听事件  
    };
    
    function initControls() {
            controls2 = new THREE.OrbitControls(camera, renderer.domElement);
            controls2.enableDamping = true;
            controls2.dampingFactor = 1;
            controls2.enableZoom = true;
            controls2.zoomSpeed = 2;
            controls2.autoRotate = false;

            controls2.minDistance = 0;
            controls2.maxDistance = 600;
            controls2.enablePan = true;
            controls2.keyPanSpeed = 15;
        }

    function animate() {
        //更新控制器
        controls2.update();
        divRender();
        renderer.render(scene, camera);
        requestAnimationFrame(animate);
    }
  
    function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

    function divRender() {
        //计算三维坐标对应的屏幕坐标
        var position = new THREE.Vector3(20, 30, 50);
        var windowPosition = transPosition(position);
        var left = windowPosition.x;
        var top = windowPosition.y;
        //设置div屏幕位置
        let div = document.getElementById('tag');
        div.style.display = "";
        div.style.left = left + 'px';
        div.style.top = top + 'px';
    }
    function transPosition(position) {
        let world_vector = new THREE.Vector3(position.x, position.y, position.z);
        let vector = world_vector.project(camera);
        let halfWidth = window.innerWidth / 2,
            halfHeight = window.innerHeight / 2;
        return {
            x: Math.round(vector.x * halfWidth + halfWidth),
            y: Math.round(-vector.y * halfHeight + halfHeight)
        };
    }
    window.onload = init;
</script>

</html>

项目中的应用:
html中标签样式:

  .tap{
            position: absolute;
            background-color: MidnightBlue;
            background-color:rgba(0,10,40);
            border-top-left-radius: 10px;
            border-bottom-right-radius:10px;
            opacity: 0.5;
            font-size: 4px;
            color: aqua;
            width: 36px;
            height: 44px;
            padding: 1px 1px 1px;
        }

js中动态添加

//txt1 txt2 txt3 为div中要显示的文本,具体样式可修改 innerHTML那一行
function addDom(txt1,txt2,txt3) {
    let addDivDom = document.createElement('div');
    let bodyDom = document.body;
    bodyDom.insertBefore(addDivDom, bodyDom.lastChild);
    addDivDom.classList = 'tap';
    addDivDom.innerHTML = '<span style="color:white;font-size: 10px;padding: 5px">' + txt1 + '</span>'+'<span style="font-size: 11px;font-weight: bold">'+txt2+'</span>'+'<p style="padding: 5px;margin-top: -3px;">'+txt3+'</p>';
}
 

render中要实时渲染修改标签的二维坐标,代码中的position为三维坐标,即标签插入时的三维坐标

function renderLabel(){
            div.style.left=transPosition(position).x + 'px';
            div.style.top=transPosition(position).y + 'px';
}
//三维坐标转屏幕坐标
  function transPosition (position) {
        let world_vector = new THREE.Vector3(position.x, position.y, position.z);
        let vector = world_vector.project(camera);
        let halfWidth = window.innerWidth / 2,
            halfHeight = window.innerHeight / 2;
        return {
            x: Math.round(vector.x * halfWidth + halfWidth),
            y: Math.round(-vector.y * halfHeight + halfHeight)
        };
    }

具体实例1:给建筑物添加标签
效果图:
在这里插入图片描述
在这里插入图片描述
(图一标签为颜色最暗的建筑的标签,图二为最高的建筑的标签)

    let build=new THREE.Group();
    var loader = new THREE.VRMLLoader();
    //加载一个wrl格式的模型,其他格式模型同样,自建cube等不需要自建box
    loader.load( 'model/h.wrl', function ( object ) {

        object.castShadow = true;

        build= object.children[0].children[0];
        build.castShadow = true;
        object.position.x=-20;
        object.position.y=0;
        object.position.z=-30;

        scene.add(object);
        let box= creatBoundingBox(object);
        build.box=box;
         addDom("楼宇名称  ","h 可点击","占地面积:25541平方米",box);
        CubeArray.push(box);
        })
        
function addDom(txt1,txt2,txt3,cube) {
    let addDivDom = document.createElement('div');
    let bodyDom = document.body;
    bodyDom.insertBefore(addDivDom, bodyDom.lastChild);
    addDivDom.id=cube.uuid+"_text";
    addDivDom.classList = 'tap';
    addDivDom.innerHTML = '<span style="color:white;font-size: 10px;padding: 5px">' + txt1 + '</span>'+'<span style="font-size: 11px;font-weight: bold">'+txt2+'</span>'+'<p style="padding: 5px;margin-top: -3px;">'+txt3+'</p>';
    divIdArray.push(addDivDom.id);
}
 //渲染实时更新标签位置
function render() {
    cubeLabe();
    renderer.render(scene, camera);
}
//只显示最近点击的楼的标签 其他标签隐藏不显示
function cubeLabe() {
    if(IsSelectedMesh==true)
    {
        let cube=clickmesh;
        let divid=cube.uuid+"_text";
        for(let i=0;i<divIdArray.length;i++) {
            let id = divIdArray[i];
            let div = document.getElementById(id);
            if(id==divid)
            {
                if(div!=null&&div!=undefined){
                    div.style.display="";
                    div.style.left=interface.transPosition(cube.position).x + 'px';
                    let posi=new THREE.Vector3(cube.position.x,(cube.position.y)*2,cube.position.z);
                    div.style.top=interface.transPosition(posi).y-100 + 'px';
                    // let number=cube.uuid;
                    // div.style.zIndex=number;
                }
            }else {
                if(div!=null&&div!=undefined){
                    div.style.display = "none";
                }

            }
        }
    }else {
        for(let i=0;i<divIdArray.length;i++) {
            let id = divIdArray[i];
            let div = document.getElementById(id);

            if(div!=null||div!=undefined){
                div.style.display = "none";
            }
        }
    }
}
//生成模型包围盒实体,方便标签判断位置
function creatBoundingBox(object) {
    //计算包围盒长宽高
    let Box=new THREE.Box3();
    Box.setFromObject(object);
    if ( Box.isEmpty() ) return;
    let min = Box.min;
    let max = Box.max;
    let width=max.x-min.x;
    let height=max.y-min.y;
    let deepth=max.z-min.z;
    // console.log(width+";"+height+";"+deepth);

    //计算包围盒中心点
    let centerX=(max.x+min.x)/2;
    let centerY=(max.y+min.y)/2;
    let centerZ=(max.z+min.z)/2;

    //画一个boundingbox的cube实体

    let boxGeometry=new THREE.BoxGeometry(width,height,deepth);
    let boxMaterial=new THREE.MeshLambertMaterial({});
    let box=new THREE.Mesh(boxGeometry,boxMaterial);
    box.position.set(centerX,centerY,centerZ);
    return box;
}

具体实例2 点击模型表面添加标签,标签为图片
效果图:
在这里插入图片描述
在这里插入图片描述

    var fixedBoard = function () {
        position:null;
        div:null;
        image:null
    }
    var fixedBoardlist=[];
    //添加鼠标事件 移除鼠标事件
    function ImageTag() {
        addEventListener('click',addFixedBoard);// 监听窗口鼠标单击事件
        $(document).keydown(function (event) {
            if (event.keyCode == 27) {
                removeAddBoard();
            }
        });
    }
//固定位置的标签
    function addFixedBoard() {
        var windowX = event.clientX;//鼠标单击位置横坐标
        var windowY = event.clientY;//鼠标单击位置纵坐标

        var addDivDom = document.createElement('div');
        var bodyDom = document.body;
        bodyDom.insertBefore(addDivDom, bodyDom.lastChild);
        // addDivDom.id=cube.uuid+"_text";
        addDivDom.classList = 'tap';
        var img=new Image();
        // var image=document.createElement("img");
        var  image_src="./img/002.png";
        img.src=image_src;
        addDivDom.appendChild(img);


        var x = (windowX / window.innerWidth) * 2 - 1;//标准设备横坐标
        var y = -(windowY / window.innerHeight) * 2 + 1;//标准设备纵坐标
        var standardVector = new THREE.Vector3(x, y, 0.5);//标准设备坐标
        //标准设备坐标转世界坐标
        var worldVector = standardVector.unproject(camera);
        var ray = worldVector.sub(camera.position).normalize();
        //创建射线投射器对象
        var raycaster = new THREE.Raycaster(camera.position, ray);
        //返回射线选中的对象
        var intersects = raycaster.intersectObjects(floorChildrenGroup);
        console.log(intersects);
        if (intersects.length > 0) {
            var point=intersects[0].point;
            var board=new fixedBoard();
            board.position=point;
            board.div=addDivDom;
            board.image=img;
            fixedBoardlist.push(board);
        }

    }
//移除鼠标单击事件绑定
    function removeAddBoard() {
        removeEventListener('click',addFixedBoard);
    }
//实时修改渲染时的图片位置
    function imagePosition() {
        for(var i=0;i<fixedBoardlist.length;i++){
            var position=fixedBoardlist[i].position;
            var div=fixedBoardlist[i].div;
            var x=interface.transPosition(position).x;
            var y=interface.transPosition(position).y;
            var image=fixedBoardlist[i].image;
            var width=image.width;
            var height=image.height;
            div.style.top=y-height+ 'px';
            div.style.left=x-width/2+ 'px';

        }
    }
//报警标签
    function Warning(Istrue) {
        if(Istrue){

            for(var i=0;i<fixedBoardlist.length;i++){
                fixedBoardlist[i].image.src='./img/003.png';
            }
            var button0=document.getElementById('warn');
            button0.style.display="none";
            var button1=document.getElementById('cancelwarn');
            button1.style.display="";
        }else {
            for(var i=0;i<fixedBoardlist.length;i++){
                fixedBoardlist[i].image.src='./img/002.png';
            }
            var button0=document.getElementById('warn');
            button0.style.display="";
            var button1=document.getElementById('cancelwarn');
            button1.style.display="none";
        }
    }
function render(){
    renderer.render(scene, camera);
    imagePosition();
}
  • 24
    点赞
  • 112
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
在Vue中使用Three.js批量添加标签,可以通过创建一个Vue组件来实现。首先需要在Vue组件中引入Three.js库和OrbitControls库,然后在组件的mounted钩子函数中创建场景、相机、渲染器等对象,并在场景中添加需要的标签。具体实现步骤如下: 1. 在Vue组件中引入Three.js库和OrbitControls库: ``` import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; ``` 2. 在组件的mounted钩子函数中创建场景、相机、渲染器等对象: ``` mounted() { // 创建场景对象 this.scene = new THREE.Scene(); // 创建相机对象 this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); this.camera.position.set(0, 0, 5); // 创建渲染器对象 this.renderer = new THREE.WebGLRenderer({ antialias: true }); this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.setClearColor(0xffffff, 1); // 将渲染器添加到页面中 this.$el.appendChild(this.renderer.domElement); // 创建控制器对象 this.controls = new OrbitControls(this.camera, this.renderer.domElement); this.controls.enableDamping = true; this.controls.dampingFactor = 0.25; this.controls.enableZoom = false; } ``` 3. 在场景中添加需要的标签: ``` addLabels() { // 循环添加标签 for (let i = 0; i < this.labels.length; i++) { const label = this.labels[i]; // 创建标签对象 const div = document.createElement('div'); div.className = 'label'; div.textContent = label.text; div.style.color = label.color; div.style.fontSize = label.fontSize + 'px'; const labelObject = new THREE.CSS2DObject(div); labelObject.position.set(label.position.x, label.position.y, label.position.z); // 将标签添加到场景中 this.scene.add(labelObject); } } ``` 其中,this.labels是一个数组,包含了需要添加标签的信息,例如文本内容、颜色、字体大小和位置等。在循环中,创建一个div元素作为标签的内容,然后将其包装成CSS2DObject对象,并设置其位置,最后将其添加到场景中即可。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值