做有态度的前端团队

网易FEG前端团队

#ThreeJS学习笔记( 二)——导入外部模型

外部模型格式

Threejs支持了许多格式的3D模型导入,包括*.obj、 *.sea、*.3mf 、*.amf、*.sea、*.pmd、*.json等。
这里主要讲解一下obj模型的导入,及将obj文件转成文件更小的json格式导入。

导入obj模型

3Dmax格式转换成obj格式

美术提供的一般为3Dmax项目文件夹,里面包含了.max文件以及贴图图片等资源,用3DMAX打开.max文件可以看到3D模型
如图:

1469608235365.png

  • 点击菜单里的导出,选择obj格式,点击保存后出现选项
  • 导出比例:几何体选项里的输出比例,默认是1.0,我们根据模型的分辨率,以及需要在网页上呈现的分辨率设置一下比例输出即可。简单的说,你直接按1.0比例输出的如果在浏览器看的时候大小差距太大了,可以在这里导出比例设置一下,另外也可以设置mesh的scale,直接缩放。这个模型需要将比例设置为0.1。几何体的其他选项都不需要修改。
  • 材质:点击材质导出,勾选使用材质路径,选择保存材质的路径。格式为jpg,格式设置中可以设置导出jpg的质量,无特殊要求默认即可,并勾选转换位图,关闭材质设置。
  • 点击导出,导出过程有可能会提示找不到材质,设置材质路径为美术提供的文件夹目录即可
  • 最后会得到一个*.obj文件、一个*mtl文件、若干材质图,包括多个不同通道的贴图jpg和法线贴图jpg

1469608270416.png

1469608312275.png

1469608413927.png

1469610128497.png

导出obj后的二次处理

导出后的文件如图所示

1469613142241.png

其中,test.mtl文件定义了test.obj模型与各贴图间的对应关系。
由于示例中的模型是由多个子模型组成的模型组,同时设置了多通道贴图,每一个子模型都对应四张贴图。
打开mtl文件,我们可以看到每个子模型都有一组贴图数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
# 创建的文件:27.07.2016 17:00:50
 
newmtl JZ2012_jz_l_1 
    Ns 20.0000
    Ni 1.5000
    d 1.0000
    Tr 0.0000
    Tf 1.0000 1.0000 1.0000
    illum 2
    Ka 0.5882 0.5882 0.5882
    Kd 0.5882 0.5882 0.5882
    Ks 0.4500 0.4500 0.4500
    Ke 0.0000 0.0000 0.0000
    map_Ka JZ2012_jz_d.jpg
    map_Kd JZ2012_jz_d.jpg
    map_Ks JZ2012_jz_s.jpg
    map_Ke JZ2012_jz_e.jpg
    map_bump Map__171_法线凹凸.jpg
 
newmtl JZ2030_jz_l_1   
......

例如上面例子中关于子模型JZ2012_jz_l_1 贴图描述,其中map_Ka,map_Kd,map_Ks,map_Ke指定了各通道对应的贴图,map_bump则指定了法线贴图:

1469613671197.png

在使用threejs的mtlLoader解析mtl贴图并渲染为模型材质时,threejs仅调用map_Ka通道图片和map_bump法线贴图进行材质渲染。而基于图片数量及文件大小的控制,项目中采用的方法是让设计师将 JZ2012_jz_d.jpg、JZ2012_jz_s.jpg、JZ2012_jz_e.jpg三张图合成并调色后作为map_Ka通道贴图:

1469623501953.png

注:目前未查到threeJS 的mtl_loader是否能自动载入多通道贴图,待研究。
另外由于自动导出的法线贴图名称中带有中文,需要将mtl中map_bump和对应的法向贴图名称改成非中文命名。
在做以上图片处理时,需要同时将图片资源做压缩处理,以免资源加载时间过长。

使用mtlLoader和objLoaer加载obj模型及贴图

加载带mtl材质的obj模型,需要先定义mtl对象并加载mtl之外再加载obj模型。此时需要引用threejs两个js库

1
2
<script src="../js/lib/threejs/MTLLoader.js"></script>
<script src="../js/lib/threejs/OBJLoader.js"></script>

THREE.MTLLoader()函数说明:

  • mtlLoader.setBaseUrl():设置材质路径
  • mtlLoader.setPath():设置mtl文件所在路径
  • mtlLoader.load(filename,onSuccess(materials ),onProgress(xhr),onError(error)):mtl文件名、 加载成功后回调处理(参数为生成的材质库)、加载过程中回调处理(xhr对象属性可计算出已完成加载百分比)、失败回调处理

THREE.OBJLoader() 函数说明:

  • objLoader.setMaterials( materials ):设置obj使用的材质贴图
  • objLoader.setPath( options.objPath ):设置obj文件所在路径
  • objLoader.load( filename,onSuccess(object ),onProgress(xhr),onError(error)):obj文件名、 加载成功后回调处理(参数为生成的三维对象)、加载过程中回调处理(xhr对象属性可计算出已完成加载百分比)、失败回调处理。

在onSuccess(object ){}回调里我们可以对生成的三维对象做一些处理:对材质进行调色、设置透明度、设置贴图模式等,对设置旋转、缩放、位置摆放、自发光颜色、环境光颜色。
如果obj文件代表的三维对象是由多个子模型构成的模型组合,我们可以调用object.traverse(function(child){})来对每个子模型进行处理。
以下简单封装成一个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
function createMtlObj(options){
//      options={
//          mtlBaseUrl:"",
//          mtlPath:"",
//          mtlFileName:"",
//          objPath:"",
//          objFileName:"",
//          completeCallback:function(object){ 
//          }
//          progress:function(persent){
//             
//          }
//      }
    THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );
    var mtlLoader = new THREE.MTLLoader();
    mtlLoader.setBaseUrl( options.mtlBaseUrl );//设置材质路径
    mtlLoader.setPath( options.mtlPath );//设置mtl文件路径
    mtlLoader.load( options.mtlFileName, function( materials ) {
        materials.preload();
        var objLoader = new THREE.OBJLoader();
        objLoader.setMaterials( materials );//设置三维对象材质库
        objLoader.setPath( options.objPath );//设置obj文件所在目录
        objLoader.load( options.objFileName, function ( object ) {
             
             
            if(typeof options.completeCallback=="function"){
                options.completeCallback(object);
            }
        }, function ( xhr ) {
            if ( xhr.lengthComputable ) {
                var percentComplete = xhr.loaded / xhr.total * 100;
                if(typeof options.progress =="function"){
                    options.progress( Math.round(percentComplete, 2));
                }
                //console.log( Math.round(percentComplete, 2) + '% downloaded' );
            }
        }, function(error){
             
        });
 
    });
}

调用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
createMtlObj({
    mtlBaseUrl:"../resource/haven/",
    mtlPath: "../resource/haven/",
    mtlFileName:"threejs.mtl",
    objPath:"../resource/haven/",
    objFileName:"threejs.obj",
    completeCallback:function(object){
        object.traverse(function(child) {
            if (child instanceof THREE.Mesh) {
                child.material.side = THREE.DoubleSide;//设置贴图模式为双面贴图
                child.material.emissive.r=0;//设置rgb通道R通道颜色
                child.material.emissive.g=0.01;//设置rgb通道G通道颜色
                child.material.emissive.b=0.05;//设置rgb通道B通道颜色
                child.material.transparent=true;//材质允许透明
                //child.material.opacity=0;//材质默认透明度                       
                //child.material.shading=THREE.SmoothShading;//平滑渲染
            }
        });
        object.emissive=0x00ffff;//自发光颜色
        object.ambient=0x00ffff;//环境光颜色
//      object.rotation.x= 0;//x轴方向旋转角度
        object.position.y = 0;//位置坐标X
        object.position.z = 0;//位置坐标y
        object.scale.x=1;//缩放级别
        object.scale.y=1;//缩放级别
        object.scale.z=1;//缩放级别
        object.name="haven";//刚体名称
        object.rotation.y=-Math.PI;//初始Y轴方向旋转角度
        scene.add(object);//添加到场景中
    },
    progress:function(persent){
         
        $("#havenloading .progress").css("width",persent+"%");
    }
})

此时如果在之前没有添加光源,在浏览器上看到的可能是一片黑色,通过增加光源可以将物体显现出来。比例添加一个全局光

1
2
var ambient = new THREE.AmbientLight( 0xffffff );
scene.add( ambient );

此时在浏览器看到是这样的效果:
1470037673302.png

导入obj模型的后期渲染

如上图看到,我们导入的模型经过调色虽然比3Dmax显示效果好些,但仍然一片灰蒙蒙,丑不拉叽的。所以后期需要适当添加各种光源来渲染出更好的效果。
添加一个平行光做为主光源营造反射光面,并添加三个点光源对暗部适当补光后效果如下:

1
2
3
4
5
6
7
8
9
10
11
12
var directionalLight = new THREE.DirectionalLight( 0xffffff );
directionalLight.position.set( -5, 5, 5).normalize();
scene.add( directionalLight );
var pointlight = new THREE.PointLight(0x63d5ff, 1, 200);
pointlight.position.set(0, 0, 200);
scene.add( pointlight );               
var pointlight2 = new THREE.PointLight(0xffffff, 1, 200);
pointlight2.position.set(-200, 200, 200);
scene.add( pointlight2 );
var pointlight3 = new THREE.PointLight(0xffffff, 1.5, 200);
pointlight3.position.set(-200, 200, 0);
scene.add( pointlight3 );

1470039562664.png

接下再添加一个4000*4000*4000的天空盒子作为背景,并适当调整camera的可视范围,最后显示结果如下:

1470039862826.png

在设置点光源位置时可借助Threejs提供的helper来查看设置的点光源位置,方便调整光源位置

1
2
3
scene.add( new THREE.PointLightHelper( pointlight3 ) );
scene.add( new THREE.PointLightHelper( pointlight2 ) );
scene.add( new THREE.PointLightHelper( pointlight ) );

1470041255056.png

DEMO:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    <div id="space"></div
    <script   src="https://code.jquery.com/jquery-1.12.4.min.js"   integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="   crossorigin="anonymous"></script>
    <script src="../js/lib/threejs/three.js"></script>
    <script src="../js/lib/threejs/MTLLoader.js"></script>
    <script src="../js/lib/threejs/OBJLoader.js"></script>
    <script src="../js/lib/threejs/OrbitControls.js"></script>
    <script>
         
 
        var container, stats;
 
        var camera, scene, renderer;
 
        var mouseX = 0, mouseY = 0;
 
        var windowHalfX = window.innerWidth / 2;
        var windowHalfY = window.innerHeight / 2;
 
 
        init();
        animate();
        var mesh;
 
        function init() {
 
            container = document.getElementById("space")
            camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 8000 );
            camera.position.set(0, 0, 1500);
             
            scene = new THREE.Scene();
 
            var ambient = new THREE.AmbientLight( 0xffffff );
            scene.add( ambient );
             
             
            var directionalLight = new THREE.DirectionalLight( 0xffffff );
            directionalLight.position.set( -5, 5, 5).normalize();
            scene.add( directionalLight );
 
            var pointlight = new THREE.PointLight(0x63d5ff, 1, 200);
            pointlight.position.set(0, 0, 200);
            scene.add( pointlight );               
            var pointlight2 = new THREE.PointLight(0xffffff, 1, 200);
            pointlight2.position.set(-200, 200, 200);
            scene.add( pointlight2 );
            var pointlight3 = new THREE.PointLight(0xffffff, 1.5, 200);
            pointlight3.position.set(-200, 200, 0);
            scene.add( pointlight3 );
            scene.add( new THREE.PointLightHelper( pointlight3 ) );
            scene.add( new THREE.PointLightHelper( pointlight2 ) );
            scene.add( new THREE.PointLightHelper( pointlight ) );
         
             
            var path = "../resource/sky/";
            var format = '.jpg';
            var urls = [
                    path + 'px' + format, path + 'nx' + format,
                    path + 'py' + format, path + 'ny' + format,
                    path + 'pz' + format, path + 'nz' + format
                ];
            var skyMaterials = [];
            for (var i = 0; i < urls.length; ++i) {
                var loader = new THREE.TextureLoader();
                loader.setCrossOrigin( this.crossOrigin );
                var texture = loader.load( urls[i], function(){}, undefined, function(){} );
                 
                skyMaterials.push(new THREE.MeshBasicMaterial({
                    //map: THREE.ImageUtils.loadTexture(urls[i], {},function() { }),
                    map: texture,
                    overdraw: true,
                    side: THREE.BackSide,
                    //transparent: true,
                    //needsUpdate:true,
                    premultipliedAlpha: true
                    //depthWrite:true,
                     
    //              wireframe:false,
                })
                );
                 
            }
             
            var cube = new THREE.Mesh(new THREE.CubeGeometry(4000, 4000,4000), new THREE.MeshFaceMaterial(skyMaterials));
            cube.name="sky";
            scene.add(cube);
             
            createMtlObj({
                mtlBaseUrl:"../resource/haven/",
                mtlPath: "../resource/haven/",
                mtlFileName:"threejs.mtl",
                objPath:"../resource/haven/",
                objFileName:"threejs.obj",
                completeCallback:function(object){
                    object.traverse(function(child) {
                        if (child instanceof THREE.Mesh) {
                            child.material.side = THREE.DoubleSide;
                            child.material.emissive.r=0;
                            child.material.emissive.g=0.01;
                            child.material.emissive.b=0.05;
                            child.material.transparent=true;
                            //child.material.opacity=0;                    
                            //child.material.shading=THREE.SmoothShading;
                        }
                    });
 
                    object.emissive=0x00ffff;
                    object.ambient=0x00ffff;
                    //object.rotation.x= 10/180*Math.PI;
                    object.position.y = 0;
                    object.position.z = 0;
                    object.scale.x=1;
                    object.scale.y=1;
                    object.scale.z=1;
                    object.name="haven";
                    object.rotation.y=-Math.PI;
                    scene.add(object);
                },
                progress:function(persent){
                     
                    $("#havenloading .progress").css("width",persent+"%");
                }
            })
            renderer = new THREE.WebGLRenderer();
            renderer.setPixelRatio( window.devicePixelRatio );
            renderer.setSize( window.innerWidth, window.innerHeight );
            container.appendChild( renderer.domElement );
            document.addEventListener( 'mousemove', onDocumentMouseMove, false );
            window.addEventListener( 'resize', onWindowResize, false );
        }
         
        var controls = new THREE.OrbitControls(camera,container);
        //controls.maxPolarAngle=1.5;
        //controls.minPolarAngle=1;
        controls.enableDamping=true;
        controls.enableKeys=false;
        controls.enablePan=false;
        controls.dampingFactor = 0.1;
        controls.rotateSpeed=0.1;
//      controls.enabled = false;
        //controls.minDistance=1000;
        //controls.maxDistance=3000;
        function createMtlObj(options){
        //      options={
        //          mtlBaseUrl:"",
        //          mtlPath:"",
        //          mtlFileName:"",
        //          objPath:"",
        //          objFileName:"",
        //          completeCallback:function(object){ 
        //          }
        //          progress:function(persent){
        //             
        //          }
        //      }
                //THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );
            var mtlLoader = new THREE.MTLLoader();
            mtlLoader.setBaseUrl( options.mtlBaseUrl );
            mtlLoader.setPath( options.mtlPath );
            mtlLoader.load( options.mtlFileName, function( materials ) {
                materials.preload();
                var objLoader = new THREE.OBJLoader();
                objLoader.setMaterials( materials );
                objLoader.setPath( options.objPath );
                objLoader.load( options.objFileName, function ( object ) {
                    if(typeof options.completeCallback=="function"){
                        options.completeCallback(object);
                    }
                }, function ( xhr ) {
                    if ( xhr.lengthComputable ) {
                        var percentComplete = xhr.loaded / xhr.total * 100;
                        if(typeof options.progress =="function"){
                            options.progress( Math.round(percentComplete, 2));
                        }
                        //console.log( Math.round(percentComplete, 2) + '% downloaded' );
                    }
                }, function(error){
                     
                } );
         
            });
        }
        function onWindowResize() {
            windowHalfX = window.innerWidth / 2;
            windowHalfY = window.innerHeight / 2;
            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 animate() {
            requestAnimationFrame( animate );
            render();
        }
        function render() {
//              camera.position.x += ( mouseX - camera.position.x ) ;
//              camera.position.y += ( mouseY - camera.position.y ) ;
            camera.lookAt( scene.position );
            renderer.render( scene, camera );
 
        }
         
    </script>
    </body>
</html>

使用jsonLoader加载3D模型

threejs提供了对json格式的支持,相对obj格式的文件来说要小很多,可以提高模型的加载速度。
将obj文件转为了json格式需要借助一个软件:blender以及THREEJS提供的插件io_three;
软件下载地址:https://www.blender.org/
io_three插件在three代码包里的路径:three.js-master/utils/exporters/blender/addons

安装插件的方法

  • 将io_three 复制到blender安装目录下的addons目录中,如:D:\blender-2.77a-windows64\2.77\scripts\addons
  • 打开blender,点击菜单->用户设置,向下拖动保存用户设置按钮所在的区域,会显示所有的用户设置内容
  • 选择add-ons选项卡,在左侧搜索框输入three ,将右侧出现的结果勾选上,到此则已经启用该插件。

1470192336842.png

转换格式

  • 在blender中新建 一个项目,删除默认添加的正方体等对象
  • 切换回info菜单栏,点击文件->导入->*.obj,选择obj之后,blender中会显示模型
  • 点击文件->导出->Threejs(.json),保存为haven.json,存储到材质所在的路径。导出设置如下:

1470209341377.png

使用JsonLoader载入json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var loader = new THREE.JSONLoader();
loader.load( '../resource/haven/haven.json', function ( geometry, materials ) {
    var object = new THREE.Mesh( geometry, materials[0] );
    object.material.side = THREE.DoubleSide;
    object.material.emissive.r=0;
    object.material.emissive.g=0.01;
    object.material.emissive.b=0.05;
    object.material.transparent=true;
    //object.material.opacity=0;                       
    object.material.shading=THREE.SmoothShading;
    object.position.y = 0;
    object.position.z = 0;
    object.scale.x=1;
    object.scale.y=1;
    object.scale.z=1;
    scene.add(object);
})

这时我们看到的图像是这样的

1470209408071.png

是的,没错,blender只能将当前选中的单个模型导出json文件,我们使用的obj文件是由多个子模型构成的模型组合,需要对每个子模型单独导出为json文件,并在页面中使用jsonLoader单独载入。

手机阅读请扫描下方二维码:

分享到:

    已有 36 条评论

    1. 有在线预览地址吗? 我教程走 根本没用啊……
      报错
      Uncaught TypeError: Cannot read property 'visible' of undefined
      at p (three.min.js:134)
      at p (three.min.js:134)
      at Xd.render (three.min.js:173)
      at render (main.js?v=fsd:195)
      at animate (main.js?v=fsd:189)

      1. ubee

        我的代码里没有设置visible属性的,看一下是否你自己的代码里main属性里的animate方法里的脚本是否有多余的设置

    2. h.g.

      咨询一个问题,向blender导入文件的时候,为什么就只导入模型,没有图片。这样模型没有皮肤。很奇怪。

    3. [...]http://feg.netease.com/archives/301.html[...]

    4. test

    5. bjzhangzhilei

      你好,我是北京网易传媒的,有个3dmax方面的问题请教一下,你们3dmax贴图的材质球是用的默认扫描线渲染器下的材质球吗?但是看你们的mtl文件中的代码,是newmtl,这个应该是mental rey或v-rey渲染器下的名字,我用这两个渲染器下的材质球,导出obj时,贴图导不出来,只能在默认扫描线渲染器下的材质球导出obj才能导出贴图。这是我遇到的问题以及总结http://jingyan.baidu.com/article/fec7a1e5d9e7011190b4e7b6.html,我觉得您是用插件渲染器导出的贴图,求指教,谢谢啦!

      1. bjzhangzhilei

        找到答案了,已经解决!

        1. ubee

          3Dmax是由美术同学提供的。具体用哪个渲染器我就不知道了

        2. yang61591

          找到什么答案可以分享么~最近也踩了你说的坑 ali-43.gif

        3. JsonDiv

          天啦噜,找到答案了也不说一下,还出来炫耀一下。。。 ali-45.gif

      2. ubee

        这个问题,obj本身不带贴图,需要mtl同时导入,另外导出obj+mtl时,如果贴图路径没设置正确,可以用文本编辑器打开mtl文件,把图片路径修改为项目的相对路径。
        单独导入obj是没有贴图的。如果只有obj可以用threejs的textureload导入贴图,并在导入obj后, 把obj的mesh.materital设置为导入的贴图。

        1. zm10

          您好,我导出obj格式后,没有导出贴图文件,mtl文件中也没有贴图路径是为什么呢

        2. 张志龙

          你好,请问将单独的obj文件导入threejs中,贴图的时候只会改变obj 的颜色而看不到实际的纹理,可能在那些方面出问题?

    6. ubee

      我的代码里没有设置visible属性的,看一下是否你自己的代码里main属性里的animate方法里的脚本是否有多余的设置

    7. 翟浩

      能否给demo包,新手求老司机领路 ali-52.gif

      1. ubee

        直接上threejs.org上找就可以了
        加载obj的是这个 demo
        https://threejs.org/examples/?q=obj#webgl_loader_obj_mtl

    8. leovan

      能否给个demo包,新手求老司机带路

      1. ubee

        直接上threejs.org上找就可以了
        加载obj的是这个 demo
        https://threejs.org/examples/?q=obj#webgl_loader_obj_mtl

    9. inuyasha1981

      想请教一个问题,three.js 导入 Obj 时,如果 Obj 本身是带有分组的,会把分组下的原件重复添加进去。比如在3D建模中,Room作为一个模型,编组下面有 Desk 对象。那么 three.js 导入 obj 后,Desk 这个对象会被导入两次,生成一个 Desk_1。这个怎么解决?如果不在建模时分组,那么我又怎么样在导入 Obj 之后把 Desk 和 Room 重新编组呢?例如 Room.add(Desk); 这样的形式。希望有时间的话可以回复,谢谢。

      1. ubee

        你这个room应该只是一个group,你可以只循环mesh添加,或者只添加group,这样就只会导入一次,重新编组,可以var g=new THREE.Group(); g.add(mesh1);g.add(mesh2),这样子,mesh1 和mesh2的position参考系就以g的中心点为原点。

    10. zhang

      问一下,max2012导出obj包含贴图并转换格式之后,如dds转tga。dds转xxx,导出的贴图都变暗了。用2010的倒是没问题。另外 使用obj导出的贴图不能带通道吗?源贴图是有通道的,导出之后通道就消失了? ali-45.gif

      1. ubee

        我之前也遇过这个问题,后来发现threejs只贴了一个通道的图,最后我只能把所有的通道都合并成一张图,或者使用lightMAP来贴光影图。

      2. ubee

        用ligthMAP还需要把UV展开,搞2层uv,在原来的uv上贴上默认贴图,在uv2上贴光影图。而obj不支持2UV,只能blender加载包含2uv的模型,然后导出带2uv信息的json,再用threejs导入json。

    11. 不吃火锅底料

      你好,请问下如果我要加载不同的obj模型,建模出来的obj模型大小位置都不统一,这时候不能把camera的位置写死吧,该如何做到设置camera位置适配不同的模型啊

      1. ubee

        建议调整模型的position 和scale 来统一,而不调整camera。调camera的位置更难统一视觉效果。。

    12. 好厉害呀,学习一下

    13. D_R_M

      好文

    14. asd

    15. 阿辛

      非常感谢 ali-43.gif

    16. guagua123

      你好,我最近刚学threejs,在加载了包含贴图的mtl时爆了错误,Handlers.get() has been removed. Use LoadingManager.getHandler() instead.和这个错误Cannot read property 'setCrossOrigin' of undefined,这个错误是什么原因导致的呢?我怀疑是贴图路径的原因,但是路径我已经改为英文的了,还是报这个错误,有哪位大佬能帮我解惑 ali-61.gif

      1. guoguo

        我也遇到了这个问题 求问怎么解决

    17. 1

      1 ali-40.gif ali-40.gif ali-41.gif ali-41.gif ali-42.gif ali-42.gif ali-43.gif ali-43.gif ali-44.gif ali-44.gif ali-45.gif ali-45.gif ali-46.gif ali-46.gif ali-47.gif ali-47.gif ali-48.gif ali-48.gif ali-49.gif ali-49.gif ali-50.gif ali-50.gif ali-51.gif ali-51.gif ali-52.gif ali-52.gif ali-53.gif ali-53.gif ali-54.gif ali-54.gif ali-55.gif ali-55.gif ali-56.gif ali-56.gif ali-57.gif ali-57.gif ali-58.gif ali-58.gif ali-59.gif ali-59.gif ali-60.gif ali-60.gif ali-61.gif ali-61.gif

    18. 1

      1 ali-40.gif ali-40.gif ali-41.gif ali-41.gif ali-42.gif ali-42.gif ali-43.gif ali-43.gif ali-44.gif ali-44.gif ali-45.gif ali-45.gif ali-46.gif ali-46.gif ali-47.gif ali-47.gif ali-48.gif ali-48.gif ali-49.gif ali-49.gif ali-50.gif ali-50.gif ali-51.gif ali-51.gif ali-52.gif ali-52.gif ali-53.gif ali-53.gif ali-54.gif ali-54.gif ali-55.gif ali-55.gif ali-56.gif ali-56.gif ali-57.gif ali-57.gif ali-58.gif ali-58.gif ali-59.gif ali-59.gif ali-60.gif ali-60.gif ali-61.gif ali-61.gif

    添加新评论

    ali-40.gifali-41.gifali-42.gifali-43.gifali-44.gifali-45.gifali-46.gifali-47.gifali-48.gifali-49.gifali-50.gifali-51.gifali-52.gifali-53.gifali-54.gifali-55.gifali-56.gifali-57.gifali-58.gifali-59.gifali-60.gifali-61.gif