Pergunta

Estou usando o importador .fbx padrão com shaders personalizados no XNA. O modelo .fbx é embrulhado corretamente e é texturizado adequadamente quando eu uso o Basicefffect. No entanto, quando uso meu efeito personalizado, tenho que carregar a textura como um parâmetro e não é mapeado corretamente.

Perguntas: 1) Como posso texturar meu modelo .fbx corretamente usando as coordenadas da textura incluídas com efeitos personalizados? 2) Existe uma maneira de acessar a textura do objeto Modelo .fbx carregado? Para onde vai essa textura?

Nota: Estudei pipelines de conteúdo personalizados e não acredito que escrever meu próprio importador/processador do FBX seja eficiente. No entanto, se alguém puder me fornecer descritivamente a experiência em primeira mão por ser a resposta, usarei o pipeline personalizado.

Obrigado pelo seu tempo e por ler este post.

Foi útil?

Solução

Esta é uma pergunta antiga, mas eu tive que descobrir isso ontem, então pensei em postar um acompanhamento:

Se você estiver usando o processador de conteúdo FBX padrão e tem o DefaultEffect propriedade definida como BasicEffect, você pode obter o Texture2D para o objeto via:

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

Observe que cada malha no modelo pode ter uma textura diferente.

As coordenadas de textura são armazenadas no MeshPart'sVertexBuffer junto com a posição, etc. Eu vi duas declarações de vértice. Para um modelo/malha que usava uma única textura (material de bitmap no 3DS máx), a declaração de vértice foi VertexPositionNormalTexture.

Para um modelo que tinha duas texturas (um mapa de bitmap e opacidade/alfa), a declaração tinha os elementos:

Position
Normal
Texture (usage index 0)
Texture (usage index 1)

ou, envolto em um IVertexType estrutura,

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; }
    }
}

e a estrutura HLSL equivalente:

struct VertexPositionNormalTextureTexture
{
    float3 Position : POSITION0;
    float3 Normal : NORMAL0;
    float4 Texture0 : TEXCOORD0;
    float4 Texture1 : TEXCOORD1;
};

Observe que eu mudei .Position e .Normal a partir de Vector4 e Vector3 para float4 e float3 Antes de postar isso, e não testei. É possível que eles precisem ser alterados de volta para Vector4 e float4.

Obviamente, você precisará de um amostrador e alguma lógica básica no seu shader de pixel para ler cada textura. Supondo que você definiu dois parâmetros de efeito xTexture0 e XTexture1 para Texture2D objetos que contêm sua textura de cor e mapa de opacidade,

// texture sampler
sampler Sampler0 = sampler_state
{
    Texture = (xTexture0);
};

sampler Sampler1 = sampler_state
{
    Texture = (xTexture1);
};

E aqui está um simples shader de pixels de duas texturas. Se você deseja apenas uma textura, basta ler no primeiro amostrador e devolver o valor, ou aplicar iluminação, etc.

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;

} 

Os pontos relevantes aqui são que as coordenadas de textura já estão presentes no FBX e já estão armazenadas em cada MeshPart's VertexBuffer, então tudo o que você precisa fazer é extrair a textura, passá -la para o shader como um parâmetro de efeito global e prosseguir normalmente.

Outras dicas

A razão pela qual não está funcionando é porque você precisa definir os parâmetros do efeito manualmente, em vez de confiar no BasiceFeff (que teria os parâmetros do shader definidos no pipeline de conteúdo). Agora, não estou familiarizado com o seu shader, então não pude prescrever código para resolver seu problema ...

Para responder à sua segunda pergunta, você pode contorná -la de uma maneira rotatória. Como o modelo é carregado no pipeline de conteúdo com o BasiceFeft por padrão, a textura é importada e atribuída aos parâmetros do shader lado de dentro do pipeline. Portanto, se você quiser acessá -lo, terá que olhar para a propriedade padrão do ModelMeshPart. Aqui é um post do fórum que descreve esse processo.

A resposta mais correta seria um compromisso entre um importador personalizado completo e apenas usando o padrão. Você pode fazer um processador de modelo personalizado que herda o existente. Lá, você pode importar seu próprio efeito personalizado, juntamente com suas texturas personalizadas e quaisquer parâmetros que você precisar definir. e defina -o no ModelContent. Havia um artigo (no blog de Shawn Hargreave, ou no MSDN) que mostrou como fazer isso, mas infelizmente estou não encontrando -o no momento.

boa sorte!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top