54 - three.js 笔记 - 模型中心设置为场景中心并获取边界框最值

在加载模型以及创建字体,旋转模型的时候会发现并不居中,特别是字体的旋转轴是边缘的y轴。
因此需要使模型的轴心位于模型的中心并且与场景的中心一致。
示例:
http://ithanmang.com/threeJs/home/201808/20180830/01-compute-center.html

1、 使用 .center方法

无论是缓存几何BufferGeometry还是简单几何Geometry,都有一个方法.center ()
直接让模型的几何结构调用这个方法就可以让模型居中。
这里写图片描述
例如下面的字体
① 以左侧边缘为中心点显示
这里写图片描述
② 以模型的中心点为旋转中心
添加以下代码

// TextGeometry文本几何对象
let fontGeometry = new THREE.TextGeometry(text,fontCfg);
fontGeometry.center();

这里写图片描述

2、 通过计算边界框使模型居中

模型的边界框boundingBox一个box3对象, 默认为null,计算模型的边界框,需要调用.computeBoundingBox ()方法。
例如字体模型,在没有计算边界框之前的TextGeometryboundingBox属性是null
这里写图片描述
计算边界框之后

fontGeometry.computeBoundingBox();//计算边界框

这里写图片描述
可以看到此时的boundingBox是一个box3对象,box3是在3D空间中表示一个盒子或立方体,其主要目的是为了表示对象的最小边界框。
box3有两个属性maxmin分别是边框的最值。
min:表示盒子的下(x,y,z)的边界
max:表示盒子的上(x,y,z)的边界
因此可以计算获取模型的中心点,只需要计算x轴的坐标,就可以使模型居中

font.position.x = -(fontGeometry.boundingBox.max.x - fontGeometry.boundingBox.min.x) / 2;

这里写图片描述
或者直接调用返回的box3对象的getCenter()方法,返回一个Vector3向量,然后设置为模型的中心点,也已实现居中显示。

2、 获取Group的边界最值

一般加载的模型都是通过对象组合放在一个Group中的,因此想要获取模型的边界值就需要获取整个Group的最值。
使用box3的方法expandByObject()参数是一个Object3D对象也即是Group对象或者是一个Mesh对象。
这里写图片描述
该方法返回一个Box3,因此可以获取边界最值。
同样也可以获取一组顶点或者一组向量以及一组标量的边界最值,方法如下,具体参考文档
这里写图片描述

字体模型示例代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>绘制字体模型</title>
    <style>

        body{
            margin: 0;
            overflow: hidden;
        }
        #loading {
            position: fixed;
            top: 50%;
            left: 50%;
            color: #FFFFFF;
            font-size: 20px;
            margin-top: -30px;
            margin-left: -40px;
        }

    </style>
    <script src="../../libs/build/three-r93.js"></script>
    <script src="../../libs/examples/js/Detector.js"></script>
    <script src="../../libs/examples/js/libs/dat.gui.min.js"></script>
    <script src="../../libs/examples/js/libs/stats.min.js"></script>
    <script src="../../libs/examples/js/controls/OrbitControls.js"></script>
</head>
<body>
<div id="WebGL-output"></div>
<div id="Stats-output"></div>
<p id="loading">loading......</p>
<script>

    let stats = initStats();

    let scene, camera, renderer, controls, light, gui;

    init();
    animate();

    function initScene() {
        scene = new THREE.Scene();
    }

    function initCamera() {
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
        camera.position.set(0, 200, 300);
        camera.lookAt(new THREE.Vector3(0, 0, 0));
    }

    function initRenderer() {
        if (Detector.webgl){
            renderer = new THREE.WebGLRenderer({antialias : true, autoClear : true});
        }else{
            renderer = new THREE.CanvasRenderer();
        }

        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor( 0x050505 );
        renderer.shadowMap.enabled = true;
        renderer.shadowMap.type = THREE.PCFSoftShadowMap;

        document.body.appendChild(renderer.domElement);
    }

    function initLight() {
        light = new THREE.SpotLight( 0xEEDFCC );
        light.position.set(-100, 200, 100);
        light.castShadow = true;

        scene.add(light);
        scene.add(new THREE.AmbientLight( 0xD1D1D1 ));
    }

    function initGui() {
        gui = new function () {

        };
        let guiControls = new dat.GUI();
    }

    function initContent() {

        let text = 'three.js';
        // 使用FontLoader加载字体
        let loader = new THREE.FontLoader();
        loader.load('../../libs/examples/fonts/gentilis_regular.typeface.json', function (response) {
            // 文字配置
            let fontCfg = {
                font : response,
                size : 50,
                height: 5,
                curveSegments: 20,
                bevelEnabled: true,
                bevelThickness: 10,
                bevelSize: 2,
                bevelSegments: 20
            };
            // TextGeometry文本几何对象
            let fontGeometry = new THREE.TextGeometry(text,fontCfg);
            fontGeometry.computeBoundingBox();//绑定盒子模型
            // fontGeometry.center();

            // 文字的材质
            let fontMaterial = new THREE.MeshNormalMaterial();
            let font = new THREE.Mesh(fontGeometry, fontMaterial);

            // // 计算出整个模型宽度的一半, 不然模型就会绕着x = 0,中心旋转
            font.position.x = -(fontGeometry.boundingBox.max.x - fontGeometry.boundingBox.min.x) / 2;

            scene.add(font);

            let helper = new THREE.GridHelper(1200, 60, 0xCD3700, 0x424242);
            scene.add(helper);

            document.getElementById('loading').style.display = 'none';

        });

    }

    function initControls() {
        controls = new THREE.OrbitControls(camera, renderer.domElement);
    }


    function initStats() {
        let stats = new Stats();

        stats.domElement.style.position = 'absolute';
        stats.domElement.style.left = '0px';
        stats.domElement.style.top = '0px';

        document.body.appendChild(stats.domElement);

        return stats;
    }

    function onWindowReisze() {

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);

    }

    function update() {
        stats.update();
        controls.update();
    }

    function init() {
        initScene();
        initCamera();
        initRenderer();
        initLight();
        initContent();
        initControls();
        initGui();

        window.addEventListener('resize', onWindowReisze, false);
    }

    function animate() {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
        update();
    }

</script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/ithanmang/article/details/82217963