D3D10与Geometry Shader学习笔记2

来源:互联网 发布:阿里云登录远程桌面 编辑:程序博客网 时间:2024/05/21 07:55
 
D3D10与Geometry Shader学习笔记(2)
 
华南理工大学,张嘉华 newzjh@126.com QQ:188318005,欢迎和我多多交流,共同学习进步
1.     贝赛尔曲线在Geometry Shader下的实现
贝赛尔曲线在图形绘制中经常用到,在这一节里面讲介绍如何在Geometry Shader下实现贝赛尔曲线的绘制.首先来看最简单的贝赛尔曲线,就是由四个点控制.
 
考虑到贝赛尔曲线输入是四个点,而我们这里是为二维图形绘制实时的贝赛尔曲线,因此可以用两个四维的顶点表示这四个二维的点,因为对于Geometry Shader输入的类型中point必须是一个点,line是两个点,triangle是三个点,也就是input数组的大小,而不存在四个元素的输入数组类型.在GS_Bezier()首先把两个四维的点转换为四个二维的点.接着根据贝赛尔曲线的函数,通过100次线段细分来逼近曲线,因此t=1/100,计算t1,t2为处于整段曲线的比例,接着利用贝赛尔曲线函数计算出每个线段的两端的两个点,接着Append到输出流,每输出一段线段都需要RestartStrip()一下,以确认以之前append的数据构成图元输出了.输出流这里定义为LineStream表示线段流.下面是HLSL文件,重点是Geometry Shader的代码:
struct GSIn
{
    float4 pos          : POSITION;
};
 
GSIn VS_Bezier(int i : TEXCOORD0)
{
    GSIn Output;
    Output.pos = pos[i];
    return Output;
}
 
[maxvertexcount(100)]
void GS_Bezier(line GSIn input[2], inout LineStream<PS_INPUT> LineOutputStream)
{
         float2 positions[4];
         positions[0]=input[0].pos.xy;
         positions[1]=input[0].pos.zw;
         positions[2]=input[1].pos.xy;
         positions[3]=input[1].pos.zw;
 
        for(int i=0;i<=99;i++)  
        {
                   float t1=i*0.01;  
                 float x1=positions[0].x*(1-t1)*(1-t1)*(1-t1)+positions[1].x*(1-t1)*(1-t1)*3*t1+positions[2].x*(1-t1)*3*t1*t1+positions[3].x*t1*t1*t1;  
                   float y1=positions[0].y*(1-t1)*(1-t1)*(1-t1)+positions[1].y*(1-t1)*(1-t1)*3*t1+positions[2].y*(1-t1)*3*t1*t1+positions[3].y*t1*t1*t1;  
 
                   float t2=(i+1)*0.01;  
                 float x2=positions[0].x*(1-t2)*(1-t2)*(1-t2)+positions[1].x*(1-t2)*(1-t2)*3*t2+positions[2].x*(1-t2)*3*t2*t2+positions[3].x*t2*t2*t2;  
                   float y2=positions[0].y*(1-t2)*(1-t2)*(1-t2)+positions[1].y*(1-t2)*(1-t2)*3*t2+positions[2].y*(1-t2)*3*t2*t2+positions[3].y*t2*t2*t2;  
 
                   PS_INPUT output1;
                   output1.Pos=float4(x1,y1,0.0f,1.0f);
                   output1.color=float4(1,1,1,1);
                   output1.uv=float2(0,0);
                   LineOutputStream.Append(output1);
 
                   PS_INPUT output2;
                   output2.Pos=float4(x2,y2,0.0f,1.0f);
                   output2.color=float4(1,1,1,1);
                   output2.uv=float2(0,0);
                   LineOutputStream.Append(output2);
 
                   LineOutputStream.RestartStrip();
         }
}
 
float4 PS_Bezier(PS_INPUT input) : SV_Target
{
         return input.color;
}
 
technique10 Bezier
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS_Bezier() ) );
        SetGeometryShader( CompileShader( gs_4_0, GS_Bezier() ) ); 
        SetPixelShader( CompileShader( ps_4_0, PS_Bezier() ) );
        SetBlendState( AdditiveBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );       
        SetDepthStencilState( DisableDepth, 0 );       
    }
}
 
下面是CPP文件,需要在其中调用IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_LINELIST )设置输入IA为线段列类型:
HRESULT G2DGraphics::DrawBezier(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4,DWORD color)
{
         HRESULT hr=S_OK;
 
         ID3D10Device* pd3dDevice=GGraphicsDevice::GetDevice();
 
         //透明则略过
         if (color>>24==0)
                  return S_OK;
 
         float fdevvicewidth=(float)(GGraphicsDevice::GetDeviceWidth());
         float fdeviceheight=(float)(GGraphicsDevice::GetDeviceHeight());
 
         float4 positions[4];
         float4 colors[4];
         float4 uvs[4];
 
    positions[0].x=((float)(x1)/fdevvicewidth-0.5f)*2.0f;
    positions[0].y=((float)(y1)/fdeviceheight-0.5f)*-2.0f;
    positions[0].z=((float)(x2)/fdevvicewidth-0.5f)*2.0f;
    positions[0].w=((float)(y2)/fdeviceheight-0.5f)*-2.0f;
    colors[0]=ConvertColorFromDwordToFloat4(color);
 
    positions[1].x=((float)(x3)/fdevvicewidth-0.5f)*2.0f;
    positions[1].y=((float)(y3)/fdeviceheight-0.5f)*-2.0f;
    positions[1].z=((float)(x4)/fdevvicewidth-0.5f)*2.0f;
    positions[1].w=((float)(x4)/fdevvicewidth-0.5f)*2.0f;
    colors[1]=ConvertColorFromDwordToFloat4(color);
 
         g_VertexPositions->SetFloatVectorArray((float*)&positions,0,4);
         g_VertexColors->SetFloatVectorArray((float*)&colors,0,4);
 
         // Set the input layout
         pd3dDevice->IASetInputLayout( g_pVertexLayout );
 
         // Set vertex buffer
         UINT stride = sizeof( UINT );
         UINT offset = 0;
         pd3dDevice->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
 
         pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_LINELIST );
         D3D10_TECHNIQUE_DESC techDesc;
         g_pBezierTech->GetDesc( &techDesc );
         for( UINT p = 0; p < techDesc.Passes; ++p )
         {
                   g_pBezierTech->GetPassByIndex( p )->Apply(0);
                   pd3dDevice->Draw( 2, 0 );
         }
 
        return S_OK;
        
}
 

 
2. 圆形在Geometry Shader下的实现
圆形在图形绘制中也经常用到,由半径和中心坐标控制,下面是实现的HLSL代码,同样也是通过把圆形细分为特定数量线段进行逼近,根据角度计算圆形上线段的两端顶点.
 
[maxvertexcount(100)]
void GS_Circle(point GSIn input[1], inout LineStream<PS_INPUT> LineOutputStream)
{
 
       int number=40;
       float2 position=input[0].pos.xy;
       float radius=input[0].pos.z;
       float dangle=3.1415926f*2.0f/number;
 
        for(int i=0;i<number;i++)  
        {
              float t1=i*dangle;  
               float x1=radius*cos(t1)+position.x;  
              float y1=radius*sin(t1)+position.y;  
 
              float t2=(i+1)*dangle;  
               float x2=radius*cos(t2)+position.x;  
              float y2=radius*sin(t2)+position.y;  
 
              PS_INPUT output1;
              output1.Pos=float4(x1,y1,0.0f,1.0f);
              output1.color=float4(1,1,1,1);
              output1.uv=float2(0,0);
              LineOutputStream.Append(output1);
 
              PS_INPUT output2;
              output2.Pos=float4(x2,y2,0.0f,1.0f);
              output2.color=float4(1,1,1,1);
              output2.uv=float2(0,0);
              LineOutputStream.Append(output2);
 
              LineOutputStream.RestartStrip();
       }
}
 
下面是CPP文件,输入类型为D3D10_PRIMITIVE_TOPOLOGY_POINTLIST,因为只需要圆心坐标(x,y)和半径,用一个四维顶点就可以存储了.
HRESULT G2DGraphics::DrawCircle(float x,float y,float r,DWORD color)
{
     HRESULT hr=S_OK;
 
     ID3D10Device* pd3dDevice=GGraphicsDevice::GetDevice();
 
     //透明则略过
     if (color>>24==0)
         return S_OK;
 
     float fdevvicewidth=(float)(GGraphicsDevice::GetDeviceWidth());
     float fdeviceheight=(float)(GGraphicsDevice::GetDeviceHeight());
 
     float4 positions[4];
     float4 colors[4];
     float4 uvs[4];
 
    positions[0].x=((float)(x)/fdevvicewidth-0.5f)*2.0f;
    positions[0].y=((float)(y)/fdeviceheight-0.5f)*-2.0f;
    positions[0].z=((float)(r)/fdevvicewidth)*2.0f;
    colors[0]=ConvertColorFromDwordToFloat4(color);
 
     g_VertexPositions->SetFloatVectorArray((float*)&positions,0,4);
     g_VertexColors->SetFloatVectorArray((float*)&colors,0,4);
 
     // Set the input layout
     pd3dDevice->IASetInputLayout( g_pVertexLayout );
 
     // Set vertex buffer
     UINT stride = sizeof( UINT );
     UINT offset = 0;
     pd3dDevice->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
 
     pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_POINTLIST );
     D3D10_TECHNIQUE_DESC techDesc;
     g_pCircleTech->GetDesc( &techDesc );
     for( UINT p = 0; p < techDesc.Passes; ++p )
     {
         g_pCircleTech->GetPassByIndex( p )->Apply(0);
         pd3dDevice->Draw( 1, 0 );
     }
 
     return S_OK;
    
}

 
介绍了两种简单的二维图形在Geometry Shader的绘制后,在学习笔记3里将介绍较为复杂的Geometry Shader下的LOD应用.
 
 
 
原创粉丝点击