【Three.js】解决使用Three.js导入obj模型不可见问题详细记录

问题描述:

近期在做三维重建项目,需要把最终生成的obj文件导入到web端浏览,这里使用的是three.js(另一个是babylon.js),但博主发现导入meshlab生成的obj时无法显示模型,但使用3dmax制作好的obj模型就可以正常加载。

先写结论:

模型可以加载但不显示,将mtl文件中的Tr值置为0或者将此行删除,Tr值是透明度的意思。

在这里插入图片描述

分析问题:

1.首先怀疑是Three.js无法识别meshlab导出的obj模型

查看使用3dmax导出的obj模型和meshlab导出的obj模型的内容差异:
3dmax:

mtllib .\hezi.mtl
#
# object Box001
#

v  -376.1360 0.0000 -195.4246
v  -376.1360 0.0000 -2416.9438
v  383.2684 0.0000 -2416.9438
v  383.2684 0.0000 -195.4246
v  -376.1360 281.1217 -195.4246
v  383.2684 281.1217 -195.4246
v  383.2684 281.1217 -2416.9438
v  -376.1360 281.1217 -2416.9438
# 8 vertices

vn -0.5774 -0.5774 0.5774
vn -0.5774 -0.5774 -0.5774
vn 0.5774 -0.5774 -0.5774
vn 0.5774 -0.5774 0.5774
vn -0.5774 0.5774 0.5774
vn 0.5774 0.5774 0.5774
vn 0.5774 0.5774 -0.5774
vn -0.5774 0.5774 -0.5774
# 8 vertex normals

vt 1.0000 0.0000 0.0000
vt 1.0000 1.0000 0.0000
vt 0.0000 1.0000 0.0000
vt 0.0000 0.0000 0.0000
# 4 texture coords

o Box001
g Box001
usemtl Material__20
s 2
f 1/1/1 2/2/2 3/3/3 4/4/4 
s 4
f 5/4/5 6/1/6 7/2/7 8/3/8 
s 8
f 1/4/1 4/1/4 6/2/6 5/3/5 
s 16
f 4/4/4 3/1/3 7/2/7 6/3/6 
s 32
f 3/4/3 2/1/2 8/2/8 7/3/7 
s 64
f 2/4/2 1/1/1 5/2/5 8/3/8 
# 6 polygons

meshlab:

####
#
# OBJ File Generated by Meshlab
#
####
# Object scene_dense_mesh_refine_texture.obj
#
# Vertices: 36032
# Faces: 70060
#
####
mtllib ./oursIron.mtl

vn -0.076525 -6.217203 -0.898077
v -0.537006 2.274760 -0.542009
vn -0.113609 -6.222937 -0.851465
v -0.480373 2.269041 -0.512856
vn 3.533463 -1.284490 -3.854646
v 0.272679 2.189417 -0.064509
vn -3.800684 -2.640818 -4.247900
v -1.191661 0.672984 0.196901
vn -3.108446 -1.922066 4.855567
v -0.489023 -0.371425 0.833074
vn 3.783675 -1.464100 4.783770
v -0.290044 -0.228601 0.900917
vn 1.204478 -2.802450 5.142253
v -0.240296 -0.132796 0.911664
vn -1.789222 -3.291406 5.007094
v -0.998870 0.413465 1.330705
vn -3.730475 5.029276 0.472679
v -1.170823 0.951970 0.805072

比较后发现除了排列方式不同其他的内容元素都是一样的,比如v,vn等,这里的具体含义参考博客:
obj文件、mtl文件结构说明
并且博主使用可以加载显示的obj模型在meshlab中重新导出仍然可以显示,这基本上可以排除是meshalb导出的原因。

2.模型是否已经导入到Three.js中?

先给出加载mtl和obj的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>three.js webgl - OBJLoader + MTLLoader</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <style>
        body {
            font-family: Monospace;
            background-color: rgba(101, 132,226, 0.1);
            color: #fff;
            margin: 0px;
            overflow: hidden;
        }
        #info {
            color: #fff;
            position: absolute;
            top: 10px;
            width: 100%;
            text-align: center;
            z-index: 100;
            display:block;
        }
        #info a, .button { color: #f00; font-weight: bold; text-decoration: underline; cursor: pointer }
    </style>
    <!--引入three.js三维引擎-->
<!--    <script src="http://www.yanhuangxueyuan.com/3D/example/three.min.js"></script>-->
<!--    <script src="http://www.yanhuangxueyuan.com/3D/example/three.min.js"></script>-->
<!--    <script src="js/three.js"></script>-->
    <!--引入轨道控件OrbitControls.js-->
    <!--<script src="js/OrbitControls.js"></script>-->
    <!--<script src="http://www.yanhuangxueyuan.com/3D/example/OrbitControls.js"></script>-->
</head>
<body>
<!--<script src="http://www.yanhuangxueyuan.com/3D/example/three.min.js"></script>-->
<script src="js/three.js"></script>
<!--<script src="../build/three.js"></script>-->
<script src="js/DDSLoader.js"></script>
<script src="js/MTLLoader.js"></script>
<script src="js/OBJLoader.js"></script>
<script src="js/TrackballControls.js"></script>
<script src="js/Detector.js"></script>
<script src="js/stats.min.js"></script>
<script src="js/OrbitControls.js"></script>
<!--<script src="js/Vector3Node.js"></script>-->
<script>

    // 容器
    var container,
        stats,
        // 控制器
        controls,
        orbitControls;

    // 镜头
    var camera,
        // 场景
        scene,
        // 渲染
        renderer;

    var mouseX = 0, mouseY = 0;
    var windowHalfX = window.innerWidth / 2;
    var windowHalfY = window.innerHeight / 2;


    init();
    // animate();


    function init() {

        container = document.createElement( 'div' );
        document.body.appendChild( container );

        //正投影相机
        //创建正投影相机
        // var camera = new THREE.OrthographicCamera(window.innerWidth / -16, window.innerWidth / 16, window.innerHeight / 16, window.innerHeight / -16, -200, 500);
        // camera.position.set(120, 60, 180); //设置相机位置
        // camera.lookAt(scene.position); //设置相机方向

        //创建一个一个视角
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 );

        //设置视角离原点的位置(眼睛距离模型的距离)
        // camera.position.z = 700;
        camera.position.set(15,25,20);//设置相机位置
        camera.lookAt(new THREE.Vector3(0, 0, 0)); // 让相机指向原点

        //控制器
        controls = new THREE.TrackballControls( camera );
        //设置旋转速度
        controls.rotateSpeed = 3;

        // 使动画循环使用时阻尼或自转 意思是否有惯性
        controls.enableDamping = true;
        //是否可以缩放
        controls.enableZoom = true;
        //是否自动旋转
        controls.autoRotate = true;
        //设置相机距离原点的最近距离
        controls.minDistance = 500;
        //设置相机距离原点的最远距离
        controls.maxDistance = 2000;
        //是否开启右键拖拽
        controls.enablePan = true;

        // scene
        scene = new THREE.Scene();
        // const axesHelper = new THREE.AxesHelper();
        // scene.add(axesHelper);

        var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
        scene.add( ambientLight );
        var axesHelper = new THREE.AxesHelper(15);
        scene.add(axesHelper);

        var pointLight = new THREE.PointLight( 0xffffff, 0.8 );
        camera.add( pointLight );
        // pointLight.position.set(0,0,20100);
        // camera.position.set(10,10,10);
        // camera.lookAt(10,10,10);
        scene.add( camera );
        // var mesh=new THREE.Object3D (mtlLoader);//网格模型对象
        // scene.add(mesh);//网格模型添加到场景中
        renderer = new THREE.WebGLRenderer({antialias: false,
            alpha: true}); // 设置透明);
        // 设置分辨率
        renderer.setPixelRatio( window.devicePixelRatio );
        // 设置渲染尺寸
        renderer.setSize( window.innerWidth, window.innerHeight );
        container.appendChild( renderer.domElement );

        orbitControls = new THREE.OrbitControls(camera,renderer.domElement);
        orbitControls.enableDamping = true;
        orbitControls.enableZoom = true;
        orbitControls.autoRotate = false;
        orbitControls.autoRotateSpeed = 3;
        orbitControls.enablePan = true;
        orbitControls.enableKeys = true;
        orbitControls.keyPanSpeed = 7;
        orbitControls.keys = {
            LEFT:37,
            UP:38,
            RIGHT:39,
            BOTTOM:40
        }
        controls =orbitControls;

        // model  开始创建模型

        var onProgress = function ( xhr ) {

            if ( xhr.lengthComputable ) {

                var percentComplete = xhr.loaded / xhr.total * 100;
                console.log( Math.round( percentComplete, 2 ) + '% downloaded' );

            }

        };
        //报错通知
        var onError = function ( xhr ) {
            console.log("error!");
        };

        THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );

        // 加载mtl

        var mtlLoader=new THREE.MTLLoader()
            .setPath( './objmtl/' )
            .load( 'iron.mtl', function ( materials ) {

                materials.preload();

                // 加载obj
                new THREE.OBJLoader()
                    .setMaterials( materials )
                    .setPath( './objmtl/' )
                    .load( 'iron.obj', function ( object ) {
                        object.position.y = - 95;
                        console.log("print obj:" , object);
                        // object.children[0].geometry.center();
                        // 设置旋转中心点
                        object.children[0].geometry.computeBoundingBox();
                        // console.log("23123123", object.children[0].geometry.computeBoundingBox());

                        object.children[0].geometry.center();
                        // object.children[0].scale.set(200,200,200);
                        object.position.y = 0;
                        console.log("111",object.children[0].geometry.boundingBox.max.x,"ininn",object.children[0].geometry.boundingBox.min.x);
                        console.log("222",object.children[0].geometry.boundingBox.max.y,"ininn",object.children[0].geometry.boundingBox.min.y);
                        console.log("333",object.children[0].geometry.boundingBox.max.z,"ininn",object.children[0].geometry.boundingBox.min.z);
                        console.log("444",object.children[0].geometry.center());
                        // object.position.y = 0;
                        console.log("position()",object.position);
                        // object.scale.set(200,200,200);
                        object.position.set(0,0,0);
                        scene.add( object );
                        function animate() {
                            controls.update();

                            requestAnimationFrame( animate );
                        object.rotateY(0.1);//每次绕y轴旋转0.01弧度
                            renderer.render( scene, camera );
                        }
                        animate();
                    }, onProgress, onError );
            } );
        // 自适应监听
        window.addEventListener( 'resize', onWindowResize, false );
    }

    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize( window.innerWidth, window.innerHeight );
    }
    function onDocumentMouseMove( event ) {
        mouseX = ( event.clientX - windowHalfX ) / 2;
        mouseY = ( event.clientY - windowHalfY ) / 2;
    }
    function render() {
        camera.position.x += ( mouseX - camera.position.x ) * .05;
        camera.position.y += ( - mouseY - camera.position.y ) * .05;
        camera.lookAt( scene.position );
        renderer.render( scene, camera );
    }
    render();
</script>
</body>
</html>

下面是打印的log
在这里插入图片描述
可以看到模型已经加载完毕,且包围框的最大最小值都是有值的,且可以加载的obj模型打印出的log也差不多,但是我注意到一点,可以正常显示的obj模型的包围框的最大最小值是远大于上面那张显示不出的,见下图:
在这里插入图片描述
看111 222 333那几行的log可以看出要比第一张大很多,所以怀疑是不是由于模型太小了在Three.js的坐标系中无法找到(在obj文件中的v参数也可以看出这一点),于是向调整相机位置、放大模型,寻找模型中心点等操作,参考以下文章:
Three.js加载.obj和.mtl文件(无法加载材质、路径错误问题
vue+three.js导入obj模型不显示问题
使用three.js加载obj+mtl模型完整案例
尝试以上方法后仍然不能解决问题。ε=(´ο`*)))

3.是否可以单独加载obj模型

看log认为实际上已经加载进three.js了,博主偶然发现贴图指定错误后原来可以显示的模型也无法显示了,所以会不会贴图的问题?
于是博主修改代码,只加载obj不加载mtl文件,代码如下:

new THREE.OBJLoader()
		.setPath( './objmtl/' )
		.load( 'oursIron_original.obj', function ( object ) {
             object.position.y = - 95;
             object.children[0].geometry.computeBoundingBox();
             object.children[0].geometry.center();
             // object.children[0].scale.set(200,200,200);
             object.position.y = 0;            
             object.scale.set(4,4,4);
             object.position.set(0,0,0);
             scene.add( object );

发现竟然显示出来了,是一个没有贴图的白色模型,那也就是说是贴图问题导致obj在three.js中无法加载。

4.mtl文件有什么问题?

这里首先要了解mtl文件中各个参数的含义,这里参考博客:
obj文件、mtl文件结构说明
mtl文件详解
three.js 为obj模型设置mtl后模型不显示问题
重点是最后一篇博客,评论区有一条是:

打开mtl文件,删除TR  那一行的值即可(我的问题是这样解决的)

https://stackoverflow.com/questions/46916134/mesh-disappears-after-setting-material-obj-mtl-using-three-js
在这里插入图片描述
博主打开自己的mtl文件发现果然Tr值为1,Tr是透明度的意思。。。改为0后终于显示出来了!查看了其他加载不出来的模型的mtl文件发现Tr值都为1。。
在这里插入图片描述

结论

虽然最后解决问题的方式看起来简单,但是博主花了好大力气才知道这个解决办法,从一头雾水一点点排查也着实不容易,以此记录希望可以帮助到以后的同学,也非常感谢大家可以看到这里。
最后放上加载出来的模型截图:
在这里插入图片描述

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要在Three.js导入`.obj`模型并贴图,你可以使用`MTLLoader`和`OBJLoader`加载器,并在材质上应用纹理。 首先,确保你已经安装了所需的依赖项: ``` npm install three react-three-fiber ``` 然后,创建一个新的React组件来加载和渲染`.obj`模型: ```jsx import React, { useRef } from 'react'; import { Canvas, useLoader } from 'react-three-fiber'; import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader'; import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'; function Model() { const materials = useLoader(MTLLoader, '/path/to/model.mtl'); materials.preload(); const obj = useLoader(OBJLoader, '/path/to/model.obj'); const modelRef = useRef(); obj.setMaterials(materials); obj.position.y = -1; return <primitive object={obj} ref={modelRef} />; } function App() { return ( <Canvas> <ambientLight /> <pointLight position={[10, 10, 10]} /> <Model /> </Canvas> ); } export default App; ``` 在上面的代码中,我们首先导入了需要的加载器和组件。然后,在`Model`组件中,我们使用`useLoader`钩子加载`.mtl`文件,并预加载材质。 接下来,我们使用`useLoader`再次加载`.obj`文件,并创建一个模型引用。然后,我们将预加载的材质应用于模型,并设置模型的位置。 在`App`组件中,我们创建了一个基本的Three.js场景,并添加了环境光和点光源。然后,我们将`Model`组件放置在场景中以渲染模型。 请确保将`/path/to/model.mtl`和`/path/to/model.obj`替换为你实际模型文件和材质文件的路径。 这只是一个简单的示例,你可以根据需要进行修改和扩展。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值