FX Shader question

Community Forums/General Help/FX Shader question

RifRaf(Posted 2011) [#1]
Does anyone here know much about shaders? I have a hardware instancing shader here, that I want to add altas mapping to. But dont know a thing about the language. I plan to get a good book on the subject but will be a awhile before I can get out and get one.

Anyone here able to take a peek at this and tell me if adding atlas mapping would be very difficult ?

Thanks

//hwinstance.fx
    // view * projection matrix
    float4x4 viewProjMatrix : MATRIX_VIEWPROJ;

    // texture matrix
    float4x4 textureMatrix : MATRIX_TEXTURE0;

    // entity diffuse texture
    texture diffuseTexture : TEXTURE_0;

    //NEW Pixel shader options
    bool no_light_influence;

    // texture filtering
    int filtering       : TEXTURE_FILTERING;
    int anisotropyLevel : ANISOTROPY_LEVEL;

    // light data
    float4 lightColor     : LIGHT0_COLOR;
    float3 lightDirection : LIGHT0_DIRECTION;
    float4 ambientColor   : COLOR_AMBIENT;

    // entity diffuse sampler
    sampler samplerDiffuse = sampler_state
    {
        Texture       = <diffuseTexture>;
        ADDRESSU      = WRAP;
        ADDRESSV      = WRAP;
        ADDRESSW      = WRAP;
        MAGFILTER     = filtering;
        MINFILTER     = filtering;
        MIPFILTER     = filtering;
        MAXANISOTROPY = anisotropyLevel;
    };

    // Input VS structure
    struct VSInput
    {
       float4 position  : POSITION0;
       float2 texCoords : TEXCOORD0;
       float3 normal    : NORMAL;
       float4 matrixC1  : TEXCOORD2;
       float4 matrixC2  : TEXCOORD3;
       float4 matrixC3  : TEXCOORD4;
       float4 diffColor   : TEXCOORD5;
    };

    // Output VS structure
    struct VSOutput
    {
       float4 position  : POSITION0;
       float2 texCoords : TEXCOORD0;
       float3 normal    : TEXCOORD1;
       float4 diffColor : TEXCOORD5;
    };

    // Vertex shader for hardware instancing
    void VSMain(in VSInput IN, out VSOutput OUT)
    {
       // restore world matrix for instance
       float4x4 worldMatrix;
       worldMatrix[0] = float4(IN.matrixC1.x, IN.matrixC2.x, IN.matrixC3.x, 0.0f);
       worldMatrix[1] = float4(IN.matrixC1.y, IN.matrixC2.y, IN.matrixC3.y, 0.0f);
       worldMatrix[2] = float4(IN.matrixC1.z, IN.matrixC2.z, IN.matrixC3.z, 0.0f);
       worldMatrix[3] = float4(IN.matrixC1.w, IN.matrixC2.w, IN.matrixC3.w, 1.0f);
       // transform position
       OUT.position  = mul(IN.position,  worldMatrix);
       OUT.position  = mul(OUT.position, viewProjMatrix);
       OUT.normal    = normalize(mul(IN.normal, worldMatrix));
       OUT.texCoords = mul(IN.texCoords, textureMatrix);
       // diffuse color NEW
       OUT.diffColor = IN.diffColor;
    }

    // Pixel shaders
    float4 PSMain(in VSOutput IN) : COLOR
    {
       float4 diffuse = tex2D(samplerDiffuse, IN.texCoords) * IN.diffColor;
       float4 result  = ambientColor * diffuse + (diffuse * saturate(dot(IN.normal, -lightDirection)) * lightColor);
       return float4(result.xyz, diffuse.w);
    }

    // Unlit pixel shader
    float4 PSMain_Unlit(in VSOutput IN) : COLOR
    {
       return tex2D(samplerDiffuse, IN.texCoords) * IN.diffColor;
    }

    //  Technique
    technique Instancing
    {
       pass p0
       {
          AlphaBlendEnable = 0;
          CullMode         = CCW;
          VertexShader     = compile vs_2_0 VSMain();
          PixelShader      = compile ps_2_0 PSMain();
       }
    }

    //  Technique with alpha
    technique Instancing_alpha
    {
       pass p0
       {
          SrcBlend = SrcAlpha;
            DestBlend = InvSrcAlpha;
          AlphaBlendEnable = 1;
          CullMode         = CCW;
          VertexShader     = compile vs_2_0 VSMain();
          PixelShader      = compile ps_2_0 PSMain();
       }
    }

    //  Technique with alpha unlit
    technique Instancing_alpha_unlit
    {
       pass p0
       {
          SrcBlend = SrcAlpha;
            DestBlend = InvSrcAlpha;
          AlphaBlendEnable = 1;
          CullMode         = NONE;
          VertexShader     = compile vs_2_0 VSMain();
          PixelShader      = compile ps_2_0 PSMain_Unlit();
       }
    }

    //  Technique for unlit rendering
    technique Instancing_Unlit
    {
       pass p0
       {
          AlphaBlendEnable = 0;
          CullMode         = CCW;
          VertexShader     = compile vs_2_0 VSMain();
          PixelShader      = compile ps_2_0 PSMain_Unlit();
       }
    }


edit : sorry I had meant to put this in general help

Last edited 2011


Kryzon(Posted 2011) [#2]
Hey there. I think you can handle this from the application side; no need to mess with shader code (in fact implementing it in the shader would probably use more memory than handling it directly from the application).

The thing is, with atlas mapping you are relocating\offsetting a mesh's UV coordinates to a certain position in the atlas.
Say you have a big 2048² texture that is your atlas, and your mesh's texture is 256².
After packing as much textures as you can in this atlas, you need to find out where they were relocated.
Say a certain mesh's texture was stored at the bottom-right corner; all you need to do is add this position\offset to the current UV coordinates of every vertex in this certain mesh, then store these UVs in your vertex buffers.

Consider UVs as percentages, so if a 256² texture is stored at the bottom-right of that 2048² atlas, the top-left corner of this stored texture would be something in the order of [0.875 , 0.875].
Add this UV value to the UV coordinates of every vertex of that specific mesh and it should sample the relocated texture in your atlas (do this calculation for every atlas'ed mesh). Then as 'diffuseTexture' send that atlas texture.


col(Posted 2011) [#3]
Atlas mapping is simply storing more than one texture in a single texture. You only need to make sure that the UVs are correct for the model and they tie up correctly with atlas map texture.

So knowing that, this shader should already work with atlas mapping as it is.

Be aware of texture edges and texture smearing. You may also have problems with mipmaps etc in which case you need to rewrite the texture access function to use the ddx and ddy functions. I've only ever briefly looked into it, I'll probably have to cross this bridge myself soon :D but until then....

Last edited 2011


RifRaf(Posted 2011) [#4]
I know what atlas mapping is, but whenever I try to adjust UVs in the application it effects all instances of the object. So wouldnt I have to do this in the shader if I want to effect each instance UV settings individually?

i want to be able to adjust UVs in real time on instanced objects and not bound to the original UVs of the object that was "instanced" is that even possible ?

Last edited 2011


Kryzon(Posted 2011) [#5]
Oh, don't worry about the over-explanation. I'm sure you know what atlas mapping is, but many people read these threads and they might not :)

Anyway, in your application code you must have a call to either glTexCoordPointer or glVertexAttribPointer that specifies the vertex buffer (or vertex buffer region) used for storing texture coordinate values.
Find out where these texture coordinates are poked into this vertex buffer and make sure that instead of cloning the same UVs for every single vertex for all instances, you are actually poking UVs that might be edited.
There must be the same number of vertices as there are of texture coordinates, so even if you have a "polygon soup" vertex buffer (containing entries for the vertices of all the instances at the same time), we know for sure that there is a way for you to allow instances to have edited UVs that are not the same as those of the model's they instance.


RifRaf(Posted 2011) [#6]
Ah, ok thats where we are missing each other :) The engine im using is DX9, and doesnt have direct calls to any low level DX stuff.. its all B3D like syntax. Im using Xors3D

So in this case, I *think* I have to put this into the shader somehow.

Last edited 2011


Kryzon(Posted 2011) [#7]
Cool. A couple of things spring to mind:
• Is your Xors code using a single surface to store the geometry for all the instances?
If that is so, then find the part that populates this surface with geometry. Change it so that instead of simply cloning the same model again and again, you write geometry with the edited UV coordinates, if there is any change present. I'm sure you have a class\type to store each instance so that you know where they're located, their name etc. So you can add a field to this class that tells if there is any UV offset to apply to each vertex when writing them to that single surface (if uvOffset != zero then you have a certain offset to add to each vertex).
(This way is much simpler IMO)

• If you have to do it through shader code, find the part where the Xors code adds the "matrixC1", "matrixC2" and "matrixC3" attributes to each vertex, and in the same manner add another one, a float2 called "uvOffset". You need to update the vertex structure in the shader for this float2 value:
    // Input VS structure
    struct VSInput
    {
       float4 position  : POSITION0;
       float2 texCoords : TEXCOORD0;
       float3 normal    : NORMAL;
       float4 matrixC1  : TEXCOORD2;
       float4 matrixC2  : TEXCOORD3;
       float4 matrixC3  : TEXCOORD4;
       float2 uvOffset  : TEXCOORD6; //Added line.
       float4 diffColor   : TEXCOORD5;
    };

Look in your Xors code the part where it associates the "matrixC1" etc. values to each vertex, and using the same technique, associate the edited uv offset you want each instance to have. A value of 'zero' means you don't want any offset to be applied to a certain vertex, so it remains a perfect clone of the root mesh.
Then you need to update the VSMain() function in your shader code with this:
       // Find this line...
       OUT.texCoords = mul(IN.texCoords, textureMatrix);

       // ...and change it to this:
       OUT.texCoords = mul(IN.texCoords + IN.uvOffset, textureMatrix);

I believe the critical part will be the Xors code that adds the "uvOffset" attribute to each instance's vertex. I don't know how Xors3D works with attributes, but my guess is that each loop you'll need to update the uvOffset values for each vertex if you want to be able to edit UVs in real time.


RifRaf(Posted 2011) [#8]
Thanks, ill see what I can do with this.