天天看点

四面体简单光照渲染+漫游(使用多个ConstantBuffer减小带宽)

建立了三个ConstantBuffer,一个是每一帧都需要从cpu传过来的用来旋转的world矩阵,一个是摄影机操作后传过来的view矩阵,还有一个是只传过来一次的projection矩阵和两个方向光的向量

1.lighting.fx

// Constant Buffer Variables
cbuffer CBChangesEveryFrame : register( b0 )
{
	matrix World;
};

cbuffer CBChangesWhenMoving : register( b1 )
{
	matrix View;
}

cbuffer CBNeverChange : register( b2 )
{
	matrix Projection;
	float4 vLightDir[2];
};

struct VS_INPUT
{
    float4 Pos : POSITION;
    float3 Norm : NORMAL;
};

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float3 Norm : TEXCOORD0;
};
// 以上都是声明

// Vertex Shader
PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;
    output.Pos = mul( input.Pos, World );
    output.Pos = mul( output.Pos, View );
    output.Pos = mul( output.Pos, Projection );
	output.Norm = mul( float4(input.Norm, 1), World ).xyz;// .xyz指取前三位向量,等式左边的PS_INPUT中的Norm是float3型,而右边是float4型
	// 也可写成output.Norm = mul( input.Norm, (float3x3)World );
    
    return output;
}

// Pixel Shader
float4 PS( PS_INPUT input) : SV_Target
{
	static float4 vLightColor = {1.0f, 1.0f, 1.0f, 1.0f};
    float4 finalColor = 0;
	float k = 0.85f;// 反射率
    for(int i = 0; i < 2; i++)
    {
        finalColor += k * saturate(dot((float3)vLightDir[i], -input.Norm) * vLightColor);// 反射率 * saturate(dot(两光线向量·顶点法线向量)·颜色值),saturate表示饱和处理——大于1变为1,小于0变成0
    }
    finalColor.a = 1;// 同finalColor.w = 1; rgba对应xyzw
    return finalColor;
}
           

2.winmain.cpp

#include <windows.h>
#include <d3d11_1.h>
#include <d3dcompiler.h>
#include <directxmath.h>
#include <directxcolors.h>
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") 
// 找到项目的属性->链接器->输入->附加依赖项,在%(AdditionalDependencies)前追加上以下项:
// d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;
// 或者像下面这样添加代码:
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dcompiler.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "comctl32.lib")

using namespace DirectX;

struct VertexNormal
{
	XMFLOAT3 Pos;
	XMFLOAT3 Normal;
};

struct CBChangesEveryFrame
{
	XMMATRIX mWorld;
};

struct CBChangesWhenMoving
{
	XMMATRIX mView;
};

struct CBNeverChanges
{
	XMMATRIX mProjection;
	XMFLOAT4 vLightDir[2];
};

struct Camera
{
	Camera()
		: vAxisX(XMVectorSet(1.0f, 0.0f, 0.0f, 1.0f))
		, vAxisAim(XMVectorSet(1.0f, 0.0f, 0.0f, 1.0f))
		, vAxisY(XMVectorSet(0.0f, 1.0f, 0.0f, 1.0f))
		, vAxisZ(XMVectorSet(0.0f, 0.0f, 1.0f, 1.0f))
		, vPosition(XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f)) 
	{}
	Camera(const XMVECTOR & xAxis, const XMVECTOR & yAxis, const XMVECTOR & zAxis, const XMVECTOR & pos)
		: vAxisX(XMVector3Normalize(xAxis))
		, vAxisAim(XMVector3Normalize(xAxis))
		, vAxisY(XMVector3Normalize(yAxis))
		, vAxisZ(XMVector3Normalize(zAxis))
		, vPosition(pos)
	{}
	// 前后平移
	void XMove(float dx)
	{
		XMMATRIX move = XMMatrixTranslationFromVector(dx * vAxisX);
		vPosition = XMVector3TransformCoord(vPosition, move);
	}
	// 左右平移
	void YMove(float dy)
	{
		XMMATRIX move = XMMatrixTranslationFromVector(dy * vAxisY);
		vPosition = XMVector3TransformCoord(vPosition, move);
	}
	// 上下平移
	void ZMove(float dz)
	{
		XMMATRIX move = XMMatrixTranslationFromVector(dz * vAxisZ);
		vPosition = XMVector3TransformCoord(vPosition, move);
	}
	void ZSpin(float angle)
	{
		XMMATRIX mspin = XMMatrixRotationAxis(vAxisZ, angle);
		vAxisX = XMVector3Transform(vAxisX, mspin);
		vAxisAim = XMVector3Transform(vAxisAim, mspin);
		vAxisY = XMVector3Transform(vAxisY, mspin);
	}
	void YSpin(float angle)
	{
		XMMATRIX mspin = XMMatrixRotationAxis(vAxisY, angle);
		vAxisAim = XMVector3Transform(vAxisAim, mspin);
	}
	void ZoomIn(float in)
	{
		XMMATRIX move = XMMatrixTranslationFromVector(in * vAxisAim);
		vPosition = XMVector4Transform(vPosition, move);
	}
	XMVECTOR vEye() const {return vPosition;}
	XMVECTOR vUp() const {return XMVector4Transform(vAxisAim, XMMatrixRotationAxis(vAxisY, -XM_PIDIV2));}
	XMVECTOR vFocus() const {return vPosition + vAxisAim;}
	XMVECTOR vPosition;// 摄像机位矢
	XMVECTOR vAxisAim;// 瞄准轴(可以在摄像机vAxisX-vAxisZ平面内上下转动)
	XMVECTOR vAxisX;// 摄像机前后移动轴单位向量
	XMVECTOR vAxisY;// 摄像机左右移动轴单位向量
	XMVECTOR vAxisZ;// 摄像机上下移动轴单位向量
};

HINSTANCE				g_hInst = nullptr;
HWND					g_hWnd = nullptr;
D3D_DRIVER_TYPE				g_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVEL			g_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device*				g_pd3dDevice = nullptr;
ID3D11Device1*				g_pd3dDevice1 = nullptr;
ID3D11DeviceContext*			g_pImmediateContext = nullptr;
ID3D11DeviceContext1*			g_pImmediateContext1 = nullptr;
IDXGISwapChain*				g_pSwapChain = nullptr;
IDXGISwapChain1*			g_pSwapChain1 = nullptr;
ID3D11RenderTargetView*			g_pRenderTargetView = nullptr;
ID3D11Texture2D*			g_pDepthStencil = nullptr;
ID3D11DepthStencilView*			g_pDepthStencilView = nullptr;
ID3D11VertexShader*			g_pVertexShader = nullptr;
ID3D11PixelShader*			g_pPixelShader = nullptr;
ID3D11InputLayout*			g_pVertexLayout = nullptr;
ID3D11Buffer*				g_pVertexBuffer = nullptr;
ID3D11Buffer*				g_pCBChangesEveryFrame = nullptr;
ID3D11Buffer*				g_pCBChangesWhenMoving = nullptr;
ID3D11Buffer*				g_pCBNeverChange = nullptr;
Camera					g_Camera;

HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow );
HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut );
HRESULT InitDevice();
void CleanupDevice();
void KeyDownEvent(WPARAM wParam);
void MouseEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void CameraOperator(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
void Render();

int WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow )
{
	UNREFERENCED_PARAMETER( hPrevInstance );
	UNREFERENCED_PARAMETER( lpCmdLine );

	if( FAILED( InitWindow( hInstance, nCmdShow ) ) )
		return 0;

	if( FAILED( InitDevice() ) )
	{
		CleanupDevice();
		return 0;
	}

	MSG msg = {};
	while( WM_QUIT != msg.message )
	{
		if( PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) )
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
		else
		{
			Render();
		}
	}

	CleanupDevice();

	UnregisterClass(L"class1", g_hInst);

	return ( int )msg.wParam;
}

HRESULT InitDevice()
{
	HRESULT hr = S_OK;

	// 1.Create device
	RECT rc;
	GetClientRect( g_hWnd, &rc );
	UINT width = rc.right - rc.left;
	UINT height = rc.bottom - rc.top;

	UINT createDeviceFlags = 0;
#ifdef _DEBUG
	createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

	D3D_DRIVER_TYPE driverTypes[] =
	{
		D3D_DRIVER_TYPE_HARDWARE,
		D3D_DRIVER_TYPE_WARP,
		D3D_DRIVER_TYPE_REFERENCE,
	};
	UINT numDriverTypes = ARRAYSIZE( driverTypes );

	D3D_FEATURE_LEVEL featureLevels[] =
	{
		D3D_FEATURE_LEVEL_11_1,
		D3D_FEATURE_LEVEL_11_0,
		D3D_FEATURE_LEVEL_10_1,
		D3D_FEATURE_LEVEL_10_0,
	};
	UINT numFeatureLevels = ARRAYSIZE( featureLevels );

	for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
	{
		g_driverType = driverTypes[driverTypeIndex];
		hr = D3D11CreateDevice( nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
			D3D11_SDK_VERSION, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );

		if ( hr == E_INVALIDARG )
		{
			// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
			hr = D3D11CreateDevice( nullptr, g_driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1,
				D3D11_SDK_VERSION, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
		}

		if( SUCCEEDED( hr ) )
			break;
	}
	if( FAILED( hr ) )
		return hr;

	// Obtain DXGI factory from device (since we used nullptr for pAdapter above)
	IDXGIFactory1* dxgiFactory = nullptr;
	{
		IDXGIDevice* dxgiDevice = nullptr;
		hr = g_pd3dDevice->QueryInterface( __uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice) );
		if (SUCCEEDED(hr))
		{
			IDXGIAdapter* adapter = nullptr;
			hr = dxgiDevice->GetAdapter(&adapter);
			if (SUCCEEDED(hr))
			{
				hr = adapter->GetParent( __uuidof(IDXGIFactory1), reinterpret_cast<void**>(&dxgiFactory) );
				adapter->Release();
			}
			dxgiDevice->Release();
		}
	}
	if (FAILED(hr))
		return hr;

	// 2.Create swap chain
	IDXGIFactory2* dxgiFactory2 = nullptr;
	hr = dxgiFactory->QueryInterface( __uuidof(IDXGIFactory2), reinterpret_cast<void**>(&dxgiFactory2) );
	if ( dxgiFactory2 )
	{
		// DirectX 11.1 or later
		hr = g_pd3dDevice->QueryInterface( __uuidof(ID3D11Device1), reinterpret_cast<void**>(&g_pd3dDevice1) );
		if (SUCCEEDED(hr))
		{
			(void) g_pImmediateContext->QueryInterface( __uuidof(ID3D11DeviceContext1), reinterpret_cast<void**>(&g_pImmediateContext1) );
		}

		DXGI_SWAP_CHAIN_DESC1 sd;
		ZeroMemory(&sd, sizeof(sd));
		sd.Width = width;
		sd.Height = height;
		sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		sd.SampleDesc.Count = 1;
		sd.SampleDesc.Quality = 0;
		sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		sd.BufferCount = 1;

		hr = dxgiFactory2->CreateSwapChainForHwnd( g_pd3dDevice, g_hWnd, &sd, nullptr, nullptr, &g_pSwapChain1 );
		if (SUCCEEDED(hr))
		{
			hr = g_pSwapChain1->QueryInterface( __uuidof(IDXGISwapChain), reinterpret_cast<void**>(&g_pSwapChain) );
		}

		dxgiFactory2->Release();
	}
	else
	{
		// DirectX 11.0 systems
		DXGI_SWAP_CHAIN_DESC sd;
		ZeroMemory(&sd, sizeof(sd));
		sd.BufferCount = 1;
		sd.BufferDesc.Width = width;
		sd.BufferDesc.Height = height;
		sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		sd.BufferDesc.RefreshRate.Numerator = 60;
		sd.BufferDesc.RefreshRate.Denominator = 1;
		sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		sd.OutputWindow = g_hWnd;
		sd.SampleDesc.Count = 1;
		sd.SampleDesc.Quality = 0;
		sd.Windowed = TRUE;

		hr = dxgiFactory->CreateSwapChain( g_pd3dDevice, &sd, &g_pSwapChain );
	}

	// Note this tutorial doesn't handle full-screen swapchains so we block the ALT+ENTER shortcut
	dxgiFactory->MakeWindowAssociation( g_hWnd, DXGI_MWA_NO_ALT_ENTER );

	dxgiFactory->Release();

	if (FAILED(hr))
		return hr;

	// 3.Create a render target view
	ID3D11Texture2D* pBackBuffer = nullptr;
	hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast<void**>( &pBackBuffer ) );
	if( FAILED( hr ) )
		return hr;

	hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, nullptr, &g_pRenderTargetView );
	pBackBuffer->Release();
	if( FAILED( hr ) )
		return hr;

	// 4.Create depth stencil texture
	D3D11_TEXTURE2D_DESC descDepth;
	ZeroMemory( &descDepth, sizeof(descDepth) );
	descDepth.Width = width;
	descDepth.Height = height;
	descDepth.MipLevels = 1;
	descDepth.ArraySize = 1;
	descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	descDepth.SampleDesc.Count = 1;
	descDepth.SampleDesc.Quality = 0;
	descDepth.Usage = D3D11_USAGE_DEFAULT;
	descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	descDepth.CPUAccessFlags = 0;
	descDepth.MiscFlags = 0;
	hr = g_pd3dDevice->CreateTexture2D( &descDepth, nullptr, &g_pDepthStencil );
	if( FAILED( hr ) )
		return hr;

	// 5.Create the depth stencil view
	D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
	ZeroMemory( &descDSV, sizeof(descDSV) );
	descDSV.Format = descDepth.Format;
	descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
	descDSV.Texture2D.MipSlice = 0;
	hr = g_pd3dDevice->CreateDepthStencilView( g_pDepthStencil, &descDSV, &g_pDepthStencilView );
	if( FAILED( hr ) )
		return hr;

	g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, g_pDepthStencilView );

	// 6.Setup the viewport
	D3D11_VIEWPORT vp;
	vp.Width = (FLOAT)width;
	vp.Height = (FLOAT)height;
	vp.MinDepth = 0.0f;
	vp.MaxDepth = 1.0f;
	vp.TopLeftX = 0;
	vp.TopLeftY = 0;
	g_pImmediateContext->RSSetViewports( 1, &vp );

	// 7.Compile and create the vertex shader. Define, create and set the input layout at the same time.
	// 7.1.Compile the vertex shader
	ID3DBlob* pVSBlob = nullptr;
	hr = CompileShaderFromFile( L"lighting.fx", "VS", "vs_5_0", &pVSBlob );
	if( FAILED( hr ) )
	{
		MessageBox( nullptr,
			L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
		return hr;
	}

	// 7.2.Create the vertex shader
	hr = g_pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), nullptr, &g_pVertexShader );
	if( FAILED( hr ) )
	{	
		pVSBlob->Release();
		return hr;
	}

	// 7.3.Define the input layout
	D3D11_INPUT_ELEMENT_DESC layout[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },// 12是对齐字节位移,前一个元素是XMFLOAT3,大小3 * sizeof(XMFLOAT3) = 12,为了方便可用D3D11_APPEND_ALIGNED_ELEMENT可以代替12
	};
	UINT numElements = ARRAYSIZE( layout );

	// 7.4.Create the input layout
	hr = g_pd3dDevice->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
		pVSBlob->GetBufferSize(), &g_pVertexLayout );
	pVSBlob->Release();
	if( FAILED( hr ) )
		return hr;

	// 7.5.Set the input layout
	g_pImmediateContext->IASetInputLayout( g_pVertexLayout );

	// 8.Compile and create the pixel shader
	// 8.1.Compile the pixel shader
	ID3DBlob* pPSBlob = nullptr;
	hr = CompileShaderFromFile( L"lighting.fx", "PS", "ps_5_0", &pPSBlob );
	if( FAILED( hr ) )
	{
		MessageBox( nullptr,
			L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
		return hr;
	}

	// 8.2.Create the pixel shader
	hr = g_pd3dDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), nullptr, &g_pPixelShader );
	pPSBlob->Release();
	if( FAILED( hr ) )
		return hr;

	// 9.Create  and set vertex buffer
	// 9.1.Create vertex buffer
	VertexNormal source[12] = 
	{
		{XMFLOAT3(1, 0, 0), XMFLOAT3()},
		{XMFLOAT3(0, 0, 1), XMFLOAT3()},
		{XMFLOAT3(-1, -1, 0), XMFLOAT3()},

		{XMFLOAT3(-1, 1, 0), XMFLOAT3()},
		{XMFLOAT3(0, 0, 1), XMFLOAT3()},
		{XMFLOAT3(1, 0, 0), XMFLOAT3()},

		{XMFLOAT3(-1, -1, 0), XMFLOAT3()},
		{XMFLOAT3(0, 0, 1), XMFLOAT3()},
		{XMFLOAT3(-1, 1, 0), XMFLOAT3()},

		{XMFLOAT3(-1, -1, 0), XMFLOAT3()},
		{XMFLOAT3(-1, 1, 0), XMFLOAT3()},
		{XMFLOAT3(1, 0, 0), XMFLOAT3()},
	};

	// 赋予各个面单位化外法向量
	for (int i = 0; i < 4; i++)
	{
		XMVECTOR v01 = XMLoadFloat3(&source[3 * i + 1].Pos) - XMLoadFloat3(&source[3 * i].Pos);
		XMVECTOR v02 = XMLoadFloat3(&source[3 * i + 2].Pos) - XMLoadFloat3(&source[3 * i].Pos);
		XMVECTOR normal = XMVector3Normalize(XMVector3Cross(v01, v02));
		for (int j = 0; j < 3; j++)
		{
			XMStoreFloat3(&source[3 * i + j].Normal, normal);
		}
	}

	D3D11_BUFFER_DESC bd;
	ZeroMemory( &bd, sizeof(bd) );
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( VertexNormal ) * 12;// 顶点数
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	D3D11_SUBRESOURCE_DATA InitData;
	ZeroMemory( &InitData, sizeof(InitData) );
	InitData.pSysMem = source;
	hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
	//delete pVertices;
	if( FAILED( hr ) )
		return hr;

	// 9.2.Set vertex buffer
	UINT stride = sizeof( VertexNormal );
	UINT offset = 0;
	g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );

	// 10.Create and set index buffer 
	// We don't need this step in this example, because the vertices are sorted to be clockwise already.
	// 10.1.Create index buffer

	// 10.2.Set index buffer

	// 11.Set primitive topology
	g_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

	// 12.Create the constant buffer
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(CBChangesEveryFrame);
	bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bd.CPUAccessFlags = 0;
	hr = g_pd3dDevice->CreateBuffer( &bd, nullptr, &g_pCBChangesEveryFrame );
	if( FAILED( hr ) )
		return hr;

	bd.ByteWidth = sizeof(CBChangesWhenMoving);
	hr = g_pd3dDevice->CreateBuffer(&bd, nullptr, &g_pCBChangesWhenMoving);
	if (FAILED(hr))
		return hr;

	bd.ByteWidth = sizeof(CBNeverChanges);
	hr = g_pd3dDevice->CreateBuffer(&bd, nullptr, &g_pCBNeverChange);
	if (FAILED(hr))
		return hr;
	

	// 13.Initialize the world matrix, view matrix, projection matrix
	CBChangesEveryFrame cb_changes_every_frame = {};
	cb_changes_every_frame.mWorld = XMMatrixTranspose(XMMatrixIdentity());
	g_pImmediateContext->UpdateSubresource(g_pCBChangesEveryFrame, 0, nullptr, &cb_changes_every_frame, 0, 0);

	g_Camera = Camera(XMVectorSet(1.0f, 0.0f, 0.0f, 1.0f), XMVectorSet(0.0f, 1.0f, 0.0f, 1.0f), XMVectorSet(0.0f, 0.0f, 1.0f, 1.0f), XMVectorSet(-5.0f, 0.0f, 1.0f, 1.0f));
	XMMATRIX view = XMMatrixLookAtLH(g_Camera.vEye(), g_Camera.vFocus(), g_Camera.vUp());
	CBChangesWhenMoving cb_changes_when_moving = {};
	cb_changes_when_moving.mView = XMMatrixTranspose(view);
	g_pImmediateContext->UpdateSubresource(g_pCBChangesWhenMoving, 0, nullptr, &cb_changes_when_moving, 0, 0);

	CBNeverChanges cb_never_changes = {};
	float nearZ = 0.01f;
	float farZ = 500.0f;
	XMMATRIX projection = XMMatrixPerspectiveFovLH( XM_PIDIV4, width / (FLOAT)height, nearZ, farZ );
	cb_never_changes.mProjection = XMMatrixTranspose(projection);
	cb_never_changes.vLightDir[0] = XMFLOAT4(0.0f, 1.0f, -0.5f, 1.0f);
	cb_never_changes.vLightDir[1] = XMFLOAT4(0.0f, -1.0f, -0.5f, 1.0f);
	g_pImmediateContext->UpdateSubresource(g_pCBNeverChange, 0, nullptr, &cb_never_changes, 0, 0);

	return S_OK;
}

void Render()
{
	static DWORD t0 = GetTickCount();
	DWORD t1 = GetTickCount();
	float t = (t1 - t0) / 1000.0f;

	CBChangesEveryFrame cb = {};
	cb.mWorld = XMMatrixTranspose(XMMatrixIdentity() * XMMatrixRotationZ(2.0f * XM_PI / 3.0f * t));// 周期3s

	g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, Colors::Black);// 清屏
	g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);// 清depth stencil view

	g_pImmediateContext->VSSetShader(g_pVertexShader, nullptr, 0);
	g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pCBChangesEveryFrame);// ID3D11DeviceContext::VSSetConstantBuffers()方法: Sets the constant buffers used by the vertex shader pipeline stage. 设置顶点着色管线阶段所使用的常量缓存
	g_pImmediateContext->VSSetConstantBuffers(1, 1, &g_pCBChangesWhenMoving);// 如本例中,fx文件中的CBChangesWhenMoving常量缓存定义是register(b1),那么ID3D11DeviceContext::VSSetConstantBuffers()第一个参数就是1
	g_pImmediateContext->VSSetConstantBuffers(2, 1, &g_pCBNeverChange);

	g_pImmediateContext->PSSetShader(g_pPixelShader, nullptr, 0);
	g_pImmediateContext->PSSetConstantBuffers(0, 1, &g_pCBChangesEveryFrame);// ID3D11DeviceContext::PSSetConstantBuffers()方法: Sets the constant buffers used by the pixel shader pipeline stage.
	g_pImmediateContext->PSSetConstantBuffers(1, 1, &g_pCBChangesWhenMoving);
	g_pImmediateContext->PSSetConstantBuffers(2, 1, &g_pCBNeverChange);

	g_pImmediateContext->UpdateSubresource(g_pCBChangesEveryFrame, 0, nullptr, &cb, 0, 0);// ID3DBuffer继承于ID3DResource,一个更新一个draw
	g_pImmediateContext->Draw(12, 0);// 如果用了索引缓存,用DrawIndexed()

	g_pSwapChain->Present(1, 0);// 第一个参数调节刷新率
}

// 键盘按键按下事件
void KeyDownEvent(WPARAM wParam)
{
	static float step = 1.0f;
	switch (wParam)
	{
	case 'W':// 前进
		{
			g_Camera.XMove(step);
		}
		break;
	case 'S':// 后退
		{
			g_Camera.XMove(-step);
		}
		break;
	case 'A':// 左平移
		{
			g_Camera.YMove(-step);
		}
		break;
	case 'D':// 右平移
		{
			g_Camera.YMove(step);
		}
		break;
	case 'Q':// 上升
		{
			g_Camera.ZMove(step);
		}
		break;
	case 'Z':// 下降
		{
			g_Camera.ZMove(-step);
		}
		break;
	case VK_RIGHT:// 右转
		{
			g_Camera.ZSpin(5.0f / 180.0f * XM_PI);
		}
		break;
	case VK_LEFT:// 左转
		{
			g_Camera.ZSpin(-5.0f / 180.0f * XM_PI);
		}
		break;
	case VK_UP:// 仰
		{
			g_Camera.YSpin(-5.0f / 180.0f * XM_PI);
		}
		break;
	case VK_DOWN:// 俯
		{
			g_Camera.YSpin(5.0f / 180.0f * XM_PI);
		}
		break;
	default:
		break;
	}
}

// 鼠标事件
void MouseEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static bool s_bRBtnDown = false;
	static POINT s_Pos0;
	switch (uMsg)
	{
	case WM_MOUSEWHEEL:
		{
			static float distance = 1.0f;
			if ((INT)wParam > 0)// 前滚
			{
				g_Camera.ZoomIn(distance);
			}
			else// 后滚
			{
				g_Camera.ZoomIn(-distance);
			}
		}
		break;
	case WM_RBUTTONDOWN:
		{
			s_bRBtnDown = true;
			GetCursorPos(&s_Pos0);
		}
		break;
	case WM_RBUTTONUP:
		{
			s_bRBtnDown = false;
		}
		break;
	case WM_MOUSEMOVE:
		{
			if (s_bRBtnDown)
			{			
				POINT Pos1;
				GetCursorPos(&Pos1);
				int dx = Pos1.x - s_Pos0.x;
				int dy = Pos1.y - s_Pos0.y;
				float degree = 1.0f;
				if (dx > 0)
				{
					g_Camera.ZSpin(degree / 180.0f * XM_PI);
				}
				else if (dx < 0)
				{
					g_Camera.ZSpin(-degree / 180.0f * XM_PI);
				}

				if (dy < 0)
				{
					g_Camera.YSpin(-degree / 180.0f * XM_PI);
				}
				else if (dy > 0)
				{
					g_Camera.YSpin(degree / 180.0f * XM_PI);
				}
				s_Pos0 = Pos1;
			}
		}
		break;
	default:
		break;
	}
}

void CameraOperator(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	MouseEvent(hWnd, uMsg, wParam, lParam);
	KeyDownEvent(wParam);
	CBChangesWhenMoving cb_changes_when_moving = {};
	XMMATRIX view = XMMatrixLookAtLH(g_Camera.vEye(), g_Camera.vFocus(), g_Camera.vUp());
	cb_changes_when_moving.mView = XMMatrixTranspose(view);
	g_pImmediateContext->UpdateSubresource(g_pCBChangesWhenMoving, 0, nullptr, &cb_changes_when_moving, 0, 0);
}

// 初始化窗口
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow )
{
	// Register class
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof( WNDCLASSEX );
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_APPLICATION );
	wcex.hCursor = LoadCursor( nullptr, IDC_ARROW );
	wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
	wcex.lpszMenuName = nullptr;
	wcex.lpszClassName = L"class1";
	wcex.hIconSm = LoadIcon( wcex.hInstance, ( LPCTSTR )IDI_APPLICATION );
	if( !RegisterClassEx( &wcex ) )
		return E_FAIL;

	// Create window
	g_hInst = hInstance;
	RECT rc = { 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) };
	AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
	g_hWnd = CreateWindow( L"class1", L"简单四面体方向光渲染",
		WS_POPUP,
		CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, nullptr, nullptr, hInstance,
		nullptr );
	if( !g_hWnd )
		return E_FAIL;

	ShowWindow( g_hWnd, nCmdShow );

	return S_OK;
}

void CleanupDevice()
{
	if (g_pImmediateContext) g_pImmediateContext->ClearState();

	if (g_pCBChangesEveryFrame) g_pCBChangesEveryFrame->Release();
	if (g_pCBChangesWhenMoving) g_pCBChangesWhenMoving->Release();
	if (g_pCBNeverChange) g_pCBNeverChange->Release();
	if (g_pVertexBuffer) g_pVertexBuffer->Release();
	if (g_pVertexLayout) g_pVertexLayout->Release();
	if (g_pVertexShader) g_pVertexShader->Release();
	if (g_pPixelShader) g_pPixelShader->Release();
	if (g_pDepthStencil) g_pDepthStencil->Release();
	if (g_pDepthStencilView) g_pDepthStencilView->Release();
	if (g_pRenderTargetView) g_pRenderTargetView->Release();
	if (g_pSwapChain1) g_pSwapChain1->Release();
	if (g_pSwapChain) g_pSwapChain->Release();
	if (g_pImmediateContext1) g_pImmediateContext1->Release();
	if (g_pImmediateContext) g_pImmediateContext->Release();
	if (g_pd3dDevice1) g_pd3dDevice1->Release();
	if (g_pd3dDevice) g_pd3dDevice->Release();
}

// 回调函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DESTROY:
		{
			PostQuitMessage(0);
		}
		break;
	case WM_KEYDOWN:
		{
			if (wParam == VK_ESCAPE)
			{
				if (MessageBox(g_hWnd, L"确认退出?", L"提醒", MB_OKCANCEL) == IDOK)
				{
					SendMessage(g_hWnd, WM_DESTROY, 0, 0);
				}
			}
			CameraOperator(hWnd, uMsg, wParam, lParam);
		}						
		break;
	case WM_MOUSEMOVE:
		{
			CameraOperator(hWnd, uMsg, wParam, lParam);
		}
		break;
	case WM_RBUTTONDOWN:
		{
			CameraOperator(hWnd, uMsg, wParam, lParam);
		}
		break;
	case WM_RBUTTONUP:
		{
			CameraOperator(hWnd, uMsg, wParam, lParam);
		}
		break;
	case WM_MOUSEWHEEL:
		{
			CameraOperator(hWnd, uMsg, wParam, lParam);
		}
		break;
	default:
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
	}
	return 0;
}

// 从文件编译着色器,由微软官网例子提供
HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut )
{
	HRESULT hr = S_OK;

	DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#ifdef _DEBUG
	// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
	// Setting this flag improves the shader debugging experience, but still allows 
	// the shaders to be optimized and to run exactly the way they will run in 
	// the release configuration of this program.
	dwShaderFlags |= D3DCOMPILE_DEBUG;

	// Disable optimizations to further improve shader debugging
	dwShaderFlags |= D3DCOMPILE_SKIP_OPTIMIZATION;
#endif

	ID3DBlob* pErrorBlob = nullptr;
	hr = D3DCompileFromFile( szFileName, nullptr, nullptr, szEntryPoint, szShaderModel, 
		dwShaderFlags, 0, ppBlobOut, &pErrorBlob );
	if( FAILED(hr) )
	{
		if( pErrorBlob )
		{
			OutputDebugStringA( reinterpret_cast<const char*>( pErrorBlob->GetBufferPointer() ) );
			pErrorBlob->Release();
		}
		return hr;
	}
	if( pErrorBlob ) pErrorBlob->Release();

	return S_OK;
}
           

3. 效果图:

四面体简单光照渲染+漫游(使用多个ConstantBuffer减小带宽)
四面体简单光照渲染+漫游(使用多个ConstantBuffer减小带宽)

继续阅读