GPU编程入门(二) 象素shader

时间:2022-05-21 20:03:18

好,给出一个最简单的像素shader(pixel shader)的例子,照例,这个程序什么也没作,只是把输入又输出了一下而已

  //定义一个输出结构

struct OUTPUT...{
    float4 color :COLOR;
}
//像素shader入口函数

OUTPUT main(float4 color:COLOR)...{
    OUTPUT OUT;
    OUT.color=color;
  return OUT;
    }

关于这个程序,不需要说太多吧,应该能看懂大部分了吧

像素shader就是在每个像素进行光栅化(raster)处理期间在图形卡的GPU上执行的程序,赋予了我们直接操纵每个像素和访问像素纹理的能力。这样可以达到多种游戏力的特效效果,例如多纹理化(mulittexturing)等。相比于顶点shader必须输出一个POSITION 像素shader则必须输出一个COLOR或者是一个TEXCOORD信息,道理也是不言自明的吧

关于像素程序本身就说这么多吧,其实顶点shader和像素shader很像的东西,只是处理的对象的不同而已,理解了一个理解另一个自然很方便。

下面随便扯点关于hlsl本身的一些问题

关于上面的float4,这不是一个关键字,而只是标识一个向量(vector)数据类型,前面有说道过hlsl中向量是作为了一种基本的数据类型的,所以提供了对向量运算的天然支持,就是快,所以不必当心效率问题,说到向量,先得提下hlsl支持的基本数据类型,int ,float,half,double,bool,有点编程基础的兄弟都能明白,不过这里的int有点特殊,int和half不是所有的显卡都支持的,而且使用上也有很多限制,图形显示器处理float和int一样快的,是没有效率问题的,虽然现在的CPU也这样了,可是很多的编程书籍还是说float比int慢...这里要说的就是尽量用float就是了,具体的原因...一两句话说不清楚,哪天有空了再写上来,总之就是GPU的特殊性(哈哈~~)我记得得话一定写上来

你可以这样声明一个向量

vector(<type,size>)(括号表示可选,如果没有括号,则表示一个四元的向量)type参数表示的是这个向量中数据的类型,例如是float int什么的,size则是向量的大小,维数 例如,你可以声明一个四元向量:

float4 v;

vector v;

vector<float,4> v;

float v[4]; 以上这些声明表达的就是一个意思,看个人喜好了

初始化和C没什么区别 你可以这样,float4 V={0,0,0,0}

另一个非常常用的数据类型就是矩阵(matrix)了,矩阵就是向量的数组,有行矩阵和列矩阵的区别

声明一个矩阵,可以这样:

float4×4 M;

matrix<float,4,4> M;//原理同vector,初始化也是一样的

还有,说一个想到的,那就是顶点shader和像素shader之间的数据传递问题,这个主要是通过由顶点程序输出语义为TEXCOORD或者是COLOR的参数而像素程序调用,就是这样的...

好了,关于hlsl的基本语法就说这么多,其实主要是我烦了,一门语言的语法点显然是非常多的,要说得面面俱到那就是对着文档写书了,这个教程本来就没打算写成那样的东西,而且我也显然不是那块料,这里只是说一些基本的东西,能让你看得懂我以后写的一些东西,想深入的学习这么语言,一本好的书是必要的,现在市面上中文的比较少,不过很多blog都有写这样的东西,不一定全,不过你要认真研究了差不多了,要认真的话看E文去吧,不要说E文不好的故事,想优秀E文是少不了的,而且痛苦值暂时的,等哪天你有了阅读E文文章的能力,然后你发现找工作的时候基本都有这个要求的时候记得感谢我

下面给出一个完整的使用vs 和ps的例子,例子没做什么,只是让大家知道一个shader和direcetx是怎么结合起来的,看例子:  vertex shader://first_vs.txt


matrix WVPMatrix;
vector color;

struct VS_INPUT
...{
vector position : POSITION;
};

struct VS_OUTPUT
...{
vector position : POSITION;
vector color : COLOR;
};

VS_OUTPUT main(VS_INPUT input)
...{
VS_OUTPUT output = (VS_OUTPUT)0;

output.position = mul(input.position, WVPMatrix);
output.color = color;

return output;
}

//顶点程序没做什么,只是设置了顶点的位置坐标,然后输出一个color到片段程序

pixel shader//first_ps.txt

struct Output ...{
   vector color : COLOR;
};

Output ps_main(vector color : COLOR)
...{
   Output OUT;
float4 _color=...{1,0,0,1};
   OUT.color = _color;
   return OUT;
}

//简单的输出黄色


下面是一个directx程序,创建一个三角形,然后用上面的两个程序渲染~~看代码

#include "d3dUtility.h"
#define ReleaseCOM(x) {if(x!=NULL) x->Release(); x=NULL;}
//
// Globals
//

IDirect3DDevice9* Device = 0;

const int Width   = 640;
const int Height = 480;

IDirect3DVertexBuffer9* Triangle = 0; // vertex buffer to store
                                       // our triangle data.

//pointer about the shader
IDirect3DVertexShader9* BasicShader = 0;//vs pointer
IDirect3DPixelShader9*   PixelShader = 0;//ps pointer
ID3DXConstantTable* BasicConstTable = 0;//vs constant table pointer
ID3DXConstantTable* PixelConstTable = 0;//ps constant table pointer
D3DXHANDLE WVPMatrixHandle           = 0;//matrix handle
D3DXHANDLE ColorHandle               = 0;//color handle

//
// Classes and Structures
//
struct Vertex
...{
Vertex()...{}

Vertex(float x, float y, float z)
...{
   _x = x;   _y = y;   _z = z;
}

float _x, _y, _z;
DWORD _color;
static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ|D3DFVF_DIFFUSE;

//
// Framework Functions
//
bool Setup()
...{
//
// Create the vertex buffer.
//
ID3DXBuffer* shaderBuffer       = 0;
ID3DXBuffer* errorBuffer        = 0;
Device->CreateVertexBuffer(
   3 * sizeof(Vertex), // size in bytes
   D3DUSAGE_WRITEONLY, // flags
   Vertex::FVF,         // vertex format
   D3DPOOL_MANAGED,     // managed memory pool
   &Triangle,           // return create vertex buffer
   0);                  // not used - set to 0

//
// Fill the buffers with the triangle data.
//

Vertex* vertices;
Triangle->Lock(0, 0, (void**)&vertices, 0);

vertices[0] = Vertex(-1.0f, 0.0f, 2.0f);
vertices[1] = Vertex( 0.0f, 1.0f, 2.0f);
vertices[2] = Vertex( 1.0f, 0.0f, 2.0f);

     vertices[0]._color=D3DCOLOR_XRGB(250,0,0);
Triangle->Unlock();

//
// Set the projection matrix.
//

D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
    &proj,                         // result
    D3DX_PI * 0.5f,                // 90 - degrees
    (float)Width / (float)Height, // aspect ratio
    1.0f,                          // near plane
    1000.0f);                      // far plane
Device->SetTransform(D3DTS_PROJECTION, &proj);

//创建vertex shader
HRESULT hr = D3DXCompileShaderFromFile("first_vs.txt",
              0,
              0,
              "main", // entry point function name
              "vs_1_1",
              D3DXSHADER_DEBUG,
              &shaderBuffer,
              &errorBuffer,
              &BasicConstTable);

// output any error messages
if(errorBuffer)
...{
   MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0, 0);
   ReleaseCOM(errorBuffer);
   exit(0);
}

if(FAILED(hr))
...{
   MessageBox(0, "D3DXCompileShaderFromFile() - FAILED", 0, 0);
   return false;
}

hr = Device->CreateVertexShader((DWORD*)shaderBuffer->GetBufferPointer(), &BasicShader);

if(FAILED(hr))
...{
   MessageBox(0, "CreateVertexShader - FAILED", 0, 0);
   return false;
}


ReleaseCOM(shaderBuffer);

//创建pixel shader

HRESULT hr2 = D3DXCompileShaderFromFile("first_ps.txt",
              0,
              0,
              "ps_main", // entry point function name
              "ps_1_1",
              D3DXSHADER_DEBUG,
              &shaderBuffer,
              &errorBuffer,
              &PixelConstTable);

// output any error messages
if(errorBuffer)
...{
   MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0, 0);
   ReleaseCOM(errorBuffer);
   exit(0);
}

if(FAILED(hr2))
...{
   MessageBox(0, "D3DXCompileShaderFromFile() - FAILED", 0, 0);
   return false;
}

hr2 = Device->CreatePixelShader((DWORD*)shaderBuffer->GetBufferPointer(), &PixelShader);

if(FAILED(hr2))
...{
   MessageBox(0, "CreateVertexShader - FAILED", 0, 0);
   return false;
}
ReleaseCOM(shaderBuffer);

WVPMatrixHandle = BasicConstTable->GetConstantByName(0, "WVPMatrix");ColorHandle = BasicConstTable->GetConstantByName(0, "color");
BasicConstTable->SetDefaults(Device);

//set light false so we can see the triangle's color
Device->SetRenderState(D3DRS_LIGHTING, false);

return true;
}
void Cleanup()
...{
d3d::Release<IDirect3DVertexBuffer9*>(Triangle);
      ReleaseCOM(BasicShader);
     ReleaseCOM(BasicConstTable);

      ReleaseCOM(PixelShader);
     ReleaseCOM(PixelConstTable);
}

bool Display(float timeDelta)
...{
if( Device )
...{
   Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(153,153,153), 1.0f, 0);
   Device->BeginScene();
         Device->SetStreamSource(0, Triangle, 0, sizeof(Vertex));
   Device->SetFVF(Vertex::FVF);
 
   D3DXMATRIX matWorld, matView, matProj;
      Device->GetTransform(D3DTS_WORLD, &matWorld);
      Device->GetTransform(D3DTS_VIEW, &matView);
      Device->GetTransform(D3DTS_PROJECTION, &matProj);

      D3DXMATRIX matWVP = matWorld * matView * matProj;
    
     //set the globals 设置shader程序的全局变量,这里为了显示有和没有pixel shader的区别,先设置了一个颜色,然后用ps修改
      BasicConstTable->SetMatrix(Device, WVPMatrixHandle, &matWVP);
      D3DXVECTOR4 color(1.0f, 1.0f, 0.0f, 1.0f);
      BasicConstTable->SetVector(Device, ColorHandle, &color);
 
   //use the shader 使用shader
   Device->SetVertexShader(BasicShader);
   Device->SetPixelShader(PixelShader);
   // Draw one triangle.
   Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

   Device->EndScene();
   Device->Present(0, 0, 0, 0);
}
return true;
}


//
// WndProc
//
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
...{
switch( msg )
...{
case WM_DESTROY:
   ::PostQuitMessage(0);
   break;
 
case WM_KEYDOWN:
   if( wParam == VK_ESCAPE )
    ::DestroyWindow(hwnd);
   break;
}
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}

//
// WinMain
//
int WINAPI WinMain(HINSTANCE hinstance,
        HINSTANCE prevInstance,
        PSTR cmdLine,
        int showCmd)
...{
if(!d3d::InitD3D(hinstance,
   Width, Height, true, D3DDEVTYPE_HAL, &Device))
...{
   ::MessageBox(0, "InitD3D() - FAILED", 0, 0);
   return 0;
}
 
if(!Setup())
...{
   ::MessageBox(0, "Setup() - FAILED", 0, 0);
   return 0;
}

d3d::EnterMsgLoop( Display );

Cleanup();

Device->Release();

return 0;
}

运行程序,毫无新意,就是一个黄色的三角形

大部分都是有注释的,能看懂的吧,很早写的程序了,肯定很乱的,凑合吧

这里为了显示有没有ps的区别,先是用vs把三角形的颜色设成绿色,然后用ps改成黄色(吃饱撑的,哈哈)你可是注释掉关于ps的那部分代码,一样能工作的 去掉vs 同样能的,哈哈

前面说了,这个程序只是向你展示怎么用,怎么结合,下节就不会给出directx程序了,只给出shader,自己运行吧 出错就是你进步的开始

下次贴个纹理混合吧~~

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/gamedevers/archive/2007/05/21/1619881.aspx