XNA .Fbx 纹理

3
我正在使用 XNA 中的标准 .fbx 导入程序和自定义着色器。当我使用 BasicEffect 时,.fbx 模型被正确 UV 包装,并且纹理也被正确应用。然而,当我使用自定义效果时,我必须将纹理作为参数加载,并且它没有正确映射。
问题:1)如何在使用自定义效果时正确应用包含的纹理坐标到我的 .fbx 模型上?2)有没有一种方法可以从加载的 .fbx 模型对象中访问纹理?这个纹理放在哪里?
注意:我已经研究了自定义内容管道,并认为编写自己的 Fbx 导入/处理器并不高效。但是,如果有人能够提供描绘性的第一手经验作为答案,我将使用自定义管道。
感谢阅读此帖。
2个回答

6

这是一个旧问题,但昨天我不得不自己解决,所以我想发表一篇后续文章:

如果您正在使用默认的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.NormalVector4Vector3更改为float4float3,但尚未测试。可能需要将它们改回Vector4float4
当然,您需要在像素着色器中设置一些基本逻辑和采样器来读取每个纹理。假设您已经将两个效果参数xTexture0和xTexture1设置为包含颜色纹理和不透明度图的Texture2D对象。
// 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中,并已存储在每个MeshPartVertexBuffer中,因此您只需要提取纹理,将其作为全局效果参数传递到您的着色器中,并像往常一样继续进行。


1

它不起作用的原因是因为您必须手动设置效果的参数,而不能依赖于基本效果(该效果应在内容管道中设置着色器参数)。现在,我不熟悉您的着色器,所以无法提供代码来解决您的问题...

回答您的第二个问题,您可以通过迂回的方式绕过它。因为模型默认使用基本效果在内容管道中加载,纹理被导入并分配给着色器的参数内部。因此,如果您想访问它,您需要查看模型网格部件的默认效果属性。这里是一个描述此过程的论坛帖子。

更正确的答案将是完全自定义导入程序和仅使用默认值之间的折衷方案。您可以创建一个从现有导入程序继承的自定义模型处理器。在其中,您可以导入自己的自定义效果,以及您需要设置的自定义纹理和任何参数,并将其设置在模型内容上。曾经有一篇文章(可能在Shawn Hargreave的博客或msdn上)展示了如何做到这一点,但不幸的是我目前找不到它。

祝你好运!


这是您用来在FBX文件中复制3DS Max效果的过程吗? - Chris Ridenour
(如果有人需要)GS 3.1的皮肤效果示例(在引入默认的SkinnedEffect之前)[http://create.msdn.com/en-US/education/catalog/sample/skinned_model]展示了如何在设计时替换BasicEffect为自定义着色器。(使用ConvertMaterial方法) - sebf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接