0

I am rather new to HLSL and I am struggling with implementing a grass shader. In the geometry shader I create quads which will display the grass blades. However when I try blending in the pixelshader things get weird. Sometimes it ignores everything which is behind the quad. I'm assuming it's a problem with the depth stencil. this is the result:

Here is my shader:

//************
// VARIABLES *
//************
cbuffer cbPerObject
{
    float4x4 m_MatrixWorldViewProj : WORLDVIEWPROJECTION;
    float4x4 m_MatrixWorld : WORLD;
    float4x4 gMatrixViewInverse : VIEWINVERSE;
    float3 m_LightDir = { 2.0f,-5.0f,0.0f };
}

RasterizerState FrontCulling
{
    CullMode = NONE;
};

SamplerState samLinear
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;// of Mirror of Clamp of Border
    AddressV = Wrap;// of Mirror of Clamp of Border
};
BlendState EnableBlending
{
    BlendEnable[0] = TRUE;
    SrcBlend = SRC_ALPHA;
    DestBlend = INV_SRC_ALPHA;
    BlendOp = ADD;
    SrcBlendAlpha = ZERO;
    DestBlendAlpha = ZERO;
    BlendOpAlpha = ADD;
    RenderTargetWriteMask[0] = 0x0F;
};
DepthStencilState EnableDepth
{
    // Depth test parameters
    DepthEnable = true;
    DepthWriteMask = all;
    DepthFunc = less;
    StencilEnable = false;
};

Texture2D m_TextureDiffuse<
    string UIName = "Diffuse Texture";
    string UIWidget = "Texture";
    string ResourceName = "Grass.dds";
>;
Texture2D m_TextureDiffuseBlade<
    string UIName = "Diffuse Texture Blade";
    string UIWidget = "Texture";
    string ResourceName = "GrassBladeDiffuse.dds";
>;
Texture2D m_PerlinNoise<
    string UIName = "Perlin Texture";
    string UIWidget = "Texture";
    string ResourceName = "Perlin.dds";
>;
float gGrassHeight
<
    string UIName = "Grass Height";
    string UIWidget = "slider";
    float UIMin = 0;
    float UIMax = 10.0f;
    float UIStep = 0.01;
> = 0.6f;
float gGrassHeightRandom
<
    string UIName = "Grass Height Random";
    string UIWidget = "slider";
    float UIMin = 0;
    float UIMax = 1.0f;
    float UIStep = 0.01;
> = 1.0f;
float gGrassBend
<
    string UIName = "Grass Bend";
    string UIWidget = "slider";
    float UIMin = 0;
    float UIMax = 1.0f;
    float UIStep = 0.01;
> = 1.0f;

int gGrassBlades
<
    string UIName = "Grass Blades";
    string UIWidget = "slider";
    int UIMin = 1;
    int UIMax = 5.0f;
    int UIStep = 1;
> = 5;
float gGrassBladesSize
<
    string UIName = "Grass Blades Size";
    string UIWidget = "slider";
    float UIMin = 0;
    float UIMax = 1.0f;
    float UIStep = 0.01;
> = 0.2f;
float gGrassSpread<
    string UIName = "Grass Spread";
> = 5.0f;

float gTime;
//**********
// STRUCTS *
//**********
struct VS_DATA
{
    float3 Position : POSITION;
    float3 Normal : NORMAL;
    float2 TexCoord : TEXCOORD;
};

struct GS_DATA
{
    float4 Position : SV_POSITION;
    float3 Normal : NORMAL;
    float2 TexCoord : TEXCOORD0;
    bool Blade : FALSE;
};

//****************
// VERTEX SHADER *
//****************
VS_DATA MainVS(VS_DATA vsData)
{
    return vsData;
}

//******************
// GEOMETRY SHADER *
//******************
void CreateVertex(inout TriangleStream<GS_DATA> triStream, float3 pos, float3 normal, float2 texCoord, bool blade = true)
{
    //Step 1. Create a GS_DATA object
    GS_DATA temp = (GS_DATA)0;
    //Step 2. Transform the position using the WVP Matrix and assign it to (GS_DATA object).Position (Keep in mind: float3 -> float4)
    temp.Position = mul(float4(pos, 1), m_MatrixWorldViewProj);
    //Step 3. Transform the normal using the World Matrix and assign it to (GS_DATA object).Normal (Only Rotation, No translation!)
    temp.Normal = mul(normal, (float3x3)m_MatrixWorld);
    //Step 4. Assign texCoord to (GS_DATA object).TexCoord
    temp.TexCoord = texCoord;
    //set if blade or not
    temp.Blade = blade;
    //Step 5. Append (GS_DATA object) to the TriangleStream parameter (TriangleStream::Append(...))
    triStream.Append(temp);
}

float3x3 AngleAxis3x3(float angle, float3 axis)
{
    float c, s;
    sincos(angle, s, c);

    float t = 1 - c;
    float x = axis.x;
    float y = axis.y;
    float z = axis.z;

    return float3x3(
        t * x * x + c, t * x * y - s * z, t * x * z + s * y,
        t * x * y + s * z, t * y * y + c, t * y * z - s * x,
        t * x * z - s * y, t * y * z + s * x, t * z * z + c
        );
}

[maxvertexcount(5*6*3 +3)]
//[instance(16)]
void GrassGenerator(triangle VS_DATA vertices[3], inout TriangleStream<GS_DATA> triStream)//, uint InstanceID : SV_GSInstanceID)
{
    float3 basePoint, top;

    //Step 1. Calculate The basePoint
    basePoint = (vertices[0].Position + vertices[1].Position + vertices[2].Position) / 3;
    //Step 2. Calculate The normal of the basePoint
    float3 normal = normalize((vertices[0].Normal + vertices[1].Normal + vertices[2].Normal) / 3);


    //orignal vertex
    CreateVertex(triStream, vertices[0].Position, vertices[0].Normal, vertices[0].TexCoord, false);
    CreateVertex(triStream, vertices[1].Position, vertices[1].Normal, vertices[1].TexCoord, false);
    CreateVertex(triStream, vertices[2].Position, vertices[2].Normal, vertices[2].TexCoord, false);

    triStream.RestartStrip();

    float3 left, right, grassnormal;
    for (int j = 0; j < gGrassBlades; j++)
    {
        float3 position = basePoint + float3(m_PerlinNoise.SampleLevel(samLinear, vertices[j].TexCoord, 0).y - 0.5f, m_PerlinNoise.SampleLevel(samLinear, vertices[j].TexCoord, 0).z - 0.5f, 0)*gGrassSpread;
        top = position + (gGrassHeight * normal);
        float3 grassDirection = float3(1, 0, 0) * gGrassBladesSize;

        float xAngle = 0.0f;
        for (int i = 0; i < 3; i++)
        {
            float3x3 rotation = AngleAxis3x3(xAngle, normal);

            grassDirection = mul(grassDirection, rotation);




            //Step 5. Calculate The Normal of the grass
            float3 leftEdge, rightEdge;
            leftEdge = (position - grassDirection) - top;
            rightEdge = (position + grassDirection) - top;
            grassnormal = normalize(cross(leftEdge, rightEdge));

            //Create Spike Geometry
            CreateVertex(triStream, top - grassDirection, grassnormal, float2(0, 0));
            CreateVertex(triStream, position - grassDirection, grassnormal, float2(0, 1));
            CreateVertex(triStream, position + grassDirection, grassnormal, float2(1, 1));

            triStream.RestartStrip();

            CreateVertex(triStream, top + grassDirection, grassnormal, float2(1, 0));
            CreateVertex(triStream, position + grassDirection, grassnormal, float2(1, 1));
            CreateVertex(triStream, top - grassDirection, grassnormal, float2(0, 0));

            triStream.RestartStrip();

            static const float PI = 3.14159265f;

            xAngle = 2 * PI / 3;
        }
    }
}

//***************
// PIXEL SHADER *
//***************
float4 MainPS(GS_DATA input) : SV_TARGET
{
    input.Normal = -normalize(input.Normal);
float alpha;
float3 color;

if (input.Blade) {
    alpha = m_TextureDiffuseBlade.Sample(samLinear,input.TexCoord).a;
    color = m_TextureDiffuseBlade.Sample(samLinear,input.TexCoord).rgb;
}
else {
    alpha = m_TextureDiffuse.Sample(samLinear,input.TexCoord).a;
    color = m_TextureDiffuse.Sample(samLinear,input.TexCoord).rgb;
}
float s = max(dot(m_LightDir, input.Normal), 0.4f);
return float4(color*s,alpha);
}


//*************
// TECHNIQUES * 
//*************
technique10 DefaultTechnique
{
    pass p0 {
        SetDepthStencilState(EnableDepth, 0);
        SetBlendState(EnableBlending, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xFFFFFFFF);
        SetRasterizerState(FrontCulling);
        SetVertexShader(CompileShader(vs_4_0, MainVS()));
        SetGeometryShader(CompileShader(gs_5_0, GrassGenerator()));
        SetPixelShader(CompileShader(ps_4_0, MainPS()));
    }
}
Quinten Henry
  • 125
  • 1
  • 2
  • 10
  • if depth test is activated the fragment (pixel) you are currently rendering will be discarded if something is closer to the camera. Then no blending will occured. When doing blending you should try to sort the pixel you are rendering using depth or some will be blended only once. Try to disable the depth test and see the result. – Paltoquet Apr 04 '18 at 14:28
  • It appears you are using the legacy Effects for Direct3D 11, correct? If so, you should use the [latest version](https://github.com/Microsoft/FX11/wiki). Also be aware of this [known issue](https://github.com/Microsoft/FX11/issues/3) related to FX11 and Geometry Shaders. Also note that grass/foliage often uses alpha-to-coverage instead of alpha-blending. – Chuck Walbourn Apr 05 '18 at 15:55

0 Answers0