我在XNA中使用标准的.fbx导入器和自定义着色器。当我使用BasicEffect时,.fbx模型是正确的UV包装和适当的纹理。然而,当我使用我的自定义效果时,我必须加载纹理作为参数,并且它没有正确映射。
问题: 1)如何使用自定义效果中包含的纹理坐标正确地为我的.fbx模型添加纹理? 2)有没有办法从加载的.fbx模型对象中访问纹理?这个纹理是怎么回事?
注意:我已经研究了自定义内容管道,我不相信编写自己的Fbx导入器/处理器会很有效。然而,如果有人能够描述地向我提供第一手经验,这就是答案,那么我将使用自定义管道。
感谢您抽出时间阅读这篇文章。
发布于 2011-03-25 00:36:27
这是一个古老的问题,但我昨天不得不自己解决这个问题,所以我想我应该发表一个后续文章:
如果您使用的是默认的FBX内容处理器,并将DefaultEffect属性设置为BasicEffect,则可以通过以下方式获取对象的Texture2D:
texture = ((BasicEffect)model.Meshes[0].Effects[0]).Texture;请注意,模型中的每个网格可能具有不同的纹理。
纹理坐标与位置等一起存储在MeshPart的VertexBuffer中。我已经看到了两个顶点声明。对于使用单一纹理( 3DS Max中的位图材质)的模型/网格,顶点声明为VertexPositionNormalTexture。
对于具有两个纹理(位图和不透明度/alpha贴图)的模型,声明具有以下元素:
Position
Normal
Texture (usage index 0)
Texture (usage index 1)或者,包装到一个IVertexType结构中,
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; }
}
}和等价的HLSL结构:
struct VertexPositionNormalTextureTexture
{
float3 Position : POSITION0;
float3 Normal : NORMAL0;
float4 Texture0 : TEXCOORD0;
float4 Texture1 : TEXCOORD1;
};请注意,在我发布这篇文章之前,我将.Position和.Normal从Vector4和Vector3更改为float4和float3,并且还没有对其进行测试。可能需要将它们改回Vector4和float4。
当然,你需要一个采样器和像素着色器中的一些基本逻辑来读取每个纹理。假设您已经为包含颜色纹理和不透明度贴图的Texture2D对象设置了两个效果参数xTexture0和xTexture1,
// texture sampler
sampler Sampler0 = sampler_state
{
Texture = (xTexture0);
};
sampler Sampler1 = sampler_state
{
Texture = (xTexture1);
};这是一个简单的双纹理像素着色器。如果你只想要一个纹理,只需从第一个采样器中读取并返回值,或应用照明等。
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;
} 这里的相关点是,纹理坐标已经存在于FBX中,并且已经存储在每个MeshPart的VertexBuffer中,因此您需要做的就是提取纹理,将其作为全局效果参数传递到您的着色器中,然后照常进行。
发布于 2009-12-04 22:10:28
它不工作的原因是因为你必须手动设置效果的参数,而不是依赖于basiceffect (在内容管道中设置着色器参数)。现在,我不熟悉你的着色器,所以我不能指定代码来解决你的问题…
要回答你的第二个问题,你可以绕过它。由于默认情况下模型加载到具有基本效果的内容管道中,因此将导入纹理并将其指定给管道的内的着色器的参数。因此,如果你想访问它,你必须查看modelmeshpart的默认效果属性。Here是一个论坛帖子,描述了这个过程。
更正确的答案应该是在完全自定义导入器和仅使用默认导入器之间进行折衷。您可以创建一个从现有模型处理器继承而来的自定义模型处理器。在那里,你可以导入你自己的自定义效果,以及你的自定义纹理和任何你需要设置的参数。并在模型内容上设置它。有一篇文章(在Shawn Hargreave的博客上,或者在msdn上)展示了如何做到这一点,但不幸的是,我现在找不到它。
祝好运!
https://stackoverflow.com/questions/1765779
复制相似问题