• DirectX9:第四部分 顶点着色器


    一.简介

    顶点着色器(Vertex Shader)是一段运行在图形卡GPU中的程序,它可取代固定流水线(渲染管线)中的变换光照环节

    二.使用顶点着色器的步骤

    (1)顶点声明的创建使用

    在使用固定流水线(渲染管线)的时候,使用灵活的顶点格式(FVF)来描述顶点结构的分量

    在可编程流水线中,顶点结构的描述为一个 D3DVERTEXELEMENT9 类型的结构数组,该结构数组中的每个元素都描述了顶点结构的一个分量

    D3DVERTEXELEMENT9 decl[] =
    {
       {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
        {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
      D3DDECL_END() 
    };
    
    // 顶点声明的创建
    g_pd3dDevice->CreateVertexDeclaration(decl, &VertexDecl);
    
    // 顶点声明的启用
    g_pd3dDevice->SetVertexDeclaration(VertexDecl);
    

    (2)编写顶点着色器程序

    // Globals
    matrix ViewProjMatrix;
    
    // Structures
    struct VS_INPUT
    {
       vertor position : POSITION;
       vector color : COLOR;      
    };    
    
    struct VS_OUTPUT
    {
       vector position : POSITION;
       vector diffuse : COLOR;      
    };
    
    VS_OUTPUT Main(VS_INPUT input)
    {
      VS_OUTPUT output = (VS_OUTPUT)0;
      output.position = mul(input.position, ViewProjMatrix);
      output.diffuse = input.color;
    
      return output;   
    }
    

    (3)编译顶点着色器程序

    HRESULT hr = 0;
    ID3DXBuffer* shader = 0;
    ID3DXBuffer* errorBuffer =0;
    
    hr = D3DXCompileShaderFromFile(
        L"shade.txt",
        0,
        0,
        "Main",
        "vs_1_1",
        D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY,
        &shader,
        &errorBuffer,
        &VertexConstantTable);
    

    (4)创建IDirect3DVertexShader9

    hr = g_pd3dDevice->CreateVertexShader((DWORD*)shader->GetBufferPointer(), &TriangleShader);
    

    (5)绑定顶点着色器

    g_pd3dDevice->SetVertexShader(TriangleShader);
    

    (6)释放顶点着色器

    if(TriangleShader != NULL)
        TriangleShader->Release();
    

    三.例子

    1.彩色三角形

    #include <Windows.h>
    #include <mmsystem.h>
    #include <d3dx9.h>
    #pragma warning( disable : 4996 ) // disable deprecated warning 
    #include <strsafe.h>
    #pragma warning( default : 4996 )
    #include <d3dx9math.h>
     
    LPDIRECT3D9             g_pD3D = NULL; 
    LPDIRECT3DDEVICE9       g_pd3dDevice = NULL;
    LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; 
    LPDIRECT3DVERTEXSHADER9 TriangleShader = NULL;
    LPDIRECT3DVERTEXDECLARATION9 VertexDecl = NULL;
    LPD3DXCONSTANTTABLE VertexConstantTable = NULL;
    D3DXHANDLE ViewProjMatrixHandle = NULL;
     
    struct CUSTOMVERTEX
    {
    	FLOAT x, y, z;
    	DWORD color;
    };
     
    bool VertexShader()
    {
    	if(TriangleShader)
    		return true;
     
    	HRESULT hr = 0;
    	ID3DXBuffer* shader = 0;
    	ID3DXBuffer* errorBuffer = 0;
     
    	hr = D3DXCompileShaderFromFile(
    		L"shade.txt",
    		0,
    		0,
    		"Main",
    		"vs_1_1",
    		D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY,
    		&shader,
    		&errorBuffer,
    		&VertexConstantTable);
     
    	hr = g_pd3dDevice->CreateVertexShader(
    		(DWORD*)shader->GetBufferPointer(),
    		&TriangleShader);
     
    	if(shader)
    		shader->Release();
     
    	if(errorBuffer)
    		errorBuffer->Release();
    	return true;
    }
     
    bool VertexBuffer()
    {
    	if(g_pVB)
    		return true;
     
    	g_pd3dDevice->CreateVertexBuffer(
    		3 * sizeof(CUSTOMVERTEX), 
    		0,
    		0,
    		D3DPOOL_MANAGED,
    		&g_pVB,
    		0);
     
    	CUSTOMVERTEX* v;
    	g_pVB->Lock(0, 0, (void**)&v, 0);
     
    	v[0].x = -1, v[0].y = -1, v[0].z = 0, v[0].color = D3DCOLOR_XRGB(255, 0, 0);
    	v[1].x = 0, v[1].y = 1, v[1].z = 0, v[1].color = D3DCOLOR_XRGB(0, 255, 0);
    	v[2].x = 1, v[2].y = -1, v[2].z = 0, v[2].color = D3DCOLOR_XRGB(0, 0, 255);
    	
    	g_pVB->Unlock();
    	return true;
    }
     
    bool VertexDeclaration()
    {
    	if(VertexDecl)
    		return true;
     
    	D3DVERTEXELEMENT9 decl[] = 
    	{
    		{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
    		{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
    		D3DDECL_END()
    	};
    	g_pd3dDevice->CreateVertexDeclaration(decl, &VertexDecl);
    	g_pd3dDevice->SetVertexDeclaration(VertexDecl);
     
    	return true;
    }
     
    bool GetHandles()
    {
    	if(ViewProjMatrixHandle)
    		return true;
     
    	ViewProjMatrixHandle = VertexConstantTable->GetConstantByName(0, "ViewProjMatrix");
    	VertexConstantTable->SetDefaults(g_pd3dDevice);
     
    	return true;
    }
     
    HRESULT InitD3D(HWND hWnd)
    {
    	if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
    		return E_FAIL;
     
    	// Set up the structure used to create the D3DDevice
    	D3DPRESENT_PARAMETERS d3dpp;
    	ZeroMemory(&d3dpp, sizeof(d3dpp));
    	d3dpp.Windowed = TRUE;
    	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
    	d3dpp.EnableAutoDepthStencil = TRUE;
            d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
    	// Create the D3DDevice
    	if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
    		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
    		&d3dpp, &g_pd3dDevice)))
    	{
    		return E_FAIL;
    	}
    	return S_OK;
    }
     
    VOID SetupMatrices()
    {
    	D3DXVECTOR3 vEyePt(0.0f, 0.0f, -5);
    	D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);
    	D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);
    	D3DXMATRIXA16 matView;
    	D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
     
    	//D3DXMatrixPerspectiveFovLH()函数中的最远、最近距离为相对于视点的距离(即vEyePt中的距离)
    	D3DXMATRIXA16 matProj;
    	D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f, 200.0f);
     
    	D3DXMATRIX ViewProjMatrix = matView * matProj;
    	VertexConstantTable->SetMatrix(g_pd3dDevice, ViewProjMatrixHandle, &ViewProjMatrix);
    }
     
    VOID Cleanup()
    {
    	if (g_pVB != NULL)
    		g_pVB->Release();
     
    	if (g_pd3dDevice != NULL)
    		g_pd3dDevice->Release();
     
    	if (g_pD3D != NULL)
    		g_pD3D->Release();
     
    	if (TriangleShader != NULL)
    		TriangleShader->Release();
     
    	if (VertexDecl != NULL)
    		VertexDecl->Release();
     
    	if (VertexConstantTable != NULL)
    		VertexConstantTable->Release();
    }
     
    int Render()
    {
    	VertexBuffer();
    	VertexShader();
    	VertexDeclaration();
    	GetHandles();
    	SetupMatrices();
     
    	g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0);
     
    	if (SUCCEEDED(g_pd3dDevice->BeginScene()))
    	{
    		g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
    		g_pd3dDevice->SetVertexShader(TriangleShader);
     
    		g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
    		g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
    		g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    		g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,1);
     
    		g_pd3dDevice->EndScene();
    	}
    	g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
     
    	return 0;
    }
     
    LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	switch (msg)
    	{
    	case WM_DESTROY:
    		Cleanup();
    		PostQuitMessage(0);
    		return 0;
    	}
     
    	return DefWindowProc(hWnd, msg, wParam, lParam);
    }
     
    INT WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, INT)
    {
    	UNREFERENCED_PARAMETER(hInst);
     
    	// Register the window class
    	WNDCLASSEX wc =
    	{
    		sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
    		GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
    		L"D3D Tutorial", NULL
    	};
    	RegisterClassEx(&wc);
     
    	// Create the application's window
    	HWND hWnd = CreateWindow(L"D3D Tutorial", L"D3D: VertexShader",
    		WS_OVERLAPPEDWINDOW, 100, 100, 700, 700,
    		NULL, NULL, wc.hInstance, NULL);
     
    	if (SUCCEEDED(InitD3D(hWnd)))
    	{
    			ShowWindow(hWnd, SW_SHOWDEFAULT);
    			UpdateWindow(hWnd);
     
    			MSG msg;
    			ZeroMemory(&msg, sizeof(msg));
    			while (msg.message != WM_QUIT)
    			{
    				if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
    				{
    					TranslateMessage(&msg);
    					DispatchMessage(&msg);
    				}
    				else
    					Render();
    			}
    	}
     
    	UnregisterClass(L"D3D Tutorial", wc.hInstance);
    	return 0;
    }
    

    2.蓝色茶壶

    ////////////////////////////////////////////////////////////////////////////
    // 
    // File: transform.txt
    // 
    // Author: Frank Luna (C) All Rights Reserved
    //
    // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 
    //
    // Desc: Vertex shader that transforms a vertex by the view and 
    //       projection transformation, and sets the vertex color to blue.
    //          
    ////////////////////////////////////////////////////////////////////////////
    
    //
    // Globals
    //
    
    // Global variable to store a combined view and projection
    // transformation matrix.  We initialize this variable
    // from the application.
    matrix ViewProjMatrix;
    
    // Initialize a global blue color vector.
    vector Blue = {0.0f, 0.0f, 1.0f, 1.0f};
    
    //
    // Structures
    //
    
    // Input structure describes the vertex that is input
    // into the shader.  Here the input vertex contains
    // a position component only.
    struct VS_INPUT
    {
        vector position  : POSITION;
    };
    
    // Output structure describes the vertex that is
    // output from the shader.  Here the output
    // vertex contains a position and color component.
    struct VS_OUTPUT
    {
        vector position : POSITION;
        vector diffuse  : COLOR;
    };
    
    //
    // Main Entry Point, observe the main function 
    // receives a copy of the input vertex through
    // its parameter and returns a copy of the output
    // vertex it computes.
    //
    
    VS_OUTPUT Main(VS_INPUT input)
    {
        // zero out members of output
        VS_OUTPUT output = (VS_OUTPUT)0;
     
        // transform to view space and project
        output.position  = mul(input.position, ViewProjMatrix);
    
        // set vertex diffuse color to blue
        output.diffuse = Blue;
    
        return output;
    }
    
    //////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    // File: colorTriangle.cpp
    // 
    // Author: Frank Luna (C) All Rights Reserved
    //
    // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 
    //
    // Desc: Renders two colored triangles, one shaded with flat shading and the
    //       other shaded with Gouraud shading.  Demontrates vertex colors and,
    //       the shading render states.
    //          
    //////////////////////////////////////////////////////////////////////////////////////////////////
    
    #include "d3dUtility.h"
    
    //
    // Globals
    //
    
    IDirect3DDevice9* Device = 0; 
    
    const int Width  = 640;
    const int Height = 480;
    
    // 顶点着色器
    IDirect3DVertexShader9* TransformShader = 0;
    
    // 常量表
    ID3DXConstantTable* TransformConstantTable = 0;
    
    // 茶壶模型
    ID3DXMesh* Teapot = 0;
    
    // 
    D3DXHANDLE TransformViewProjHandle = 0;
    
    // 投影矩阵
    D3DXMATRIX ProjMatrix;
    
    
    //
    // Framework Functions
    //
    bool Setup()
    {
    	HRESULT hr = 0;
    
    	//
    	// 创建茶壶模型
    	//
    
    	D3DXCreateTeapot(Device, &Teapot, 0);
    
    	//
    	// 缓存
    	// 
    
    	ID3DXBuffer* shader = 0;
    	ID3DXBuffer* errorBuffer = 0;
    
    
    	// 加载shader文件,设立缓存区
    	hr = D3DXCompileShaderFromFile(
    		"transform.txt",
    		0,
    		0,
    		"Main",
    		"vs_1_1",
    		D3DXSHADER_DEBUG,
    		&shader,
    		&errorBuffer,
    		&TransformConstantTable
    		);
    
    	// 如果shader文件错误
    	if (errorBuffer)
    	{
    		::MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0, 0);
    		d3d::Release<ID3DXBuffer*>(errorBuffer);
    	}
    
    	// 如果加载出错
    	if (FAILED(hr))
    	{
    		::MessageBoxA(0, (char*)errorBuffer->GetBufferPointer(), 0, 0);
    		d3d::Release<ID3DXBuffer*>(errorBuffer);
    	}
    
    	// 根据缓存区创建顶点着色器
    	hr = Device->CreateVertexShader(
    		(DWORD*)shader->GetBufferPointer(),
    		&TransformShader);
    
    	if (FAILED(hr))
    	{
    		::MessageBox(0, "CreateVertexShader-FAILED", 0, 0);
    		return false;
    	}
    
    	// 释放缓存区
    	d3d::Release<ID3DXBuffer*>(shader);
    
    	//
    	// Get Handles
    	//
    
    	TransformViewProjHandle = TransformConstantTable->GetConstantByName(0, "ViewProjMatrix");
    
    	//
    	// Set shader contants
    	//
    
    	TransformConstantTable->SetDefaults(Device);
    
    	// 
    	// 设置投影矩阵,设置一个圆锥体投影
    	//
    
    	D3DXMatrixPerspectiveFovLH(&ProjMatrix, D3DX_PI * 0.25f, (float)Width / (float)Height, 1.0f, 1000.0f);
    
    	//
    	// 设置线框模式
    	//
    
    	//Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
    
    	return true;
    }
    
    void Cleanup()
    {
    	d3d::Release<ID3DXMesh*>(Teapot);
    	d3d::Release<IDirect3DVertexShader9*>(TransformShader);
    	d3d::Release<ID3DXConstantTable*>(TransformConstantTable);
    }
    
    bool Display(float timeDelta)
    {
    	if (Device)
    	{
    
    		//
    		// Update the scene: Allow user to rotate around scene
    		//
    
    		static float angle = (3.0f * D3DX_PI) / 2.0f;
    		static float height = 5.0f;
    
    		if (::GetAsyncKeyState(VK_LEFT) & 0x8000f)
    			angle -= 0.5f * timeDelta;
    
    		if (::GetAsyncKeyState(VK_RIGHT) & 0x8000f)
    			angle += 0.5f * timeDelta;
    
    		if (::GetAsyncKeyState(VK_UP) & 0x8000f)
    			height += 5.0f * timeDelta;
    
    		if (::GetAsyncKeyState(VK_DOWN) & 0x8000f)
    			height -= 5.0f * timeDelta;
    
    		D3DXVECTOR3 position( cosf(angle) * 10.0f, height, sinf(angle) * 10.0f);
    		D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
    		D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
    		D3DXMATRIX V;
    		D3DXMatrixLookAtLH(&V, &position, &target, &up);
    
    		D3DXMATRIX ViewProj = V * ProjMatrix;
    
    		TransformConstantTable->SetMatrix(Device, TransformViewProjHandle, &ViewProj);
    
    		//
    		// Render
    		//
    
    		Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
    		Device->BeginScene();
    
    		Device->SetVertexShader(TransformShader);
    
    		Teapot->DrawSubset(0);
    
    		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;
    }
    
  • 相关阅读:
    浅析Python中bytes和str区别
    Python面对对象相关知识总结
    Django实现微信公众号简单自动回复
    阿里云部署django实现公网访问
    JDBC学习笔记(1)——JDBC概述
    Java单元测试初体验(JUnit4)
    Java设计模式系列之动态代理模式(转载)
    Java设计模式系列之责任链模式
    Java设计模式系列之观察者模式
    局部内部类和匿名内部类的对比
  • 原文地址:https://www.cnblogs.com/k5bg/p/11088553.html
Copyright © 2020-2023  润新知