2009-11-19 132 views
3

我在XNA中使用标准.fbx导入器和自定义着色器。使用BasicEffect时,.fbx模型可以正确地进行UV包装并进行适当的纹理处理。但是,当我使用我的自定义效果时,我必须将纹理作为参数加载,并且未正确映射。XNA .Fbx纹理

问题:1)如何使用自定义效果包含的纹理坐标正确地纹理我的.fbx模型? 2)有没有办法从加载的.fbx模型对象访问纹理?这个纹理去哪了?

注:我研究了自定义内容管道,不相信编写我自己的Fbx导入器/处理器将会很有效率。但是,如果有人能够描述性地向我提供这种答案的第一手经验,那么我将使用自定义管道。

谢谢你的时间和阅读这篇文章。

回答

6

这是一个老问题,但我有,所以我想我会发布一个后续昨天这出自己:如果您使用的是默认FBX内容处理器

,并有DefaultEffect属性设置为BasicEffect,您可以通过获得Texture2D的对象:

texture = ((BasicEffect)model.Meshes[0].Effects[0]).Texture; 

注意,在模型中的每个网格可以有不同的质感。

纹理坐标存储在MeshPartVertexBuffer以及位置等我见过两个顶点声明。对于使用单个纹理的模型/网格(3DS Max中的位图材质),顶点声明为VertexPositionNormalTexture

对于有两个纹理(位图和不透明/α-地图)的模型,声明有元素:

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.NormalVector4Vector3float4float3之前我发布了这个,并没有测试它。可能需要将它们更改回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

它不工作的原因是因为您必须手动设置效果参数,而不是依赖basiceffect(会在内容管道中设置着色器参数)。现在,我对你的着色器不熟悉,所以我不能规定代码来解决你的问题...

要回答你的第二个问题,你可以用一种迂回的方式解决它。由于模型默认情况下会使用basiceffect加载内容管道,因此纹理将被导入并分配给流水线内内的着色器参数。所以如果你想访问它,你必须看看modelmeshpart的默认效果属性。 Here是描述此过程的论坛帖子。

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

祝你好运!

+0

这是您用来从FBX文件中的3DS max重现效果的过程吗? – 2010-01-04 21:14:41

+0

是的,它是...... – 2010-01-05 14:12:30

+0

(万一任何人遇到这种情况并需要它)GS 3.1的皮肤效应样本(在他们引入股票SkinnedEffect之前)[http://create.msdn.com/en- US/education/catalog/sample/skinned_model]显示了如何在设计时加载自定义着色器的BasicEffect。 (ConvertMaterial方法) – sebf 2011-02-16 23:12:53