ThreeJS中的EdgesGeometry的使用

1  首先看看效果

   

X坐标平移了一个单位后的效果,效果良好。

但也有一个问题,如果图形结构比较复杂,也就是顶点较多的情况下,会影响帧率,实验结果是帧率从60直接降到了15。

2  THREE.EdgesGeometry

具体参数可以查询相关资料,直接上代码,其中的boundingBox和selectedObject都是全局变量,配合鼠标点选功能完成。

其中对位置、缩放、旋转都取了选中对象的原始值,否则会出现偏差(没有及时更新?没搞明白)。

因为这段代码是放在渲染函数中的,有些局部变量可以考虑设置为全局变量,以提高渲染效率。

            if(selectedObject)
            {
                if (boundingBox)
                    scene.remove(boundingBox);

                //简单的包围盒
                // boundingBox = new THREE.BoxHelper(selectedObject, 0x0000ff);
                // scene.add(boundingBox);
                //完整的线框
                var edgesMtl =  new THREE.LineBasicMaterial({color: 0xff0000});
                var coneEdges = new THREE.EdgesGeometry(selectedObject.geometry, 1);
                coneEdges.lineWidth=1;
                boundingBox = new THREE.LineSegments(coneEdges, edgesMtl);
                scene.add(boundingBox);
                //控制位置
                boundingBox.position.set(selectedObject.position.x-2,
                                         selectedObject.position.y,
                                         selectedObject.position.z);
                //控制角度
                boundingBox.rotation.set(selectedObject.rotation.x,
                                         selectedObject.rotation.y,
                                         selectedObject.rotation.z);
                //控制比例
                boundingBox.scale.set(   selectedObject.scale.x,
                                         selectedObject.scale.y,
                                         selectedObject.scale.z);
            }       

3  完整的代码

   需要注意src位置、全局变量和鼠标点选函数,以及主渲染函数

<html>
<head>
    <title>Threejs三维场景基本模块</title>
    <style type="text/css">
        body
        {
            margin: 0;
            overflow: hidden; /* 隐藏body窗口区域滚动条 */
        }
    </style>
    <!--引入three.js三维引擎-->

    <script type="text/javascript" src="threejsmaster/build/three.js"></script>
    <script type="text/javascript" src="threejsmaster/build/js/libs/dat.gui.min.js">/script>
    <script type="text/javascript" src="threejsmaster/build/js/libs/stats.min.js"></script>
    <script type="text/javascript" src="threejsmaster/build/js/loaders/STLLoader.js"></script>

</head>
<body>
    <!-- 作为Three.js渲染器输出元素 -->
    <div id="WebGLwxp" align="center">
        <div id="notice"></div>
    </div>

    <script type="text/javascript">

        //全局变量---------------------------------

        //仿真场景必备变量
        var scene, camera, renderer;           
       
        //界面变量
        var GuiControls;

        //物体变量
        var cube;

        //相机视角
        var fov = 45;
        var mouseDownX = 0;
        var mouseMoveX = 0;

        //鼠标点选变量 
        var objects = [];    //可以点选的物体容器
        var mouseXY;           //鼠标平面坐标
        var raycaster;         //射线对象
        var boundingBox;       //包围盒
        var selectedObject;    //被选中的物体

        var WxpTexture;        //纹理对象   
        var textObj ;          //公告板  
        var stats;             //性能显示板

        //-----------------------------------------      
        //键盘函数    
        function WxpKeyPressed(e) {
            var key = event.keyCode;
            if (!boundingBox)
                document.getElementById("notice").innerHTML = "请先选中物体" + key.toString();
            switch (key) {

                case 37: /*左方向键*/
                    GuiControls.camerPositionX += 0.1;
                    break;

                case 39: /*右方向键*/
                    GuiControls.camerPositionX -= 0.1;
                    break;

                case 38: /*向上键*/
                    GuiControls.camerPositionY -= 0.1;
                    break;

                case 40: /*向下键*/
                    GuiControls.camerPositionY += 0.1;
                    break;

                case 87: /*w*/
                    selectedObject.position.y += 0.5;
                    selectedObject.rotation.x -= Math.PI / 4.0;
                    break;

                case 65: /*a*/
                    selectedObject.position.x -= 0.5;
                    selectedObject.rotation.y -= Math.PI / 4.0;
                    break;

                case 83: /*s*/
                    selectedObject.position.y -= 0.5;
                    selectedObject.rotation.x += Math.PI / 4.0;
                    break;
                case 68: /*d*/
                    selectedObject.position.x += 0.5;
                    selectedObject.rotation.y += Math.PI / 4.0; ;
                    break;
            }          
        }

        //---------------------------------------------------
        //中键滚动
        function WxpMousewheel(e) {
            e.preventDefault();
            if (e.wheelDelta) {
                if (e.wheelDelta > 0) { //当滑轮向上滚动时
                    fov += 1;
                }

                if (e.wheelDelta < 0) { //当滑轮向下滚动时
                    fov -= 1;
                }

            } else if (e.detail) {  //Firefox滑轮事件
                if (e.detail > 0) { //当滑轮向上滚动时
                    fov -= 1;
                }
                if (e.detail < 0) { //当滑轮向下滚动时
                    fov += 1;
                }
            }
            camera.fov = fov;
            camera.updateProjectionMatrix();
            renderer.render(scene, camera);
        }

        //左键按下--------------------------------
        function WxpMouseDown(event) {//按下鼠标

            event.preventDefault();
            mouseXY.set((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1);

            raycaster.setFromCamera(mouseXY, camera);

            var intersects = raycaster.intersectObjects(objects);

            if (intersects.length > 0) {

                selectedObject = intersects[0].object;                

                //boundingBox = new THREE.BoxHelper(selectedObject, 0xff0000);
               // scene.add(boundingBox);               
                
                //动态标签
                var str = new String("");
                var div = document.getElementById('notice');
                var left = transPosition(selectedObject.position).x+100;
                var top = transPosition(selectedObject.position).y - 50;
                div.style.position = 'absolute';
                div.style.color = "blue";
                div.style.display = "";
                div.style.left = left + 'px';
                div.style.top = top + 'px';

                str = selectedObject.name + "  x=" + left + "   y=" + top;
                div.innerHTML = str;
            }
            //没有选中物体就移除包围盒,不显示物体信息
            else {
                if (boundingBox)
                    scene.remove(boundingBox);
                selectedObject=null;
                var div = document.getElementById('notice');
                div.innerHTML = "";
                document.body.style.cursor = 'default';
            }

        }

        //三维坐标转屏幕坐标
        function transPosition(position) {
            var world_vector = new THREE.Vector3(position.x, position.y, position.z);
            var vector = world_vector.project(camera);
            var halfWidth = window.innerWidth / 2,
            halfHeight = window.innerHeight / 2;
            return {
                x: Math.round(vector.x * halfWidth + halfWidth),
                y: Math.round(-vector.y * halfHeight + halfHeight)
            };
        }
        //按下左键后移动------------------------------
        function WxpMouseMove(event) {//移动鼠标

            mouseMoveX = event.clientX - mouseDownX;
            // mouseX = event.clientX - windowHalfX;

            // targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
        }

        //左键释放-------------------------------------
        function WxpMouseUp(event) {//释放鼠标键

            document.removeEventListener('mousemove', WxpMouseMove, false);
            document.removeEventListener('mouseup', WxpMouseUp, false);
        }
        //----------------------------------------- 
        //场景基本配置
        function WxpInitScene() {

            //**********************基本元素**************************************
            var sceneWidth = window.innerWidth;  // window.innerWidth-400;
            var sceneHeight = window.innerHeight; //window.innerHeight-80;

            //创建一个场景
            scene = new THREE.Scene();

            //创建一个摄像机对象
            camera = new THREE.PerspectiveCamera(45, sceneWidth / sceneHeight, 0.1, 200);

            //设置摄像机参数
            camera.position.set(10.0, -20, 13);
            camera.up.set(0, 0, 1);                          //Z轴正向向上
            camera.lookAt(new THREE.Vector3(0, 0, 0));

            //创建一个WebGL渲染器
            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setClearColor(new THREE.Color(0x7696f1));
            renderer.setSize(sceneWidth, sceneHeight);
            renderer.setPixelRatio(window.devicePixelRatio); //框锯齿设置

            //系统坐标系绘制-------------------------
            var axesHelper = new THREE.AxesHelper(12);
            scene.add(axesHelper);

            raycaster = new THREE.Raycaster();
            mouseXY = new THREE.Vector2();

            //网格线绘制
            var grid = new THREE.GridHelper(24, 24, 0xFF0000, 0x444444);
            grid.material.opacity = 0.4;
            grid.material.transparent = true;
            grid.rotation.x = Math.PI / 2.0;                  //默认网格线旋转90度
            scene.add(grid);
            //---------------------------------------           
            //***********************************************************************
            //建立环境光线
            var ambient = new THREE.AmbientLight(0x666666);
            scene.add(ambient);

            //平行光(没感觉到作用)
            var directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
            scene.add(directionalLight);

            //创建点光源 正上面
            var spotLightTop = new THREE.SpotLight(0xFFFFFF);
            spotLightTop.position.set(0, 0, 50);
            spotLightTop.castShadow = true;
            scene.add(spotLightTop);

            //左前方
            var spotLightFront = new THREE.SpotLight(0xaaaaaa);
            spotLightFront.position.set(-50, 50, 5);
            spotLightFront.castShadow = true;
            scene.add(spotLightFront);

            //右前方
            var spotLightRight = new THREE.SpotLight(0xaaaaaa);
            spotLightRight.position.set(50, 50, 5);
            spotLightRight.castShadow = true;
            scene.add(spotLightRight);

            //左后方
            var spotLightLeft = new THREE.SpotLight(0xaaaaaa);
            spotLightLeft.position.set(-50, -50, 5);
            spotLightLeft.castShadow = true;
            scene.add(spotLightLeft);

            //右后方
            var spotLightRear = new THREE.SpotLight(0xaaaaaa);
            spotLightRear.position.set(50, -50, 5);
            spotLightRear.castShadow = true;
            scene.add(spotLightRear);
        

            document.getElementById("WebGLwxp").appendChild(renderer.domElement);
            window.addEventListener('keydown', WxpKeyPressed, false);
            window.addEventListener('mousedown', WxpMouseDown, false);
            window.addEventListener('mousewheel', WxpMousewheel, false);
            
            //将渲染的结果输出到指定页面元素中,必须放在场景渲染之后
            stats = new Stats();
            stats.showPanel( 0 ); // 0: fps, 1: ms, 2: mb, 3+: custom            
            document.getElementById("WebGLwxp").appendChild(stats.dom);
        }

        //----------------------------------------- 
        //加载场景物体
        function WxpAddObject() {

            //加载物体
            //创建一个立方体
            var cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
            var cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000, opacity: 0.5, transparent: true });
            cube = new THREE.Mesh(cubeGeometry, cubeMaterial);    //物体=几何体+材质
            cube.castShadow = true;
            cube.name = "objtest";

            //设置立方体的位置
            cube.position.set(0, 0, 0.5);
            scene.add(cube);
            objects.push(cube);

            //创建一个立方体
            var cubeGeometry2 = new THREE.CylinderGeometry(0, 1, 1, 20, 20, false);
            // var cubeMaterial2 = new THREE.MeshNormalMaterial({flatShading: true});
            // var cubeMaterial2 = new THREE.MeshPhongMaterial({color: 0x836DED,specular:0x111111,shininess:80});
            WxpTexture = new THREE.ImageUtils.loadTexture("aa.png");
            var cubeMaterial2 = new THREE.MeshBasicMaterial({ map: WxpTexture, transparent: true });
            WxpTexture.wrapS = THREE.RepeatWrapping;
            WxpTexture.wrapT = THREE.RepeatWrapping;
            WxpTexture.repeat.set(2, 2);
            WxpTexture.center.set(0.5, 0.5);

            cube2 = new THREE.Mesh(cubeGeometry2, cubeMaterial2);    //物体=几何体+材质
            //设置立方体的位置
            cube2.position.set(4, 0, 0.5);
            scene.add(cube2);
            objects.push(cube2);
            cube2.name = "obj多对多";


            //创建管道成型的路径(3D样条曲线)
            var path = new THREE.CatmullRomCurve3([
              new THREE.Vector3(-5, 0, 1),
              new THREE.Vector3(0, 5, 1),
              new THREE.Vector3(5, 0, 1),
              new THREE.Vector3(0, 0, 0)]);
            var point = path.getPoints(100);
            var points = new THREE.CatmullRomCurve3(point);
            // path:路径   40:沿着轨迹细分数  2:管道半径   25:管道截面圆细分数
            var geometry3 = new THREE.TubeGeometry(path, 40, 0.2, 25);
            var cube3 = new THREE.Mesh(geometry3, cubeMaterial2);    //物体=几何体+材质
            cube3.name = "objwwww";

            scene.add(cube3);
            objects.push(cube3);


            //地板
            var plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(10, 10),
					                   new THREE.MeshBasicMaterial({ color: 0xdddddd, side: THREE.DoubleSide })
					                   );
            scene.add(plane);
            plane.receiveShadow = true;


            var loader = new THREE.STLLoader();
            var stlFileName = new String("NDG2_160.stl");
            loader.load(stlFileName, function(geometry) {
                //创建纹理
                var mat = new THREE.MeshPhongMaterial({ color: 0x836DED, specular: 0x111111, shininess: 100 });
                var mesh = new THREE.Mesh(geometry, mat);
                mesh.scale.set(0.01, 0.01, 0.01);       //缩放
                geometry.center();                      //建立几何中心
                mesh.position.set(0, -2, 0.5);            //位置
                mesh.castShadow = true;
                mesh.receiveShadow = true;

                mesh.name = "test";

                objects.push(mesh);
                scene.add(mesh);
            });

            //精灵对象Sprite
            var texture = new THREE.TextureLoader().load("test.png");
            // 创建精灵材质对象SpriteMaterial
            var spriteMaterial = new THREE.SpriteMaterial({
                    color:0xffffff,//设置精灵矩形区域颜色
                    //rotation:Math.PI/4,//旋转精灵对象45度,弧度值
                    map: texture,//设置精灵纹理贴图
                    transparent:true 
                });
            // 创建精灵模型对象,不需要几何体geometry参数
            var sprite = new THREE.Sprite(spriteMaterial);
            scene.add(sprite);
            // 控制精灵大小,比如可视化中精灵大小表征数据大小
            sprite.scale.set(0.5, 0.5, 1);  只需要设置x、y两个分量就可以
            sprite.position.set(0, -5, 1); 

            //
            //先用画布将文字画出
            var canvas = document.createElement("canvas");
            var  ctx = canvas.getContext("2d");
            ctx.fillStyle = "#0000ff";
            ctx.font = "20px Arial";
            ctx.lineWidth = 1;
            ctx.fillText("ABCDRE",4,20);
            var texture = new THREE.Texture(canvas);
            texture.needsUpdate = true;

            //使用Sprite显示文字
            var material = new THREE.SpriteMaterial({map:texture});
            textObj = new THREE.Sprite(material);
            textObj.scale.set(1,1,1);
            textObj.position.set(4,-4,1);
            textObj.material=material;
            scene.add(textObj);
           
        }
        //----------------------------------------- 
        //界面设置  
        function WxpGuiSetting() {
            //存放所有需要改变的属性的对象
            GuiControls = new function() {
                this.rotationSpeed = 0.01;

                this.camerPositionX = 4.00;
                this.camerPositionY = -8.00;
                this.camerPositionZ = 4.00;
            };

            //创建dat.GUI,传递并设置属性
            var gui = new dat.GUI();
            gui.add(GuiControls, 'rotationSpeed', 0, 0.5);

            gui.add(GuiControls, 'camerPositionX', -40.0, 20.0);
            gui.add(GuiControls, 'camerPositionY', -40.0, 10.0);
            gui.add(GuiControls, 'camerPositionZ', 0.0, 40.0);
        }

        //渲染场景
        function WxpRender() {

            stats.begin();
            //GUI更新必要的参数
            cube.rotation.z += GuiControls.rotationSpeed;

            camera.position.x = GuiControls.camerPositionX;
            camera.position.y = GuiControls.camerPositionY;
            camera.position.z = GuiControls.camerPositionZ;

            WxpTexture.offset.x += 0.006;

            //先用画布将文字画出
            var canvas = document.createElement("canvas");
            var  ctx = canvas.getContext("2d");
            ctx.fillStyle = "#0000ff";
            ctx.font = "20px Arial";
            ctx.lineWidth = 1;
            var d=new Date();
            var txt=d.toLocaleTimeString();
            ctx.fillText(txt,4,20);
            var texture = new THREE.Texture(canvas);
            texture.needsUpdate = true;

            //使用Sprite显示文字
            var material = new THREE.SpriteMaterial({map:texture});
            textObj.material=material;                 

            //鼠标控制旋转
            //cube.rotation.z=mouseMoveX*0.02; 
            //document.getElementById("notice").innerHTML = cube.rotation.x.toFixed(2).toString();
            //divRender();
            //console.log(scene);
            if(selectedObject)
            {
                if (boundingBox)
                    scene.remove(boundingBox);

                //简单的包围盒
                // boundingBox = new THREE.BoxHelper(selectedObject, 0x0000ff);
                // scene.add(boundingBox);
                //完整的线框
                var edgesMtl =  new THREE.LineBasicMaterial({color: 0xff0000});
                var coneEdges = new THREE.EdgesGeometry(selectedObject.geometry, 1);
                coneEdges.lineWidth=1;
                boundingBox = new THREE.LineSegments(coneEdges, edgesMtl);
                scene.add(boundingBox);
                //控制位置
                boundingBox.position.set(selectedObject.position.x-2,
                                         selectedObject.position.y,
                                         selectedObject.position.z);
                //控制角度
                boundingBox.rotation.set(selectedObject.rotation.x,
                                         selectedObject.rotation.y,
                                         selectedObject.rotation.z);
                //控制比例
                boundingBox.scale.set(   selectedObject.scale.x,
                                         selectedObject.scale.y,
                                         selectedObject.scale.z);
            }
                               
            //渲染场景
            renderer.render(scene, camera);
            stats.end();
            //通过requestAnimationFrame方法在特定时间间隔重新渲染场景,循环调用
            requestAnimationFrame(WxpRender);    
        }

        //-----------------------------------------    
        //ThreeJS仿真函数
        function WxpThreeJSInit() {

            //初始化场景
            WxpInitScene();

            //加载物体
            WxpAddObject();

            //界面设置
            WxpGuiSetting();

            //渲染场景
            WxpRender();
        }

        //确保WxpThreeJSinit方法在网页加载完毕后被调用
        window.onload = WxpThreeJSInit;
 
    </script>

</body>
</html>

猜你喜欢

转载自blog.csdn.net/sichuanpb/article/details/111246577