通过OBJMTLLoader加载对象的三个.js多个材质

时间:2013-05-27 22:00:25

标签: javascript three.js textures mesh

我有一个模型的“.obj”和“.mtl”文件,我正在通过OBJMTLLoader加载它。 “.mtl”指定要应用于模型的纹理,并且three.js加载模型并使用应用的纹理渲染它就好了。

但这就是事情。

加载一个对象后,我想在其上应用另一个纹理。这是因为第一纹理表示对象的表面材质。第二个纹理是一个绘图,我想定位在模型的特定位置。

我的问题是:如何将第二个纹理应用到已加载(和纹理化)的对象上?

我看到three.js创建了一个THREE.Object3D的实例,该实例有一个“children”数组,其中一个实例为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但仍然不确定如何以叠加状态显示两者。我也不确定如何将纹理定位在网格上的特定位置。

2 个答案:

答案 0 :(得分:19)

您有多种选择:

  1. 您可以使用画布工具在javascript端混合图像,并使用单个纹理贴图创建单个材质。

  2. 您可以从单个几何体和材质数组创建多材质对象。 (这种方法只创建了多个相同的网格,每个网格都有一种材质,通常在其中一种材质为线框时使用。如果一种材质是透明的,它也可以正常工作。)

    THREE.SceneUtils.createMultiMaterialObject( geometry, materials );

  3. 您可以使用自定义ShaderMaterial实现多纹理效果。有两个纹理输入,并在着色器中实现颜色混合。

  4. 这里有一个关于可能实现两个纹理混合的最简单的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

答案 1 :(得分:3)

您加载的对象具有几何体(及其顶点,面和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);
}