DirectX 9 +着色器效果:禁用平滑的颜色过渡

时间:2014-11-25 03:04:10

标签: directx shader effects hlsl alphablending

我创建了一个简单的着色器效果,它必须绘制左半部分为蓝色,右半部分为红色。但过渡不是鲜明的颜色,而是用渐变看到图片:enter image description here

我需要关闭这里颜色的平滑过渡: enter image description here

着色器效果代码

struct VSInputTxVc
{
    float4  Position    : POSITION;
    float2  TexCoord    : TEXCOORD0;
    float4  Color       : COLOR;
};

struct VS_OUTPUT
{
    float4 Position : POSITION;
    float4 Color : COLOR;
};

//Vertex Shader
VS_OUTPUT RenderSceneVS(VSInputTxVc VertexIn)
{
    VS_OUTPUT VertexOut;
    VertexOut.Position = VertexIn.Position;

    if( VertexOut.Position.x > 0 )
    {
        VertexOut.Color = float4(1,0,0,1);  // Right half-part must have red color
    }
    else
    {
        VertexOut.Color = float4(0,0,1,1); // Left half-part must have blue color
    }

    return VertexOut;
}

//Pixel Shader
float4 RenderScenePS(float4 Color : COLOR) : COLOR
{
    return Color;
}

technique RenderScene
{
    pass P0
    { 
        VertexShader  = (compile vs_1_1 RenderSceneVS());
        PixelShader  = (compile ps_2_0 RenderScenePS());
    }
}

我绘制全屏原语{-1,-1:-1,1:1,-1:1,1}并且我使用不同的混合模式但它没有帮助。

C ++代码:

   //Create the Direct3D Object
    LPDIRECT3D9 pD3D = NULL;
    if( NULL == (pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
      return E_FAIL;

    //Setup the device presentation parameters
    D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

    //The final step is to use the IDirect3D9::CreateDevice method to create the Direct3D device, as illustrated in the
    //following code example.
    LPDIRECT3DDEVICE9 pd3dDevice = NULL;
    if( FAILED( pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                    D3DCREATE_HARDWARE_VERTEXPROCESSING,
                                    &d3dpp, &pd3dDevice ) ) )
    {
        MessageBox(hWnd, L"No HAL HARDWARE_VERTEXPROCESSING! Sample will exit!", NULL, 0);
        pD3D->Release();
        pD3D = NULL;
        return E_FAIL;
    }

    //set the vertex buffer size 4 vertices * vertex structure size
    UINT uiBufferSize = 4*sizeof(COLORED_VERTEX);

    //create the buffer
    if( FAILED( pd3dDevice->CreateVertexBuffer( uiBufferSize,
            D3DUSAGE_WRITEONLY, D3DFVF_COLOREDVERTEX, D3DPOOL_DEFAULT, &g_lpVertexBuffer, NULL ) ) )
        return E_FAIL;

    COLORED_VERTEX* pVertices;
    //lock the buffer for writing
    if( FAILED( g_lpVertexBuffer->Lock( 0, uiBufferSize, (void**)&pVertices, 0 ) ) )
        return E_FAIL;

    //write the vertices. Here a simple rectangle
    pVertices[0].x =  -1.0f; //left
    pVertices[0].y =  -1.0f; //bottom
    pVertices[0].z =   0.0f;
    pVertices[0].color =  0xffff0000; //red

    pVertices[1].x =  -1.0f; //left
    pVertices[1].y =   1.0f; //top
    pVertices[1].z =   0.0f;
    pVertices[1].color =  0xff0000ff; //blue

    pVertices[2].x =   1.0f; //right
    pVertices[2].y =  -1.0f; //bottom
    pVertices[2].z =   0.0f;
    pVertices[2].color =  0xff00ff00; //green

    pVertices[3].x =  1.0f; //right
    pVertices[3].y =  1.0f; //top 
    pVertices[3].z =  0.0f;
    pVertices[3].color =  0xffffffff; //white

    //unlock the buffer
    g_lpVertexBuffer->Unlock();

    //set the Vertex Format
    pd3dDevice->SetFVF( D3DFVF_COLOREDVERTEX );

    //transfer the buffer to the gpu
    pd3dDevice->SetStreamSource( 0, g_lpVertexBuffer, 0, sizeof(COLORED_VERTEX) );

    //create an effect
    ID3DXBuffer* errorBuffer = 0;
    wchar_t EffectFileName[] = L"MinimalEffect.fx";
    if(FAILED(D3DXCreateEffectFromFile( pd3dDevice, EffectFileName, NULL, 
        NULL, D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, NULL, &g_lpEffect, &errorBuffer )))
    {
        wchar_t buf[2048];
        wchar_t tmp[2048];
        swprintf_s(buf, L"D3DXCreateEffectFromFile() Error create of effect \"%s\" \n\n", EffectFileName);
        if( errorBuffer )
        {
            lstrcatW(buf, charToWchar_t( (char*)errorBuffer->GetBufferPointer(), tmp ) );
            errorBuffer->Release();
        }
        MessageBox(hWnd, buf, NULL, 0);
        pD3D->Release();
        pD3D = NULL;
        return E_FAIL;
    }

    // Choice the tehnique of shader
    D3DXHANDLE hTechnick;
    if( D3D_OK != g_lpEffect->FindNextValidTechnique( NULL, &hTechnick ) )
    {
        wchar_t buf[1024];
        swprintf_s(buf, L"[FindNextValidTechnique] No finded any valid tehnique in shader effect. \n\n File: \"%s\"",
        EffectFileName );
        MessageBoxW(hWnd, buf, L"Error", MB_OKCANCEL|MB_SETFOREGROUND|MB_TOPMOST);
        return false;
    }
    g_lpEffect->SetTechnique( hTechnick );

    //D3DXMatrixIdentity(&g_ShaderMatrix);
    //g_lpEffect->SetMatrix( "ShaderMatrix", &g_ShaderMatrix );

    //pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
    //pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_MIN);
    //pd3dDevice->SetRenderState(D3DRS_COLORVERTEX, FALSE);

    MSG msg; 
    while( g_bContinue )
    {
        //Clear render region with blue
        pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );

        //before rendering something, you have to call this
        pd3dDevice->BeginScene();

        //rendering of scene objects happens here

        //begin the effect
        UINT uiPasses = 0;
        g_lpEffect->Begin(&uiPasses, 0);
        for (UINT uiPass = 0; uiPass < uiPasses; uiPass++)
        {
            //render an effect pass
            g_lpEffect->BeginPass(uiPass);

            //render the rectangle
            pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

            g_lpEffect->EndPass();
        }
        g_lpEffect->End();

        //after the scene call
        pd3dDevice->EndScene();

        //update screen = swap front and backbuffer
        pd3dDevice->Present(NULL, NULL, NULL, NULL);

        // A window has to handle its messages.
        TranslateMessage( &msg );
        DispatchMessage( &msg );
        PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
    }

顶点数据类型:

//Definition of the Vertex Format including position and diffuse color
#define D3DFVF_COLOREDVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)

struct COLORED_VERTEX
{
    float x, y, z;  //Position
    DWORD color;    //Color
};

2 个答案:

答案 0 :(得分:1)

您正在设置四边形顶点的颜色。由光栅化器在三角形的三个顶点之间自动插入由顶点着色器输出的所有信息以生成片段。这些传递给像素着色器,它只返回导致渐变的给定颜色。为了避免这种行为,你有两种可能性:

首先,您可以在pixelhader中分支颜色,例如通过测试纹理坐标。

struct VS_OUTPUT
{
    float4 Position : POSITION;
    float2 Tex: TEXCOORD0;
};

//Vertex Shader
VS_OUTPUT RenderSceneVS(VSInputTxVc VertexIn)
{
    VS_OUTPUT VertexOut;
    VertexOut.Position = VertexIn.Position;
    VertexOut.Tex = VertexIn.TexCoord;

    return VertexOut;
}

//Pixel Shader
float4 RenderScenePS(float2 Tex: TEXCOORD0) : COLOR
{
    float4 Color = 0;
    if( Tex.x > 0.5 )
    {
        Color = float4(1,0,0,1);  // Right half-part must have red color
    }
    else
    {
        Color = float4(0,0,1,1); // Left half-part must have blue color
    }
    return Color;
}

第二种方法是渲染两个半全屏四边形。然后你可以设置顶点的颜色,并通过顶点着色器使用几乎你当前的方法。

答案 1 :(得分:0)

在Gnietschow&#39;之后更新着色器的代码。备注:

struct VSInputTxVc
{
    float4  Position    : POSITION;
    float2  TexCoord    : TEXCOORD0;
    float4  Color       : COLOR;
};

struct VS_OUTPUT
{
    float4 Position : POSITION;
    float2 Tex: TEXCOORD0;
};

//Vertex Shader
VS_OUTPUT RenderSceneVS(VSInputTxVc VertexIn)
{
    VS_OUTPUT VertexOut;
    VertexOut.Position = VertexIn.Position;

    // Convert coordinates from "POSITION" to "TEXCOORD0"
    // And normalize coordinates from [-1,1] to [0,1] (only for DirectX 9)
    // Looks like black magic but works fine ;)
    VertexOut.Tex.x = VertexIn.Position.x + 0.5;
    VertexOut.Tex.y = VertexIn.Position.y + 0.5;

    return VertexOut;
}

//Pixel Shader
float4 RenderScenePS(float2 Tex: TEXCOORD0) : COLOR
{
    float4 Color = 0;

    if( Tex.x > 0.5 )
    {
        Color = float4(1,0,0,1);  // Right half-part must have red color
    }
    else
    {
        Color = float4(0,0,1,1); // Left half-part must have blue color
    }
    return Color;
}

technique RenderScene
{
    pass P0
    { 
        VertexShader  = (compile vs_1_1 RenderSceneVS());
        PixelShader  = (compile ps_2_0 RenderScenePS());
    }
}