Three.js 在通过 OBJMTLLoader 加载的对象上的多种材质
Posted
技术标签:
【中文标题】Three.js 在通过 OBJMTLLoader 加载的对象上的多种材质【英文标题】:Three.js multiple materials on object loaded via OBJMTLLoader 【发布时间】:2013-05-22 18:37:14 【问题描述】:我有一个模型的“.obj”和“.mtl”文件,我正在通过OBJMTLLoader
加载它。 ".mtl" 指定要应用于模型的纹理,three.js 加载模型并使用应用的纹理进行渲染。
但事情就是这样。
加载一个对象后,我想在其上应用另一个纹理。这是因为第一纹理代表物体的表面材料。第二个纹理是一张图纸,我想将其放置在模型上的特定位置。
我的问题是:如何将第二个纹理应用到已加载(和纹理化)的对象上?
我看到three.js 创建了一个THREE.Object3D
的实例,并且该实例有一个带有THREE.Mesh
实例的“子”数组。
当我尝试将纹理应用到该网格 (mesh.material.map = texture
) 时,我失去了初始纹理。
我查看了这个question about applying multiple textures and JSONLoader,但没有找到答案。
我也尝试过使用new THREE.MeshFaceMaterial( materials )
(如this answer 中所建议的那样)但没有成功。
更新:
我尝试了@WestLangley 使用多材质对象的建议,但仍然无法在另一种材质之上渲染一种材质。
我做了这个简单的演示,改编自three.js OBJLoader — http://dl.dropboxusercontent.com/u/822184/webgl_multiple_texture/index.html
我按照建议使用THREE.SceneUtils.createMultiMaterialObject
,传递从.obj 加载的主网格的克隆几何图形。我还为其提供了 2 种纹理——一种用于整个表面,另一种用于模型的前表面。
但这不起作用。我添加了 2 个复选框来切换相应材料的“可见”属性。您可以看到材料存在,但我无法从第二个下方看到第一个。
加载/渲染的关键如下:
var texture = THREE.ImageUtils.loadTexture('fabric.jpg');
var texture2 = THREE.ImageUtils.loadTexture('table.jpg');
texture2.offset.set(-0.65, -2.5);
texture2.repeat.set(4, 4);
var loader = new THREE.OBJLoader();
loader.addEventListener( 'load', function ( event )
var mainMesh = event.content.children[0].children[0];
multiMaterialObject = THREE.SceneUtils.createMultiMaterialObject(
mainMesh.geometry.clone(), [
new THREE.MeshLambertMaterial( map: texture2 ),
new THREE.MeshLambertMaterial( map: texture )
]);
multiMaterialObject.position.y = -80;
scene.add(multiMaterialObject);
);
loader.load( 'male02.obj' );
更新 #2
在这一点上,我认为最好的办法是使用THREE.ShaderMaterial
将一个纹理应用到另一个上。我看到了一些examples of using one texture,但仍然不确定如何以重叠状态显示两者。我也不确定如何在网格上的特定位置定位纹理。
【问题讨论】:
类似问题(遗憾的是目前没有任何可靠的解决方案)-***.com/questions/12494781/… 您是否找到了将第二个纹理定位在网格上特定位置的解决方案?我遇到了同样的问题,我可以使用 ShaderMaterial 将纹理渲染到另一个纹理上,但我很难理解定位的工作原理。 【参考方案1】:您有多种选择:
您可以使用画布工具在 javascript 端混合图像,并使用单个纹理贴图创建单个材质。
您可以从单个几何体和一组材质创建多材质对象。 (这种方法只是创建多个相同的网格,每个网格都有一种材质,通常在其中一种材质是线框时使用。如果一种材质是透明的,它也可以正常工作。)
THREE.SceneUtils.createMultiMaterialObject( geometry, materials );
您可以使用自定义ShaderMaterial
实现多纹理效果。有两个纹理输入,并在着色器中实现颜色混合。
这里是实现混合两种纹理的最简单的three.js ShaderMaterial
示例:https://jsfiddle.net/6bg4qdhx/3/。
编辑:另见Is there a built-in way to layer textures within the standard PBR shader?
three.js r.92
【讨论】:
谢谢!如果我要走第二条路线——多材质对象——我将如何处理已经创建的对象(因为 loader 为我做了这个)?我假设THREE.SceneUtils.createMultiMaterialObject
创建了一个对象。有办法修改吗?
实际上,我看到createMultiMaterialObject
中发生了什么。就像你说的,它使用每种材料创建网格。我想如果我将另一个孩子添加到该加载器创建的THREE.Object3D
实例中,并给它另一个纹理,那应该可以吗?嗯,我会试试的。再次感谢!
我尝试了您的第二种方法,但没有成功。请参阅有问题的更新。我错过了什么吗?
第二种方法仅在其中一种材料是透明的情况下才有效。 multiMaterialObject.children[0].material.transparent = true
,multiMaterialObject.children[0].material.opacity = 0.5
。就像我说的,它通常在其中一种材料是线框时使用。
没问题。我会将进一步的问题转移到单独的问题中。着色器示例是我需要澄清的主要内容。再次感谢。【参考方案2】:
您加载的对象具有几何体(及其顶点、面和 UV)和材质。 创建 ShaderMaterial,以某种适合您的方式组合纹理,并使用加载对象的几何体创建网格。
使用 ShaderMaterial 并将两个纹理设置为统一,然后在着色器中混合它们。
所以,你制作 ShaderMaterial:
var vertShader = document.getElementById('vertex_shh').innerHTML;
var fragShader = document.getElementById('fragment_shh').innerHTML;
var attributes = ; // custom attributes
var uniforms = // custom uniforms (your textures)
tOne: type: "t", value: THREE.ImageUtils.loadTexture( "cover.png" ) ,
tSec: type: "t", value: THREE.ImageUtils.loadTexture( "grass.jpg" )
;
var material_shh = new THREE.ShaderMaterial(
uniforms: uniforms,
attributes: attributes,
vertexShader: vertShader,
fragmentShader: fragShader
);
并使用该材料创建网格:
var me = new THREE.Mesh( my_loaded_model, material_shh ); // you previously loaded geometry of the object
你可以放最简单的顶点着色器:
varying vec2 vUv;
void main()
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
以及真正进行混合的片段着色器:
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D tOne;
uniform sampler2D tSec;
varying vec2 vUv;
void main(void)
vec3 c;
vec4 Ca = texture2D(tOne, vUv);
vec4 Cb = texture2D(tSec, vUv);
c = Ca.rgb * Ca.a + Cb.rgb * Cb.a * (1.0 - Ca.a); // blending equation or wahtever suits you
gl_FragColor= vec4(c, 1.0);
【讨论】:
@kangax,这是你需要的吗?以上是关于Three.js 在通过 OBJMTLLoader 加载的对象上的多种材质的主要内容,如果未能解决你的问题,请参考以下文章
谁有three.js的loader扩展包下载地址 或者给我发一下 谢谢 我需要objmtlload
THREE.js Ray Intersect 通过添加 div 失败