Jump to content
  • Advertisement
Sign in to follow this  
dmtuan

[HLSL] Decreasing Shader Model from SM5 to SM2 (vs_5_0 to vs_4_0_level_9_3)

This topic is 1282 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, 

 

I am not an expert on HLSL. Hope someone can help me rewrite this Shader, so it can work on Shader Model 2 (vs_4_0_level_9_3). I have an engine running on Windows 8.1 (App Store), which uses DirectX 11.2 (feature level 11_1). I am trying to rewrite this engine, so it runs on Windows Phone 8.1. In order to accomplish that, I had to decrease the DirectX feature level to 9_3, which only uses Shader Model 2 (unlike feature level 11_1, which supports Shader Model 5).

 

I am having difficulties to rewrite my vertex shader (originally written for vs_5_0), so that it's now for vs_4_0_level_9_3. Here are my shaders written for vs_5_0 profile:

 

 

Common.hlsl:

// Constant buffer to be updated by application per object
cbuffer PerObject : register(b0)
{
    // WorldViewProjection matrix
    float4x4 WorldViewProjection;
    
    // We need the world matrix so that we can
    // calculate the lighting in world space
    float4x4 World;
    
    // Inverse transpose of world, used for
    // bringing normals into world space, especially
    // necessary where non-uniform scaling has been applied
    float4x4 WorldInverseTranspose;
};

// A simple directional light (e.g. the sun)
struct DirectionalLight
{
    float4 Color;
    float3 Direction;
};

// Constant buffer - updated once per frame
// Note: HLSL data is packed in such a
// way that it does not cross a 16-byte boundary
cbuffer PerFrame: register (b1)
{
    DirectionalLight Light;
    float3 CameraPosition;
};

// Constant buffer to hold our material configuration
// Note: HLSL data is packed in such a
// way that it does not cross a 16-bytes boundary
cbuffer PerMaterial : register (b2)
{
    float4 MaterialAmbient;
    float4 MaterialDiffuse;
    float4 MaterialSpecular;
    float MaterialSpecularPower;
    bool HasTexture;
    float4 MaterialEmissive;
    float4x4 UVTransform;
};

// Constant buffer to hold our skin matrices for each bone.
// Note: 1024*64 = maximum bytes for a constant buffer in SM5
cbuffer PerArmature : register(b3)
{
    float4x4 Bones[63];
};

// Vertex Shader input structure (from Application)
struct VertexShaderInput
{
    float4 Position : SV_Position;// Position - xyzw
    float3 Normal : NORMAL;    // Normal - for lighting and mapping operations
    float4 Color : COLOR0;     // Color - vertex color, used to generate a diffuse color
    float2 TextureUV: TEXCOORD0; // UV - texture coordinate
    uint4 SkinIndices : BLENDINDICES0; // blend indices
    float4 SkinWeights : BLENDWEIGHT0; // blend weights
};

// Pixel Shader input structure (from Vertex Shader)
struct PixelShaderInput
{
    float4 Position : SV_Position;
    // Interpolation of combined vertex and material diffuse
    float4 Diffuse : COLOR;
    // Interpolation of vertex UV texture coordinate
    float2 TextureUV: TEXCOORD0;

    // We need the World Position and normal for light calculations
    float3 WorldNormal : NORMAL;
    float3 WorldPosition : WORLDPOS;
};

float3 Lambert(float4 pixelDiffuse, float3 normal, float3 toLight)
{
    // Calculate diffuse color (using Lambert's Cosine Law - dot product of 
    // light and normal) Saturate to clamp the value within 0 to 1.
    float3 diffuseAmount = saturate(dot(normal, toLight));
    return pixelDiffuse.rgb * diffuseAmount;
}

float3 SpecularPhong(float3 normal, float3 toLight, float3 toEye)
{
    // R = reflect(i,n) => R = i - 2 * n * dot(i,n)
    float3 reflection = reflect(-toLight, normal);

    // Calculate the specular amount (smaller specular power = larger specular highlight)
    // Cannot allow a power of 0 otherwise the model will appear black and white
    float specularAmount = pow(saturate(dot(reflection,toEye)), max(MaterialSpecularPower,0.00001f));
    return MaterialSpecular.rgb * specularAmount;
}

float3 SpecularBlinnPhong(float3 normal, float3 toLight, float3 toEye)
{
    // Calculate the half vector
    float3 halfway = normalize(toLight + toEye);

    // Saturate is used to prevent backface light reflection
    // Calculate specular (smaller specular power = larger specular highlight)
    float specularAmount = pow(saturate(dot(normal, halfway)), max(MaterialSpecularPower,0.00001f));
    return MaterialSpecular.rgb * specularAmount;
}

VS.hlsl:

#include "Common.hlsl"

void SkinVertex(float4 weights, uint4 bones, inout float4 position, inout float3 normal)
{
    // If there are skin weights apply vertex skinning
    if (weights.x != 0)
    {
        // Calculate the skin transform from up to four bones and weights
        float4x4 skinTransform = Bones[bones.x] * weights.x +
            Bones[bones.y] * weights.y +
            Bones[bones.z] * weights.z +
            Bones[bones.w] * weights.w;
   
        // Apply skinning to vertex and normal
        position = mul(position, skinTransform);
        
        // We assume here that the skin transform includes only uniform scaling (if any)
        normal = mul(normal, (float3x3)skinTransform);
    }
}

// Vertex shader main function
PixelShaderInput VSMain(VertexShaderInput vertex)
{
    PixelShaderInput result = (PixelShaderInput)0;

    // Apply vertex skinning if any
    SkinVertex(vertex.SkinWeights, vertex.SkinIndices, vertex.Position, vertex.Normal);

    result.Position = mul(vertex.Position, WorldViewProjection);
    result.Diffuse = vertex.Color * MaterialDiffuse;
    // Apply material UV transformation
    result.TextureUV = mul(float4(vertex.TextureUV.x, vertex.TextureUV.y, 0, 1), (float4x2)UVTransform).xy;

    // We use the inverse transpose of the world so that if there is non uniform
    // scaling the normal is transformed correctly. We also use a 3x3 so that 
    // the normal is not affected by translation (i.e. a vector has the same direction
    // and magnitude regardless of translation)
    result.WorldNormal = mul(vertex.Normal, (float3x3)WorldInverseTranspose);
    
    result.WorldPosition = mul(vertex.Position, World).xyz;
    
    return result;
}

When I try to compile this vertex shader with vs_4_0_level_9_3 profile, I get this error:

Common.hlsl(76,14-18): error X4507: maximum vs_4_0_level_9_3 constant register index (256) exceeded - Try reducing number of constants referenced

 

I see the error refers to the line "float4x4 Bones[1024];" in Common.hlsl. I tried to decrease it to "float4x4 Bones[63];", but I got another error:

Common.hlsl(30,14-32): error X4507: maximum vs_4_0_level_9_3 constant register index (256) exceeded - Try reducing number of constants referenced

... the line "float4x4 WorldViewProjection;"

 

I really don't know what now.. :/ any help would be appreciated.

 

Thank you in advance for any pointers and advices.

Edited by dmtuan

Share this post


Link to post
Share on other sites
Advertisement

As I said, I already decreased it from 1024 to 63... float4x4 Bones[63]. Then another error popped up (see my 1st post, at the end)

Share this post


Link to post
Share on other sites

63 is still to much. you've got 256 vectors or 256 / 4 = 64 matrices in TOTAL.

Edited by imoogiBG

Share this post


Link to post
Share on other sites


You're using a total of 276 registers. 252 for the bones, and 24 for the other stuff. Like imoogiBG says, you need to reduce it more.
 
Note that you if you still need 63 bones, you can probably pack the needed info into 3 float4 registers, and reconstruct the matrix in the vertex shader (since some of the bone matrices elements will always be 0 or 1).

 

Thank you all for your advices. You were right. I was using 276, so it was 20 more than allowed. I decreased it to 43 bones, and it compiled fine. It is a little bit less than I need, but I will figure something out with the bones number.

 

I have one more question. If I decrease float4x4 Bones[1024] to float4x4 Bones[43], do I need to change something in the Input Layout for Vertex Shader? This is what I have now:

new[]
                {
                    // "SV_Position" = vertex coordinate in object space
                    new InputElement("SV_Position", 0, Format.R32G32B32_Float, 0, 0),
                    // "NORMAL" = the vertex normal
                    new InputElement("NORMAL", 0, Format.R32G32B32_Float, 12, 0),
                    // "COLOR"
                    new InputElement("COLOR", 0, Format.R8G8B8A8_UNorm, 24, 0),
                    // "UV"
                    new InputElement("TEXCOORD", 0, Format.R32G32_Float, 28, 0),
                    // "BLENDINDICES"
                    new InputElement("BLENDINDICES", 0, Format.R32G32B32A32_UInt, 36, 0),
                    // "BLENDWEIGHT"
                    new InputElement("BLENDWEIGHT", 0, Format.R32G32B32A32_Float, 52, 0),
                }));

After changing bone number to 43, i get this error while defining the Input Layout. I'd like to know if the error is related to the bones number change or if it's related to something else.

Share this post


Link to post
Share on other sites

What's the error? SV_Position is a DX10 and above thing, maybe that's the problem? My guess is that something in your layout is not supported in the feature level you're using.

Share this post


Link to post
Share on other sites
I have one more question. If I decrease float4x4 Bones[1024] to float4x4 Bones[43], do I need to change something in the Input Layout for Vertex Shader? This is what I have now:

shader resources are not part form Input assembler, so there is no need to update the Input Layout, the layout only specifies how you re going to pass mesh vertices to the shader.
 

 

are you using D3D11_CREATE_DEVICE_DEBUG, there should be an error?

 

Edited by imoogiBG

Share this post


Link to post
Share on other sites


What's the error? SV_Position is a DX10 and above thing, maybe that's the problem? My guess is that something in your layout is not supported in the feature level you're using.

 

It says: Message = "HRESULT: [0x80070057], Module: [General], ApiCode: [E_INVALIDARG/Invalid Arguments], Message: The parameter is incorrect.\r\n"

 

I think it is because of new InputElement("BLENDINDICES", 0, Format.R32G32B32A32_UInt, 36, 0)

I'm looking into https://msdn.microsoft.com/en-us/library/windows/desktop/ff471324(v=vs.85).aspx, and there is no reference of R32G32B32A32_UInt. 

Share this post


Link to post
Share on other sites


shader resources are not part form Input assembler, so there is no need to update the Input Layout, the layout only specifies how you re going to pass mesh vertices to the shader.
 
 
are you using D3D11_CREATE_DEVICE_DEBUG, there should be an error?

 

I see, so it's not related to the change in the bones number.

 

No, Im not using D3D11_CREATE_DEVICE_DEBUG.

 

Anyway, I think I got pass this. Thank you all for your help.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!