我有一个模型的“.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但仍然不确定如何以叠加状态显示两者。我也不确定如何将纹理定位在网格上的特定位置。
答案 0 :(得分:19)
您有多种选择:
您可以使用画布工具在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
答案 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);
}