2009-11-19 175 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