ThreeJS中一组3D对象的中心轴

Posted

技术标签:

【中文标题】ThreeJS中一组3D对象的中心轴【英文标题】:Center pivot in a group of 3D objects in ThreeJS 【发布时间】:2015-07-12 19:19:20 【问题描述】:

我目前正在开发一个插件原型,可以通过 ThreeJS 自定义 3D 对象。到目前为止我所做的工作可以在这里看到:

http://itemgl.kaleidoscop.net/

您可能已经看到,当您悬停左箭头或右箭头时,对象会旋转,其原点位于左上角。有人知道如何在 ThreeJS 中改变它吗?

代码如下:

var options =  $.extend(
    id: 'canvas',
    width: 1110,
    height: 650,
    clearColor: 0xEEEEEE,
    btnLeft: $('#btnPrevious'),
    btnRight: $('#btnNext'),
    imagesLeather: ('.imageWood'),
    imagesWood: ('.imageWood'),
    core: object: [], renderer: null, camera: null, scene: null, light: null, canvas: null, spotLight: null, group: null, interval: null,
    items: wood: null, leather: null,
    geometry: ground: null, cube: null,
    numObj: 7,
    objGeometry: [x: 15, y: 1, z: 15, x: 2, y: 16, z: 2, x: 2, y: 16, z: 2, x: 2, y: 32, z: 2, x: 2, y: 32, z: 2,x: 12, y: 3, z: 1,x: 12, y: 3, z: 1],
    objPosition: [x: 8, y: 6, z: 3, x: 1, y: -2, z: 10, x: 15, y: -2, z: 10, x: 1, y: 6, z: -5, x: 15, y: 6, z: -5, x: 8, y: 20, z: -5, x: 8, y: 15, z: -5],
    objType: ['Leather', 'Wood', 'Wood', 'Wood', 'Wood','Leather','Leather']
, options);

var methods = 

    init: function(settings)

        if(typeof settings === 'object')
            $.extend(settings, this.options);
        

        options.core.scene = new THREE.Scene();
        options.core.camera = new THREE.PerspectiveCamera(50, options.width/options.height, 0.1, 1000);
        options.core.renderer = new THREE.WebGLRenderer();
        options.core.renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        options.core.renderer.setSize(options.width, options.height);
        options.core.renderer.shadowMapEnabled = true;
        options.core.group = new THREE.Object3D();  
        options.core.group.position.x = 5;          
        for(var i=0; i<options.numObj; i++)
            var cubeGeometry = new THREE.BoxGeometry(options.objGeometry[i].x, options.objGeometry[i].y, options.objGeometry[i].z);
            options.core.object[i] = methods.addMaterial(cubeGeometry, 'images/Resources/UVMap.png');
            options.core.object[i].receiveShadow = true;
            options.core.object[i].position.x = options.objPosition[i].x;
            options.core.object[i].position.y = options.objPosition[i].y;
            options.core.object[i].position.z = options.objPosition[i].z;
            options.core.group.add(options.core.object[i]);
        
        options.core.scene.add(options.core.group);
        options.core.camera.position.x = 10;
        options.core.camera.position.y = 30;
        options.core.camera.position.z = 60;
        options.core.camera.lookAt(new THREE.Vector3(10, 0, 0));
        options.core.light = new THREE.AmbientLight(0x0c0c0c);
        options.core.scene.add(options.core.light);
        options.core.spotLight = new THREE.SpotLight(0xffffff);
        options.core.spotLight.position.set(-30, 60, 60);
        options.core.spotLight.castShadow = true;
        options.core.scene.add(options.core.spotLight);
        $("#"+options.id).append(options.core.renderer.domElement);
        methods.render();
        methods.setupButtons();         
        options.core.renderer.render(options.core.scene, options.core.camera);
    ,

    setupButtons: function()
        options.btnLeft.hover(
          function()
            options.core.interval = window.setInterval(function()
                options.core.group.rotation.y += 0.05;
                options.core.renderer.render(options.core.scene, options.core.camera);
            , 15);
          , function() 
            window.clearInterval(options.core.interval);
          
        );
        options.btnRight.hover(
          function()
            options.core.interval = window.setInterval(function()
                options.core.group.rotation.y -= 0.05;
                options.core.renderer.render(options.core.scene, options.core.camera);
            , 15);
          , function() 
            window.clearInterval(options.core.interval);
          
        );
    ,

    render: function()
        requestAnimationFrame(methods.render);  
        options.core.renderer.render(options.core.scene, options.core.camera);
    ,

    changeItem: function(type, obj)
        var texture = THREE.ImageUtils.loadTexture(obj.firstChild.src);
        for(var i=0; i<options.numObj; i++)
            if(options.objType[i] == type)
                options.core.object[i].material.map = texture;
                       
        
    ,

    addMaterial: function(geom, imageFile)
        var texture = THREE.ImageUtils.loadTexture(imageFile)
        var mat = new THREE.MeshPhongMaterial();
        mat.map = texture;
        mat.needsUpdate = true;
        var mesh = new THREE.Mesh(geom, mat);
        return mesh;
    

;

$.fn.ItemGL = function(method)

    if(typeof method === 'undefined')
        method = 'init';    
    
    if(methods[method])
        return methods[ method ].apply(this, Array.prototype.slice.call(arguments, 1));
    else if(typeof method === 'object' || !method)
        return methods.init.apply(this, arguments);
    else
        $.error('Method '+ method+' does not exist on jQuery');
        
;

【问题讨论】:

***.com/questions/12746011/…, ***.com/questions/18068599/… 谢谢@dekkard!我认为这会有所帮助:D 见***.com/questions/28848863/… 【参考方案1】:
group.applyMatrix( new THREE.Matrix4().makeTranslation( x,y,z ) );

您可以在许多其他问题中看到的内容并没有为我完成这项工作。 可能是因为它是一个组而不是单个对象。

我的解决方案(有点长,但对我有用):

    找出所有 objPosition 值的中心

    var maxTrans  = x:0, y:0, z:0;
    var minTrans  = x:0, y:0, z:0;
    var translate2Center = x:0, y:0, z:0;
    for(var i=0; i<options.objPosition.length; i++) 
        var temp = options.objPosition[i];
    
        if (temp.x > maxTrans.x) maxTrans.x = temp.x;
        else if (temp.x < minTrans.x) minTrans.x = temp.x;
        if (temp.y > maxTrans.y) maxTrans.y = temp.y;
        else if (temp.y < minTrans.y) minTrans.y = temp.y;
        if (temp.z > maxTrans.z) maxTrans.z = temp.z;
        else if (temp.z < minTrans.z) minTrans.z = temp.z;
    
    translate2Center.x = minTrans.x + (maxTrans.x-minTrans.x)/2;
    translate2Center.y = minTrans.y + (maxTrans.y-minTrans.y)/2;
    translate2Center.z = minTrans.z + (maxTrans.z-minTrans.z)/2;
    

    在添加到组之前翻译每个对象

    for(var i=0; i<options.numObj; i++)
    
        options.core.object[i].position.x = options.objPosition[i].x - translate2Center.x;
        options.core.object[i].position.y = options.objPosition[i].y - translate2Center.y;
        options.core.object[i].position.z = options.objPosition[i].z - translate2Center.z;
        options.core.group.add(options.core.object[i]);
    
    

    将整个组移回

    options.core.group.applyMatrix( new THREE.Matrix4().makeTranslation(
          translate2Center.x, translate2Center.y, translate2Center.z)
    );
    

【讨论】:

谢谢伙计!你的回答太棒了!我一直在努力解决这个问题@Tobias

以上是关于ThreeJS中一组3D对象的中心轴的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Threejs 更改对象的 zOrder?

使用threejs绘制简单的3D图形

ThreeJS - 如何找到枢轴点

如何使用 babylonjs 或 threejs 预览 3D 中的 2D 平面对象? [关闭]

使用JSONLoader在threejs上导入3d对象

三 JS - 如何用 Y 平面切割 3D 对象?