ThreeJS 中一组 3D 对象的中心枢轴
Center pivot in a group of 3D objects in ThreeJS
我目前正在开发一个插件原型,可以通过 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');
}
};
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)
);
我目前正在开发一个插件原型,可以通过 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');
}
};
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) );