我已经用 three.js 实现了一个简单的 3D 模型查看器。该项目包含一个 3D 模型数据库,分为不同的类别。一类是机型高(宽度相对较小,高度远高于其他机型的高度),另一类机型是小(相对于所有产品,高度和宽度都小于其他机型)在其他类别中,这些是小型模型),在另一个类别中,模型很大(它们的高度和比其他类别的许多模型更宽。
查看器具有固定的画布宽度和高度。为此,在画布中加载模型时,很多模型会立即以小比例加载,这需要后续多次缩放。还有一些模型,其上部不适合画布,而下部则在启动时。这也需要后续的缩放。
查看器首先需要估计模型的尺寸,然后它会自动为模型单独选择比例,然后将模型垂直和水平居中。
模型所在的平面(模型有可触摸的宽度和高度,厚度很小,所有这些模型都接近平面)与屏幕平面重合也是必要的。在启动时,许多模型对这些平面都有偏移。如何实现这一点,以便查看器自动展开模型?
下面我附上来自不同类别的模型的屏幕截图 - 它们被清楚地记录在哪里:
下面是负责初始化场景的查看器代码:
var objectUrl = $('#modelViewerModal').data('object-url');//'/storage/3d/qqq.obj';
var mesh, renderer, scene, camera, controls;
init();
animate();
function init() {
const screenshotPageWidth = $(document).width();
const screenshotPageHeight = $(document).height();
let modalBody = document.querySelector('#scene-container');
// renderer
renderer = new THREE.WebGLRenderer({modalBody});
var height = screenshotPageHeight / 2;
var width = screenshotPageWidth / 2;
if (screenshotPageHeight < screenshotPageWidth) { // landscape orientation
if (width > 3 * height / 2) {
width = 3 * height / 2;
} else if (width < 3 * height / 2) {
height = 2 * width / 3;
}
} else if (screenshotPageHeight > screenshotPageWidth) { // portrait orientation
if (height > 2 * width / 3) {
height = 2 * width / 3;
} else if (height < 2 * width / 3) {
width = 3 * height / 2;
}
}
// let limitHeight = screen.height - 137;
renderer.setSize(width, height);
modalBody.appendChild( renderer.domElement );
// scene
scene = new THREE.Scene();
scene.background = new THREE.Color( 0x000000 );
// camera
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 20, 20, 20 );
// controls
controls = new OrbitControls( camera, renderer.domElement );
// ambient
scene.add( new THREE.AmbientLight( 0x222222 ) );
// light
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 2000, 2000, 2000 );
scene.add( light );
var spotLight_01 = getSpotlight('rgb(145, 200, 255)', 1);
spotLight_01.name = 'spotLight_01';
var spotLight_02 = getSpotlight('rgb(255, 220, 180)', 1);
spotLight_02.name = 'spotLight_02';
scene.add(spotLight_01);
scene.add(spotLight_02);
// geometry
var geometry = new THREE.SphereGeometry( 5, 12, 8 );
// material
const material = new THREE.MeshPhongMaterial({
color: 0xeae8dc,
side: THREE.DoubleSide,
transparent: false,
flatShading: false,
opacity: 0
});
// mesh
var objLoader = new THREE.OBJLoader();
objLoader.load(objectUrl,
function ( obj ) {
mesh = obj;
mesh.scale.setScalar( 0.01 );
obj.traverse( function( child ) {
if ( child.isMesh ) child.material = material;
} );
// center the object
var aabb = new THREE.Box3().setFromObject( mesh );
var center = aabb.getCenter( new THREE.Vector3() );
mesh.position.x += (mesh.position.x - center.x);
mesh.position.y += (mesh.position.y - center.y);
mesh.position.z += (mesh.position.z - center.z);
scene.add( mesh );
animate();
} );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
}
function getSpotlight(color, intensity) {
var light = new THREE.SpotLight(color, intensity);
light.castShadow = true;
light.shadow.mapSize.x = 4096;
light.shadow.mapSize.y = 4096;
return light;
}