javascript 通过 OBJMTLLoader 加载对象上的 Three.js 多种材料
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16781064/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Three.js multiple materials on object loaded via OBJMTLLoader
提问by kangax
I have ".obj" and ".mtl" files of a model and I'm loading it via OBJMTLLoader
. ".mtl" specifies texture to apply to a model, and three.js loads model and renders it with applied texture just fine.
我有一个模型的“.obj”和“.mtl”文件,我正在通过 .obj 文件加载它OBJMTLLoader
。“.mtl”指定应用于模型的纹理,而three.js加载模型并使用应用的纹理渲染它就好了。
But here's the thing.
但事情是这样的。
Once an object is loaded, I would like to apply another texture onto it. This is because first texture represents surface material of an object. And second texture is a drawing, that I'd like to position at a specific location on a model.
加载对象后,我想在其上应用另一个纹理。这是因为第一个纹理代表对象的表面材料。第二个纹理是一张图纸,我想将其放置在模型的特定位置。
My question is: how to apply a second texture onto already loaded (and texturized) object?
我的问题是:如何将第二个纹理应用到已加载(和纹理化)的对象上?
I see that three.js creates an instance of THREE.Object3D
, and that instance has "children" array with one instance of THREE.Mesh
.
我看到 Three.js 创建了一个 的实例THREE.Object3D
,并且该实例具有带有一个实例的“子”数组THREE.Mesh
。
When I try to apply a texture to that mesh (mesh.material.map = texture
), I lose initial texture.
当我尝试将纹理应用于该网格 ( mesh.material.map = texture
) 时,我丢失了初始纹理。
I looked into this question about applying multiple textures and JSONLoaderbut didn't find an answer.
我研究了这个关于应用多个纹理和 JSONLoader 的问题,但没有找到答案。
I also tried using new THREE.MeshFaceMaterial( materials )
(as suggested in this answer) but unsuccessfully.
我也尝试使用new THREE.MeshFaceMaterial( materials )
(如本答案中所建议的那样)但没有成功。
UPDATE:
更新:
I tried @WestLangley's suggestion to use multi-material object, but am still unable to render one material on top of another one.
我尝试了@WestLangley 的使用多材质对象的建议,但仍然无法在另一种材质之上渲染一种材质。
I made this simple demo, adapted from three.js OBJLoader — http://dl.dropboxusercontent.com/u/822184/webgl_multiple_texture/index.html
我做了这个简单的演示,改编自three.js OBJLoader—— http://dl.dropboxusercontent.com/u/822184/webgl_multiple_texture/index.html
I'm using THREE.SceneUtils.createMultiMaterialObject
as suggested, passing it cloned geometry of main mesh loaded from .obj. I'm also giving it 2 textures — one for entire surface, another one — for front surface of the model.
我THREE.SceneUtils.createMultiMaterialObject
按照建议使用,传递从 .obj 加载的主网格的克隆几何。我还为它提供了 2 个纹理——一个用于整个表面,另一个用于模型的前表面。
But this doesn't work. I added 2 checkboxes that toggle "visible" property of corresponding materials. You can see that materials are present, but I can't see the first one from beneath second one.
但这不起作用。我添加了 2 个复选框来切换相应材料的“可见”属性。您可以看到材料存在,但我无法从第二个下方看到第一个。
The crux of the loading/rendering is as follows:
加载/渲染的关键如下:
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' );
UPDATE #2
更新 #2
At this point, I think the best bet is to use THREE.ShaderMaterial
to apply one texture onto another. I see some examples of using one texturebut still unsure how to display both in overlaid state. I'm also not sure how to position texture at a specific location on a mesh.
在这一点上,我认为最好的办法是THREE.ShaderMaterial
将一种纹理应用到另一种纹理上。我看到了一些使用一种纹理的例子,但仍然不确定如何在重叠状态下显示两者。我也不确定如何在网格上的特定位置定位纹理。
回答by WestLangley
You have several choices:
您有多种选择:
You can mix the images on the javascript side using canvas tools, and create a single material with a single texture map.
You can create a multi-material object from a single geometry and an array of materials. (This approach just creates multiple identical meshes, each with one of the materials, and usually is used when one of the materials is wireframe. It may also work OK if one material is transparent.)
THREE.SceneUtils.createMultiMaterialObject( geometry, materials );
You can achieve a multi-texture effect with a custom
ShaderMaterial
. Have two texture inputs, and implement color mixing in the shader.
您可以使用画布工具在 javascript 端混合图像,并使用单个纹理贴图创建单个材质。
您可以从单个几何体和一系列材料创建多材料对象。(这种方法只是创建多个相同的网格,每个网格都有一种材料,通常在其中一种材料是线框时使用。如果一种材料是透明的,它也可以正常工作。)
THREE.SceneUtils.createMultiMaterialObject( geometry, materials );
您可以使用自定义
ShaderMaterial
. 有两个纹理输入,并在着色器中实现颜色混合。
Here an example of just about the simplest three.js ShaderMaterial
possible that implements mixing of two textures: https://jsfiddle.net/6bg4qdhx/3/.
这是一个ShaderMaterial
实现两种纹理混合的最简单的 Three.js 示例:https: //jsfiddle.net/6bg4qdhx/3/ 。
EDIT: Also see Is there a built-in way to layer textures within the standard PBR shader?
编辑:另请参阅是否有一种内置方法可以在标准 PBR 着色器中对纹理进行分层?
three.js r.92
三.js r.92
回答by Abstract Algorithm
Your loaded object has geometry (along with its vertices, faces and UVs) and material. Create ShaderMaterial that combines the textures in some way that suits you and create mesh with geometry from loaded object.
您加载的对象具有几何体(及其顶点、面和 UV)和材质。创建以适合您的方式组合纹理的 ShaderMaterial,并从加载的对象创建具有几何体的网格。
Use ShaderMaterial and set both textures as uniforms, and then blend them within shader.
使用 ShaderMaterial 并将两个纹理设置为统一,然后在着色器中混合它们。
So, you make 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
});
And create mesh with that material:
并使用该材料创建网格:
var me = new THREE.Mesh( my_loaded_model, material_shh ); // you previously loaded geometry of the object
You can put simplest vertex shader:
您可以放置最简单的顶点着色器:
varying vec2 vUv;
void main()
{
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
And fragment shader that will actually do the blending:
和实际进行混合的片段着色器:
#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);
}