我有一个盒子(collada文件)加载在three.js画布中.我可以按预期与它互动.但是,框大小会因用户可以更改大小而异.
当我将它加载到500px乘500px画布时,如果框大,用户必须在看到它之前放大,如果它很小,它很小,用户需要放大.尺寸根据变量而变化通过.
如何在加载画布时将对象(collada文件)放入画布中,然后让用户缩放?下面是加载点击以在three.js画布中显示3D对象的代码:
$scope.generate3D = function () {
// 3D OBJECT - Variables
var texture0 = baseBlobURL + 'Texture_0.png';
var boxDAE = baseBlobURL + 'Box.dae';
var scene;
var camera;
var renderer;
var box;
var controls;
var newtexture;
// Update texture
newtexture = THREE.ImageUtils.loadTexture(texture0);
// Initial call to render scene, from this point, Orbit Controls render the scene per the event listener
THREE.DefaultLoadingManager.onProgress = function (item, loaded, total) {
// console.log( item, loaded, total ); // debug
if (loaded === total) render();
};
//Instantiate a Collada loader
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load(boxDAE, function (collada) {
box = collada.scene;
box.traverse(function (child) {
if (child instanceof THREE.SkinnedMesh) {
var animation = new THREE.Animation(child, child.geometry.animation);
animation.play();
}
});
box.scale.x = box.scale.y = box.scale.z = .2;
box.updateMatrix();
init();
});
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(100, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xdddddd);
//renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setSize(500, 500);
// Load the box file
scene.add(box);
// Lighting
var light = new THREE.AmbientLight();
scene.add(light);
// Camera
camera.position.x = 40;
camera.position.y = 40;
camera.position.z = 40;
camera.lookAt(scene.position);
// Rotation Controls
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.addEventListener('change', render);
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 5;
controls.noZoom = false;
controls.noPan = false;
// Add 3D rendering to HTML5 DOM element
var myEl = angular.element(document.querySelector('#webGL-container'));
myEl.append(renderer.domElement);
}
// Render scene
function render() {
renderer.render(scene, camera);
console.log('loaded');
}
}
// Initial 3D Preview Load
$scope.generate3D();
Run Code Online (Sandbox Code Playgroud)
更新:我已经评估了此处介绍的解决方案:如何将相机安装到对象但不确定如何定义我的collada文件的距离,因为它可能会有所不同,具体取决于用户输入的尺寸.collada文件是由用户向第三方供应商发送变量生成的,该第三方供应商返回随后加载到three.js中的collada文件.
更新2:感谢@ Blindman67,我更接近了解这是如何相互作用的.当我手动启动camera.position x,y,z值时,对象在屏幕上.我面临的挑战是如何确定每个盒子动态变化时正确的x,y,z值是多少,而且我确实有超过2.8亿的变化.我知道@ Blindman67已经在逻辑上给了我答案,但我只需要最后一步来发现如何为每次变化的对象找到正确的位置,这样我就可以设置正确的x,y,z.
将3D对象适合视图
有几种方法可以将3d对象适合摄像机视图.
您可以打折最后一个选项,因为在大多数情况下它是不切实际的.(虽然我注意到你在代码中这样做,因为在这个答案中有足够的信息来解决如何缩放对象以适应.但我不建议你这样做)
因此,您要么将摄像机移入或移出,要么保持静止并进行缩放.它与真实相机相同,可以缩放或靠近.
这两种方法都有利有弊.
翻译
移动相机(小车)对于大多数情况来说是最好的,因为它保持透视相同(线条收敛到消失点的速度有多快),因此不会扭曲视野中的物体.在3D中,该方法存在3个问题.
放大
缩放涉及改变相机的焦距.在库中,您可以通过调整FOV(视野)来完成,这是以度为单位的视图左侧和右侧之间的角度.减小FOV有效地增加了焦距和放大(3D图形没有像相机那样的焦距).增加FOV缩小.这种方法存在问题.
使用什么方法是ip,你可以使用其中一种或两者兼用.
怎么做
对于手头的问题.我们需要知道对象在场景中的大小,并使用此信息将摄像机设置更改为所需的效果(即使对象适合显示).
所以需要一些值.有关视觉说明,请参见图1.
您需要计算对象的边界球体.或者使用近似于边界球的另一个值.我会把它留给你.
代码
var oL,cL; // for the math to make it readable
var FOV = 45 * (Math.PI / 180); // convert to radians
var objectLocation = oL = {x : 0, y : 0, z : 400};
var objectRadius = 50;
var cameraLocation = cL = {x : 0, y : 0, z : 0};
var farPlane = 1000;
var nearPlane = 200;
var displayWidth = 1600;
var displayHeight = 1000;
Run Code Online (Sandbox Code Playgroud)
要计算出边界球体在视图上的显示大小是简单的trig.
// Get the distance from camera to object
var distToObject = Math.sqrt(Math.pow(oL.x - cL.x, 2) + Math.pow(oL.y - cL.y, 2) + Math.pow(oL.z - cL.z, 2));Figure 1
Run Code Online (Sandbox Code Playgroud)
当我们使用直角三角形(见图1)时,我们将结果乘以2得到总角度大小
// trig inverse tan of opposite over adjacent.
var objectAngularSize = Math.atan( (objectRadius) / distToObject ) * 2;
Run Code Online (Sandbox Code Playgroud)
获取对象占据的FOV的分数.
var objectView = objectAngularSize / FOV;
Run Code Online (Sandbox Code Playgroud)
最后你得到了对象的像素大小.
var objectPixelSize = objectView * displayWidth;
Run Code Online (Sandbox Code Playgroud)
这就是你要做的所有事情.这将有助于您了解是否使用上述代码和数学来尝试重新排列计算,以便通过移动相机或FOV使对象占据所需的像素大小.复制代码并没有教会你太多,通过应用它来使用上述信息将在你的脑海中设置它,并将在未来更容易地制作3D所需的许多其他过程.
这就是说复制代码是快速解决方案,而且是框架和库的全部内容.无需知道如何学习更好的东西.
缩放以适应.
这是最简单的并获取对象的角度大小并调整FOV以适应.(注意我使用弧度.Tour.js使用你需要转换的FOV度数)
var requieredObjectPixelSize = 900;
var distToObject = Math.sqrt(Math.pow(oL.x - cL.x, 2) + Math.pow(oL.y - cL.y, 2) + Math.pow(oL.z - cL.z, 2));
var objectAngularSize = Math.atan( (objectRadius) / distToObject ) * 2;
// get the amount the FOV must be expanded by
var scaling = displayWidth / requieredObjectPixelSize;
// change the FOV to set the objects size
FOV = objectAngularSize * scaling;
Run Code Online (Sandbox Code Playgroud)
将FOV转换为度数并使用它来创建相机.
翻译适合
移动相机以适合对象.这有点复杂,但是更好的方法.
// Approx size in pixels you want the object to occupy
var requieredObjectPixelSize = 900;
// camera distance to object
var distToObject = Math.sqrt(Math.pow(oL.x - cL.x, 2) + Math.pow(oL.y - cL.y, 2) + Math.pow(oL.z - cL.z, 2));
// get the object's angular size.
var objectAngularSize = Math.atan( (objectRadius) / distToObject ) * 2;
// get the fraction of the FOV the object must occupy to be 900 pixels
var scaling = requieredObjectPixelSize / displayWidth;
// get the angular size the object has to be
var objectAngularSize = FOV * scaling;
// use half the angular size to get the distance the camera must be from the object
distToObject = objectRadius / Math.tan(objectAngularSize / 2);
Run Code Online (Sandbox Code Playgroud)
现在移动相机.它必须沿着物体和相机之间的矢量移动.
// Get the vector from the object to the camera
var toCam = {
x : cL.x - oL.x,
y : cL.y - oL.y,
z : cL.z - oL.z,
}
Run Code Online (Sandbox Code Playgroud)
规范化矢量.这意味着使向量的长度等于1,并通过将每个分量(x,y,z)除以向量的长度来完成.
// First length
var len = Math.sqrt(Math.pow(toCam.x, 2) + Math.pow(toCam.y, 2) + Math.pow(toCam.z, 2));
// Then divide to normalise (you may want to test for divide by zero)
toCam.x /= len;
toCam.y /= len;
toCam.z /= len;
Run Code Online (Sandbox Code Playgroud)
现在,您可以缩放矢量,使其等于摄像机与对象之间的距离.
toCam.x *= distToObject;
toCam.y *= distToObject;
toCam.z *= distToObject;
Run Code Online (Sandbox Code Playgroud)
然后只需将矢量添加到对象的位置并将其放入摄像机位置即可
cL.x = oL.x + toCam.x;
cL.y = oL.y + toCam.y;
cL.z = oL.z + toCam.z;
Run Code Online (Sandbox Code Playgroud)
cl 现在持有相机的位置.
最后一件事.您需要检查对象是否在视图内.
if (distToObject - objectRadius < nearPlane) {
nearPlane = (distToObject - objectRadius) * 0.8; // move the near plane towards the camera
// by 20% of the distance between the front of the object and the camera
}
if (distToObject + objectRadius > farPlane) {
farPlane = distToObject + objectRadius * 1.2; // move the far plane away from the camera
// by 1.2 time the object radius
}
Run Code Online (Sandbox Code Playgroud)
还有一个问题.如果物体很小,物体可能非常靠近物体的前部位于相机后面.如果发生这种情况,您将需要使用缩放方法并将相机移回.这仅适用于非常精选的情况,大多数情况下可以忽略.
我没有提供有关如何将其与Three.js集成的信息,但这是一个适用于所有3D软件包的通用答案.您将不得不查阅three.js文档,了解如何更改各种相机设置.它很简单,适用于透视相机.
好的答案我需要稍微忘记它,因为我没有看到错字和错误.我将在当天晚些时候返回并修复它.
希望能帮助到你
此代码将使相机“自动居中”在给定的对象周围。
对于用户“缩放”,还可以查看 Three.js Examples/js/controls/ TrackballControls.js,它会移动相机位置(并更改外观和向上)。如果您选择使用它,我记得您需要在使用 移动相机位置之前centerCam初始化控件。在这种情况下,centerCam获取整个对象以准备用户交互,然后TrackballControls侦听器接管。
<body onload="initPage()">
<canvas id="cadCanvas" width="400" height="300"></canvas>
<button onclick="loadFile()">Load Collada File</button>
</body>
function initPage(){
var domCanvas = document.getElementById('cadCanvas');
scene = new THREE.Scene();
var fovy = 75;
camera = new THREE.PerspectiveCamera( fovy, domCanvas.width/domCanvas.height, 0.1, 1000 );
renderer = new THREE.WebGLRenderer({canvas:domCanvas});
renderer.setSize( domCanvas.width, domCanvas.height );
}
function loadFile(){
new THREE.ColladaLoader().load( url, function(obj3D) {
scene.add(obj3D);
centerCam(obj3D);
renderer.render(scene, camera);
});
}
function centerCam(aroundObject3D){
//calc cam pos from Bounding Box
var BB = new THREE.Box3().setFromObject(aroundObject3D);
var centerpoint = BB.center();
var size = BB.size();
var backup = (size.y / 2) / Math.sin( (camera.fov/2)*(Math.PI/180) );
var camZpos = BB.max.z + backup + camera.near ;
//move cam
camera.position.set(centerpoint.x, centerpoint.y, camZpos);
camera.far = camera.near + 10*size.z;
camera.updateProjectionMatrix();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1556 次 |
| 最近记录: |