使用 GLTF 的混合材质/纹理支持
Blended materials / textures support using GLTF
在进入问题之前,我想强调一下,在 3D 建模、纹理和渲染技术方面,我远不是专家。我知道一些基础知识,但如果我的方法一开始就错了,请告诉我。
此外,请原谅缺少嵌入图像。 Whosebug 要求我先获得 10 个声望...
问题
我目前正在从事一个涉及管道的项目,其中模型在 Blender (2.80 Beta) 中创建,导出为 GLTF using these export settings,然后导入在 three.js 0.102.1。这适用于大多数模型。但是,当我想导出我的地形模型时,materials 没有按预期导出(或者可能导入)。
由于这是地形,因此首选多个纹理(或更好,materials),在它们相交的地方混合它们。当然,这 可以 对整个地形使用一个巨大的纹理来完成,但是使用多个纹理的美妙之处在于您只需在整个地形上重复它们,并使用遮罩来确定混合。您无需创建巨大的单一纹理即可保持高水平的细节。
为什么我认为 GLTF 是瓶颈
这不是 Blender:
在 Blender 中,贴图看起来不错,material按预期混合:
Blending of grass and dirt
使用以下节点设置:
Material node graph
不是three.js:
我使用 NodeMaterials 在 three.js 中创建了一个类似的 material 设置:
// MATERIAL
let mtl = new THREE.StandardNodeMaterial();
mtl.roughness = new THREE.FloatNode( .9 );
mtl.metalness = new THREE.FloatNode( 0 );
function createUv(scale, offset) {
let uvOffset = new THREE.FloatNode( offset || 0 );
let uvScale = new THREE.FloatNode( scale || 1 );
let uvNode = new THREE.UVNode();
let offsetNode = new THREE.OperatorNode(
uvOffset,
uvNode,
THREE.OperatorNode.ADD
);
let scaleNode = new THREE.OperatorNode(
offsetNode,
uvScale,
THREE.OperatorNode.MUL
);
return scaleNode;
}
let grass = new THREE.TextureNode( getTexture("grass"), createUv(35) );
let dirt = new THREE.TextureNode( getTexture("dirt"), createUv(35) );
let mask = new THREE.TextureNode( getTexture("mask"), createUv() );
let maskAlphaChannel = new THREE.SwitchNode(mask, "w");
let blend = new THREE.Math3Node(
grass,
dirt,
maskAlphaChannel,
THREE.Math3Node.MIX
);
mtl.color = blend;
mtl.normal = new THREE.NormalMapNode(
new THREE.TextureNode( getTexture("dirtNormal"), createUv(35) )
);
let normalMask = new THREE.OperatorNode(
new THREE.TextureNode( getTexture("mask"), createUv() ),
new THREE.FloatNode(1),
THREE.OperatorNode.MUL
);
mtl.normalScale = normalMask;
// build shader
mtl.build();
// set material
return mtl;
结果如下,看起来相当不错的地形(这是在我的 three.js 项目中):
Properly textured terrain
Proper blending
所以我猜是 GLTF?
当然,可能是 exporter 或 importer 失败了。
- 将 GLTF 导入 Blender 得到与 three.js 相同的结果(黑色地形带有白色高光,污垢应该去的地方),所以我怀疑这就是问题所在。
- 我对导出一窍不通,所以问题可能出在这里。
此外,当我试图阅读和理解 GLTF 2.0 规范时,我在 material 或纹理规范中没有看到任何允许混合或混合的内容。
我还遇到了 KHR_technique_webgl
扩展,它也可能解决这个问题,尽管我不确定具体细节。
结论
因为我真的很想避免硬编码解决方案或使用单一的巨型纹理,GLTF 仍然是我的选择。那么,我是否遗漏了我的管道中的任何东西?此时是否可以在这种情况下使用 GLTF?作品中有什么支持这样的 material 吗?
任何形式的见解都将不胜感激。谢谢。
附加链接:
不幸的是,在撰写本文时,没有任何格式可以导出来保留来自 Blender 的自定义节点图并将其导入实时引擎。您可以为每个 Principled BSDF 套接字一个纹理。如果有帮助,glTF 导出器中有一个选项可以包含纹理变换(旋转、缩放、重复)。
对于这样的自定义内容,我建议为您的材料添加名称和自定义属性(文本或数字)。在导出设置中启用“导出自定义属性/额外”,这些将作为 material.userData
传递到 threejs,您可以从中重建节点图。
我知道它的旧 post,但我发现 Blender 导出不混合节点。
在进入问题之前,我想强调一下,在 3D 建模、纹理和渲染技术方面,我远不是专家。我知道一些基础知识,但如果我的方法一开始就错了,请告诉我。
此外,请原谅缺少嵌入图像。 Whosebug 要求我先获得 10 个声望...
问题
我目前正在从事一个涉及管道的项目,其中模型在 Blender (2.80 Beta) 中创建,导出为 GLTF using these export settings,然后导入在 three.js 0.102.1。这适用于大多数模型。但是,当我想导出我的地形模型时,materials 没有按预期导出(或者可能导入)。
由于这是地形,因此首选多个纹理(或更好,materials),在它们相交的地方混合它们。当然,这 可以 对整个地形使用一个巨大的纹理来完成,但是使用多个纹理的美妙之处在于您只需在整个地形上重复它们,并使用遮罩来确定混合。您无需创建巨大的单一纹理即可保持高水平的细节。
为什么我认为 GLTF 是瓶颈
这不是 Blender:
在 Blender 中,贴图看起来不错,material按预期混合:
Blending of grass and dirt
使用以下节点设置:
Material node graph
不是three.js:
我使用 NodeMaterials 在 three.js 中创建了一个类似的 material 设置:
// MATERIAL
let mtl = new THREE.StandardNodeMaterial();
mtl.roughness = new THREE.FloatNode( .9 );
mtl.metalness = new THREE.FloatNode( 0 );
function createUv(scale, offset) {
let uvOffset = new THREE.FloatNode( offset || 0 );
let uvScale = new THREE.FloatNode( scale || 1 );
let uvNode = new THREE.UVNode();
let offsetNode = new THREE.OperatorNode(
uvOffset,
uvNode,
THREE.OperatorNode.ADD
);
let scaleNode = new THREE.OperatorNode(
offsetNode,
uvScale,
THREE.OperatorNode.MUL
);
return scaleNode;
}
let grass = new THREE.TextureNode( getTexture("grass"), createUv(35) );
let dirt = new THREE.TextureNode( getTexture("dirt"), createUv(35) );
let mask = new THREE.TextureNode( getTexture("mask"), createUv() );
let maskAlphaChannel = new THREE.SwitchNode(mask, "w");
let blend = new THREE.Math3Node(
grass,
dirt,
maskAlphaChannel,
THREE.Math3Node.MIX
);
mtl.color = blend;
mtl.normal = new THREE.NormalMapNode(
new THREE.TextureNode( getTexture("dirtNormal"), createUv(35) )
);
let normalMask = new THREE.OperatorNode(
new THREE.TextureNode( getTexture("mask"), createUv() ),
new THREE.FloatNode(1),
THREE.OperatorNode.MUL
);
mtl.normalScale = normalMask;
// build shader
mtl.build();
// set material
return mtl;
结果如下,看起来相当不错的地形(这是在我的 three.js 项目中):
Properly textured terrain
Proper blending
所以我猜是 GLTF?
当然,可能是 exporter 或 importer 失败了。
- 将 GLTF 导入 Blender 得到与 three.js 相同的结果(黑色地形带有白色高光,污垢应该去的地方),所以我怀疑这就是问题所在。
- 我对导出一窍不通,所以问题可能出在这里。
此外,当我试图阅读和理解 GLTF 2.0 规范时,我在 material 或纹理规范中没有看到任何允许混合或混合的内容。
我还遇到了 KHR_technique_webgl
扩展,它也可能解决这个问题,尽管我不确定具体细节。
结论
因为我真的很想避免硬编码解决方案或使用单一的巨型纹理,GLTF 仍然是我的选择。那么,我是否遗漏了我的管道中的任何东西?此时是否可以在这种情况下使用 GLTF?作品中有什么支持这样的 material 吗?
任何形式的见解都将不胜感激。谢谢。
附加链接:
不幸的是,在撰写本文时,没有任何格式可以导出来保留来自 Blender 的自定义节点图并将其导入实时引擎。您可以为每个 Principled BSDF 套接字一个纹理。如果有帮助,glTF 导出器中有一个选项可以包含纹理变换(旋转、缩放、重复)。
对于这样的自定义内容,我建议为您的材料添加名称和自定义属性(文本或数字)。在导出设置中启用“导出自定义属性/额外”,这些将作为 material.userData
传递到 threejs,您可以从中重建节点图。
我知道它的旧 post,但我发现 Blender 导出不混合节点。