我在XNA中使用带有自定义着色器的标准.fbx导入程序。 .fbx模型正确地进行了UV包装,并在使用BasicEffect时进行了适当的纹理处理。但是,当我使用自定义效果时,我必须将纹理作为参数加载,并且未正确映射。
问题:1)如何使用包含的纹理坐标和自定义效果正确地纹理我的.fbx模型? 2)有没有办法从加载的.fbx模型对象访问纹理?这个纹理在哪里?
注意:我研究过自定义内容管道,并且不相信编写我自己的Fbx导入器/处理器会很有效。但是,如果有人可以描述性地为我提供这方面的第一手经验,那么我将使用自定义管道。
感谢您抽出宝贵时间阅读本文。
答案 0 :(得分:6)
这是一个老问题,但我必须在昨天自己解决这个问题,所以我想我会发布一个后续内容:
如果您使用默认的FBX内容处理器并将DefaultEffect
属性设置为BasicEffect
,则可以通过以下方式获取对象的Texture2D
:
texture = ((BasicEffect)model.Meshes[0].Effects[0]).Texture;
请注意,模型中的每个网格可能具有不同的纹理。
纹理坐标与位置等一起存储在MeshPart
的{{1}}中。我见过两个顶点声明。对于使用单个纹理(3DS Max中的位图材质)的模型/网格,顶点声明为VertexBuffer
。
对于具有两个纹理(位图和不透明度/ alpha贴图)的模型,声明具有以下元素:
VertexPositionNormalTexture
或包裹在Position
Normal
Texture (usage index 0)
Texture (usage index 1)
结构中
IVertexType
和等效的HLSL结构:
public struct VertexPositionNormalTextureTexture : IVertexType
{
public Vector3 Position;
public Vector3 Normal;
public Vector4 Texture0;
public Vector4 Texture1;
public static VertexDeclaration VertexDeclaration
{
get
{
return new VertexDeclaration
(
new VertexElement(0,VertexElementFormat.Vector3, VertexElementUsage.Position, 0)
,
new VertexElement(0,VertexElementFormat.Vector3, VertexElementUsage.Normal, 0)
,
new VertexElement(0,VertexElementFormat.Vector3, VertexElementUsage.TextureCoordinate, 0)
,
new VertexElement(0,VertexElementFormat.Vector3, VertexElementUsage.TextureCoordinate, 1)
);
}
}
VertexDeclaration IVertexType.VertexDeclaration
{
get { return VertexDeclaration; }
}
}
请注意,在我发布此消息之前,我已将struct VertexPositionNormalTextureTexture
{
float3 Position : POSITION0;
float3 Normal : NORMAL0;
float4 Texture0 : TEXCOORD0;
float4 Texture1 : TEXCOORD1;
};
和.Position
从.Normal
和Vector4
更改为Vector3
和float4
测试了它。可能需要将它们更改回float3
和Vector4
。
当然,您需要在像素着色器中使用采样器和一些基本逻辑来读取每个纹理。假设您已将两个效果参数xTexture0和xTexture1设置为包含颜色纹理和不透明度贴图的float4
个对象,
Texture2D
这是一个简单的双纹理像素着色器。如果您只想要一个纹理,只需从第一个采样器读取并返回值,或应用光照等。
// texture sampler
sampler Sampler0 = sampler_state
{
Texture = (xTexture0);
};
sampler Sampler1 = sampler_state
{
Texture = (xTexture1);
};
这里的相关点是纹理坐标已经存在于FBX中并且已经存储在每个float4 TwoTexturePixelShader(VertexPositionNormalTextureTexture input) : COLOR0
{
float4 texel0;
float4 texel1;
float4 pixel;
// check global effect parameter to see if we want textures turned on
// (useful for debugging geometry weirdness)
if (TexturesEnabled)
{
texel0 = tex2D(Sampler0, input.Texture0);
texel1 = tex2D(Sampler1, input.Texture1);
/// Assume texel1 is an alpha map, so just multiple texel0 by that alpha.
pixel.rgb=texel0.rgb;
pixel.a=texel0.a;
}
else
/// return 100% green
pixel = float4(0,1,0,1);
return pixel;
}
的{{1}}中,所以你需要做的就是提取纹理,传递它作为全局效果参数进入着色器,并照常进行。
答案 1 :(得分:1)
它不起作用的原因是因为你必须手动设置效果的参数而不是依赖于basiceffect(它会在内容管道中设置着色器参数)。现在,我不熟悉你的着色器,所以我无法开出代码来解决你的问题......
要回答你的第二个问题,你可以用迂回的方式绕过它。由于默认情况下模型在内容管道中加载basiceffect,因此导入纹理并将其分配给管道中着色器的 参数。因此,如果要访问它,则必须查看modelmeshpart的默认效果属性。 Here是一个描述此过程的论坛帖子。
更正确的答案是完全自定义导入器与仅使用默认值之间的折衷。您可以创建一个继承自现有模型的自定义模型处理器。在那里,您可以导入自己的自定义效果,以及自定义纹理和您需要设置的任何参数。并将其设置在modelcontent上。有一篇文章(无论是在Shawn Hargreave的博客上,还是在msdn上)都展示了如何做到这一点,但遗憾的是我现在还没有找到它。
祝你好运!