DirectX 10 教程22:绘制到纹理
原文地址:Tutorial 22: Render to Texture(http://www.rastertek.com/dx10tut22.html)。
源代码下载:dx10tut22.zip。
本教程介绍如何实现绘制到纹理,代码基于教程7绘制3D模型和教程11绘制2D图像。
绘制到纹理可以将场景绘制到纹理中而不是通常的后备缓存中,然后你就可以使用这张纹理实现许多效果。例如,你可以从相机的不同角度绘制场景,然后将绘制的纹理作为一个镜像或小屏幕。你也可以对这张纹理进行后期处理或使用shader进行绘制获取独特的效果。利用绘制到纹理所能达到的效果几乎是无限的,因此它也几乎是DirectX 10中威力最大的工具。
但是,因为你将场景绘制了多遍,所以绘制到纹理开销也是巨大的。3D引擎往往在这个阶段开始速度降低,但是相比于它能达到的效果还是物有所值的。
本教程中我们首先将一个旋转的立方体绘制到纹理中,然后将这张纹理绘制到屏幕左上角。立方体也会绘制到屏幕上。纹理的背景设为蓝色。首先看一下更新过的框架。
框架
框架中新添了RenderTextureClass和DebugWindowClass。RenderTextureClass封装了DirectX 10中绘制到纹理的功能。DebugWindowClass只是前面教程中BitmapClass类修改个名称而已,但是没有包含纹理,因为我们需要将绘制的纹理作为参数传递到这个类中。我将它命名为DebugWindowClass的原因是我经常使用这个类帮助我调试shader的效果,它可以帮助我看到shader每个阶段的效果。
Rendertextureclass.h
RenderTextureClass将渲染目标设置到纹理而不是常规的后备缓存,还可以从这个类获取以ID3D10ShaderResourceView形式.得到的纹理数据。
//////////////////////////////////////////////////////////////////////////////// // Filename: rendertextureclass.h //////////////////////////////////////////////////////////////////////////////// #ifndef _RENDERTEXTURECLASS_H_ #define _RENDERTEXTURECLASS_H_ ////////////// // INCLUDES // ////////////// #include <d3d10.h> //////////////////////////////////////////////////////////////////////////////// // Class name: RenderTextureClass //////////////////////////////////////////////////////////////////////////////// class RenderTextureClass { public: RenderTextureClass(); RenderTextureClass(const RenderTextureClass&); ~RenderTextureClass(); bool Initialize(ID3D10Device*, int, int); void Shutdown(); void SetRenderTarget(ID3D10Device*, ID3D10DepthStencilView*); void ClearRenderTarget(ID3D10Device*, ID3D10DepthStencilView*, float, float, float, float); ID3D10ShaderResourceView* GetShaderResourceView(); private: ID3D10Texture2D* m_renderTargetTexture; ID3D10RenderTargetView* m_renderTargetView; ID3D10ShaderResourceView* m_shaderResourceView; }; #endif
Rendertextureclass.cpp
//////////////////////////////////////////////////////////////////////////////// // Filename: rendertextureclass.cpp //////////////////////////////////////////////////////////////////////////////// #include "rendertextureclass.h"
构造函数中将私有指针初始化为null。
RenderTextureClass::RenderTextureClass() { m_renderTargetTexture = 0; m_renderTargetView = 0; m_shaderResourceView = 0; } RenderTextureClass::RenderTextureClass(const RenderTextureClass& other) { } RenderTextureClass::~RenderTextureClass() { }
Initialize方法的参数width和height表示要绘制的纹理的大小。注意:如果绘制的是整个屏幕,必须将渲染目标的长宽比设置得和屏幕一样,否则图像会变形。
首先设置纹理描述创建一个渲染目标纹理,然后使用这张纹理创建一个渲染目标视图,这样这张纹理就会以渲染目标的形式进行绘制。最后创建纹理的shader资源视图,这样调用对象就可以访问到这个数据了。
bool RenderTextureClass::Initialize(ID3D10Device* device, int textureWidth, int textureHeight) { D3D10_TEXTURE2D_DESC textureDesc; HRESULT result; D3D10_RENDER_TARGET_VIEW_DESC renderTargetViewDesc; D3D10_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc; // Initialize the render target texture description. ZeroMemory(&textureDesc, sizeof(textureDesc)); // Setup the render target texture description. textureDesc.Width = textureWidth; textureDesc.Height = textureHeight; textureDesc.MipLevels = 1; textureDesc.ArraySize = 1; textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; textureDesc.SampleDesc.Count = 1; textureDesc.Usage = D3D10_USAGE_DEFAULT; textureDesc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; textureDesc.CPUAccessFlags = 0; textureDesc.MiscFlags = 0; // Create the render target texture. result = device->CreateTexture2D(&textureDesc, NULL, &m_renderTargetTexture); if(FAILED(result)) { return false; } // Setup the description of the render target view. renderTargetViewDesc.Format = textureDesc.Format; renderTargetViewDesc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2D; renderTargetViewDesc.Texture2D.MipSlice = 0; // Create the render target view. result = device->CreateRenderTargetView(m_renderTargetTexture, &renderTargetViewDesc, &m_renderTargetView); if(FAILED(result)) { return false; } // Setup the description of the shader resource view. shaderResourceViewDesc.Format = textureDesc.Format; shaderResourceViewDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D; shaderResourceViewDesc.Texture2D.MostDetailedMip = 0; shaderResourceViewDesc.Texture2D.MipLevels = 1; // Create the shader resource view. result = device->CreateShaderResourceView(m_renderTargetTexture, &shaderResourceViewDesc, &m_shaderResourceView); if(FAILED(result)) { return false; } return true; }
Shutdown释放创建的三个接口。
void RenderTextureClass::Shutdown() { if(m_shaderResourceView) { m_shaderResourceView->Release(); m_shaderResourceView = 0; } if(m_renderTargetView) { m_renderTargetView->Release(); m_renderTargetView = 0; } if(m_renderTargetTexture) { m_renderTargetTexture->Release(); m_renderTargetTexture = 0; } return; }
SetRenderTarget方法将这个类中的渲染目标视图作为当前所有图形绘制的目标。
void RenderTextureClass::SetRenderTarget(ID3D10Device* device, ID3D10DepthStencilView* depthStencilView) { // Bind the render target view and depth stencil buffer to the output render pipeline. device->OMSetRenderTargets(1, &m_renderTargetView, depthStencilView); return; }
ClearRenderTarget类似于D3DClass::BeginScene方法,只不过它操作的对象是这个类中的渲染目标视图,这个方法每帧都需要在绘制到渲染目标前进行调用。
void RenderTextureClass::ClearRenderTarget(ID3D10Device* device, ID3D10DepthStencilView* depthStencilView, float red, float green, float blue, float alpha) { float color[4]; // Setup the color to clear the buffer to. color[0] = red; color[1] = green; color[2] = blue; color[3] = alpha; // Clear the back buffer. device->ClearRenderTargetView(m_renderTargetView, color); // Clear the depth buffer. device->ClearDepthStencilView(depthStencilView, D3D10_CLEAR_DEPTH, 1.0f, 0); return; }
GetShaderResourceView方法以shader资源视图的方式返回绘制到纹理的数据,这样绘制到渲染目标视图的数据就可以作为一张纹理被其他shader使用。你通常会直接将一张纹理传递到shader中,但现在可以调用这个方法达到同样的效果。
ID3D10ShaderResourceView* RenderTextureClass::GetShaderResourceView() { return m_shaderResourceView; }
Debugwindowclass.h
DebugWindowClass几乎就是BitmapClass,但没有了TextureClass类。代码和前面教程中的BitmapClass几乎一样,所以这个类的详细解释可参见前面的教程。
//////////////////////////////////////////////////////////////////////////////// // Filename: debugwindowclass.h //////////////////////////////////////////////////////////////////////////////// #ifndef _DEBUGWINDOWCLASS_H_ #define _DEBUGWINDOWCLASS_H_ ////////////// // INCLUDES // ////////////// #include <d3d10.h> #include <d3dx10.h> //////////////////////////////////////////////////////////////////////////////// // Class name: DebugWindowClass //////////////////////////////////////////////////////////////////////////////// class DebugWindowClass { private: struct VertexType { D3DXVECTOR3 position; D3DXVECTOR2 texture; }; public: DebugWindowClass(); DebugWindowClass(const DebugWindowClass&); ~DebugWindowClass(); bool Initialize(ID3D10Device*, int, int, int, int); void Shutdown(); bool Render(ID3D10Device*, int, int); int GetIndexCount(); private: bool InitializeBuffers(ID3D10Device*); void ShutdownBuffers(); bool UpdateBuffers(int, int); void RenderBuffers(ID3D10Device*); private: ID3D10Buffer *m_vertexBuffer, *m_indexBuffer; int m_vertexCount, m_indexCount; int m_screenWidth, m_screenHeight; int m_bitmapWidth, m_bitmapHeight; int m_previousPosX, m_previousPosY; }; #endif
Debugwindowclass.cpp
//////////////////////////////////////////////////////////////////////////////// // Filename: debugwindowclass.cpp //////////////////////////////////////////////////////////////////////////////// #include "debugwindowclass.h" DebugWindowClass::DebugWindowClass() { m_vertexBuffer = 0; m_indexBuffer = 0; } DebugWindowClass::DebugWindowClass(const DebugWindowClass& other) { } DebugWindowClass::~DebugWindowClass() { } bool DebugWindowClass::Initialize(ID3D10Device* device, int screenWidth, int screenHeight, int bitmapWidth, int bitmapHeight) { bool result; // Store the screen size. m_screenWidth = screenWidth; m_screenHeight = screenHeight; // Store the size in pixels that this bitmap should be rendered at. m_bitmapWidth = bitmapWidth; m_bitmapHeight = bitmapHeight; // Initialize the previous rendering position to zero. m_previousPosX = 0; m_previousPosY = 0; // Initialize the vertex and index buffer that hold the geometry for the triangle. result = InitializeBuffers(device); if(!result) { return false; } return true; } void DebugWindowClass::Shutdown() { // Release the vertex and index buffers. ShutdownBuffers(); return; } bool DebugWindowClass::Render(ID3D10Device* device, int positionX, int positionY) { bool result; // Re-build the dynamic vertex buffer for rendering to possibly a different location on the screen. result = UpdateBuffers(positionX, positionY); if(!result) { return false; } // Put the vertex and index buffers on the graphics pipeline to prepare them for drawing. RenderBuffers(device); return true; } int DebugWindowClass::GetIndexCount() { return m_indexCount; } bool DebugWindowClass::InitializeBuffers(ID3D10Device* device) { VertexType* vertices; unsigned long* indices; D3D10_BUFFER_DESC vertexBufferDesc, indexBufferDesc; D3D10_SUBRESOURCE_DATA vertexData, indexData; HRESULT result; int i; // Set the number of vertices in the vertex array. m_vertexCount = 6; // Set the number of indices in the index array. m_indexCount = m_vertexCount; // Create the vertex array. vertices = new VertexType[m_vertexCount]; if(!vertices) { return false; } // Create the index array. indices = new unsigned long[m_indexCount]; if(!indices) { return false; } // Initialize vertex array to zeros at first. memset(vertices, 0, (sizeof(VertexType) * m_vertexCount)); // Load the index array with data. for(i=0; i<m_indexCount; i++) { indices[i] = i; } // Set up the description of the dynamic vertex buffer. vertexBufferDesc.Usage = D3D10_USAGE_DYNAMIC; vertexBufferDesc.ByteWidth = sizeof(VertexType) * m_vertexCount; vertexBufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; vertexBufferDesc.MiscFlags = 0; // Give the subresource structure a pointer to the vertex data. vertexData.pSysMem = vertices; // Now finally create the vertex buffer. result = device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_vertexBuffer); if(FAILED(result)) { return false; } // Set up the description of the index buffer. indexBufferDesc.Usage = D3D10_USAGE_DEFAULT; indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexCount; indexBufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags = 0; indexBufferDesc.MiscFlags = 0; // Give the subresource structure a pointer to the index data. indexData.pSysMem = indices; // Create the index buffer. result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer); if(FAILED(result)) { return false; } // Release the arrays now that the vertex and index buffers have been created and loaded. delete [] vertices; vertices = 0; delete [] indices; indices = 0; return true; } void DebugWindowClass::ShutdownBuffers() { // Release the index buffer. if(m_indexBuffer) { m_indexBuffer->Release(); m_indexBuffer = 0; } // Release the vertex buffer. if(m_vertexBuffer) { m_vertexBuffer->Release(); m_vertexBuffer = 0; } return; } bool DebugWindowClass::UpdateBuffers(int positionX, int positionY) { float left, right, top, bottom; VertexType* vertices; void* verticesPtr; HRESULT result; // If the position we are rendering this bitmap to has not changed then don't update the vertex buffer since it // currently has the correct parameters. if((positionX == m_previousPosX) && (positionY == m_previousPosY)) { return true; } // If it has changed then update the position it is being rendered to. m_previousPosX = positionX; m_previousPosY = positionY; // Calculate the screen coordinates of the left side of the bitmap. left = (float)((m_screenWidth / 2) * -1) + (float)positionX; // Calculate the screen coordinates of the right side of the bitmap. right = left + (float)m_bitmapWidth; // Calculate the screen coordinates of the top of the bitmap. top = (float)(m_screenHeight / 2) - (float)positionY; // Calculate the screen coordinates of the bottom of the bitmap. bottom = top - (float)m_bitmapHeight; // Create the vertex array. vertices = new VertexType[m_vertexCount]; if(!vertices) { return false; } // Load the vertex array with data. // First triangle. vertices[0].position = D3DXVECTOR3(left, top, 0.0f); // Top left. vertices[0].texture = D3DXVECTOR2(0.0f, 0.0f); vertices[1].position = D3DXVECTOR3(right, bottom, 0.0f); // Bottom right. vertices[1].texture = D3DXVECTOR2(1.0f, 1.0f); vertices[2].position = D3DXVECTOR3(left, bottom, 0.0f); // Bottom left. vertices[2].texture = D3DXVECTOR2(0.0f, 1.0f); // Second triangle. vertices[3].position = D3DXVECTOR3(left, top, 0.0f); // Top left. vertices[3].texture = D3DXVECTOR2(0.0f, 0.0f); vertices[4].position = D3DXVECTOR3(right, top, 0.0f); // Top right. vertices[4].texture = D3DXVECTOR2(1.0f, 0.0f); vertices[5].position = D3DXVECTOR3(right, bottom, 0.0f); // Bottom right. vertices[5].texture = D3DXVECTOR2(1.0f, 1.0f); // Initialize the vertex buffer pointer to null first. verticesPtr = 0; // Lock the vertex buffer. result = m_vertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&verticesPtr); if(FAILED(result)) { return false; } // Copy the data into the vertex buffer. memcpy(verticesPtr, (void*)vertices, (sizeof(VertexType) * m_vertexCount)); // Unlock the vertex buffer. m_vertexBuffer->Unmap(); // Release the vertex array as it is no longer needed. delete [] vertices; vertices = 0; return true; } void DebugWindowClass::RenderBuffers(ID3D10Device* device) { unsigned int stride; unsigned int offset; // Set vertex buffer stride and offset. stride = sizeof(VertexType); offset = 0; // Set the vertex buffer to active in the input assembler so it can be rendered. device->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset); // Set the index buffer to active in the input assembler so it can be rendered. device->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0); // Set the type of primitive that should be rendered from this vertex buffer, in this case triangles. device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); return; }
D3dclass.h
D3Dclass的变化很小。
//////////////////////////////////////////////////////////////////////////////// // Filename: d3dclass.h //////////////////////////////////////////////////////////////////////////////// #ifndef _D3DCLASS_H_ #define _D3DCLASS_H_ ///////////// // LINKING // ///////////// #pragma comment(lib, "d3d10.lib") #pragma comment(lib, "d3dx10.lib") #pragma comment(lib, "dxgi.lib") ////////////// // INCLUDES // ////////////// #include#include //////////////////////////////////////////////////////////////////////////////// // Class name: D3DClass //////////////////////////////////////////////////////////////////////////////// class D3DClass { public: D3DClass(); D3DClass(const D3DClass&); ~D3DClass(); bool Initialize(int, int, bool, HWND, bool, float, float); void Shutdown(); void BeginScene(float, float, float, float); void EndScene(); ID3D10Device* GetDevice();
添加一个新方法用于访问深度模板视图。
ID3D10DepthStencilView* GetDepthStencilView(); void GetProjectionMatrix(D3DXMATRIX&); void GetWorldMatrix(D3DXMATRIX&); void GetOrthoMatrix(D3DXMATRIX&); void TurnZBufferOn(); void TurnZBufferOff();
新添了一个方法用于设置渲染目标。
void SetBackBufferRenderTarget(); private: bool m_vsync_enabled; ID3D10Device* m_device; IDXGISwapChain* m_swapChain; ID3D10RenderTargetView* m_renderTargetView; ID3D10Texture2D* m_depthStencilBuffer; ID3D10DepthStencilState* m_depthStencilState; ID3D10DepthStencilView* m_depthStencilView; ID3D10RasterizerState* m_rasterState; D3DXMATRIX m_projectionMatrix; D3DXMATRIX m_worldMatrix; D3DXMATRIX m_orthoMatrix; ID3D10DepthStencilState* m_depthDisabledStencilState; }; #endif
D3dclass.cpp
下面的代码只包含与上一个教程不同的部分。
//////////////////////////////////////////////////////////////////////////////// // Filename: d3dclass.cpp //////////////////////////////////////////////////////////////////////////////// #include "d3dclass.h"
GetDepthStencilView让调用对象可以访问深度模板视图。
ID3D10DepthStencilView* D3DClass::GetDepthStencilView() { return m_depthStencilView; }
SetBackBufferRenderTarget方法会将这个类中的后备缓存作为当前的渲染目标,这个方法通常在绘制到纹理完成后进行,此时我们需要重新将场景绘制到后备缓存中。
void D3DClass::SetBackBufferRenderTarget() { // Bind the render target view and depth stencil buffer to the output render pipeline. m_device->OMSetRenderTargets(1, &m_renderTargetView, m_depthStencilView); return; }
Graphicsclass.h
//////////////////////////////////////////////////////////////////////////////// // Filename: graphicsclass.h //////////////////////////////////////////////////////////////////////////////// #ifndef _GRAPHICSCLASS_H_ #define _GRAPHICSCLASS_H_ ///////////// // GLOBALS // ///////////// const bool FULL_SCREEN = true; const bool VSYNC_ENABLED = true; const float SCREEN_DEPTH = 1000.0f; const float SCREEN_NEAR = 0.1f; /////////////////////// // MY CLASS INCLUDES // /////////////////////// #include "d3dclass.h" #include "cameraclass.h" #include "modelclass.h" #include "lightshaderclass.h" #include "lightclass.h" #include "rendertextureclass.h" #include "debugwindowclass.h" #include "textureshaderclass.h" //////////////////////////////////////////////////////////////////////////////// // Class name: GraphicsClass //////////////////////////////////////////////////////////////////////////////// class GraphicsClass { public: GraphicsClass(); GraphicsClass(const GraphicsClass&); ~GraphicsClass(); bool Initialize(int, int, HWND); void Shutdown(); bool Frame(); bool Render();
新添了两个私有方法,我们需要将绘制分成两个pass(一次绘制到纹理,一次普通绘制)。
private: void RenderToTexture(); void RenderScene(); private: D3DClass* m_D3D; CameraClass* m_Camera; ModelClass* m_Model; LightShaderClass* m_LightShader; LightClass* m_Light; RenderTextureClass* m_RenderTexture; DebugWindowClass* m_DebugWindow; TextureShaderClass* m_TextureShader; }; #endif
Graphicsclass.cpp
下面的代码只包含与上一个教程不同的部分。
//////////////////////////////////////////////////////////////////////////////// // Filename: graphicsclass.cpp //////////////////////////////////////////////////////////////////////////////// #include "graphicsclass.h"
在构造函数中将私有变量初始化为null。
GraphicsClass::GraphicsClass() { m_D3D = 0; m_Camera = 0; m_Model = 0; m_LightShader = 0; m_Light = 0; m_RenderTexture = 0; m_DebugWindow = 0; m_TextureShader = 0; } GraphicsClass::GraphicsClass(const GraphicsClass& other) { } GraphicsClass::~GraphicsClass() { } bool GraphicsClass::Initialize(int screenWidth, int screenHeight, HWND hwnd) { bool result; // Create the Direct3D object. m_D3D = new D3DClass; if(!m_D3D) { return false; } // Initialize the Direct3D object. result = m_D3D->Initialize(screenWidth, screenHeight, VSYNC_ENABLED, hwnd, FULL_SCREEN, SCREEN_DEPTH, SCREEN_NEAR); if(!result) { MessageBox(hwnd, L"Could not initialize Direct3D.", L"Error", MB_OK); return false; } // Create the camera object. m_Camera = new CameraClass; if(!m_Camera) { return false; } // Create the model object. m_Model = new ModelClass; if(!m_Model) { return false; } // Initialize the model object. result = m_Model->Initialize(m_D3D->GetDevice(), L"../Engine/data/seafloor.dds", "../Engine/data/cube.txt"); if(!result) { MessageBox(hwnd, L"Could not initialize the model object.", L"Error", MB_OK); return false; } // Create the light shader object. m_LightShader = new LightShaderClass; if(!m_LightShader) { return false; } // Initialize the light shader object. result = m_LightShader->Initialize(m_D3D->GetDevice(), hwnd); if(!result) { MessageBox(hwnd, L"Could not initialize the light shader object.", L"Error", MB_OK); return false; } // Create the light object. m_Light = new LightClass; if(!m_Light) { return false; } // Initialize the light object. m_Light->SetDiffuseColor(1.0f, 1.0f, 1.0f, 1.0f); m_Light->SetDirection(0.0f, 0.0f, 1.0f);
创建并初始化render to texture对象。初始化的参数中纹理的大小我使用的是屏幕的大小,表示我想将整个屏幕的画面绘制到相同大小的纹理中。
// Create the render to texture object. m_RenderTexture = new RenderTextureClass; if(!m_RenderTexture) { return false; } // Initialize the render to texture object. result = m_RenderTexture->Initialize(m_D3D->GetDevice(), screenWidth, screenHeight); if(!result) { return false; }
创建并初始化debug window对象。注意我将窗口大小设置为100x100,显然这样做会使图像变形,想要不变形,你只需将上述大小的长宽比设置得和屏幕的长宽比一致即可。
// Create the debug window object. m_DebugWindow = new DebugWindowClass; if(!m_DebugWindow) { return false; } // Initialize the debug window object. result = m_DebugWindow->Initialize(m_D3D->GetDevice(), screenWidth, screenHeight, 100, 100); if(!result) { MessageBox(hwnd, L"Could not initialize the debug window object.", L"Error", MB_OK); return false; } // Create the texture shader object. m_TextureShader = new TextureShaderClass; if(!m_TextureShader) { return false; } // Initialize the texture shader object. result = m_TextureShader->Initialize(m_D3D->GetDevice(), hwnd); if(!result) { MessageBox(hwnd, L"Could not initialize the texture shader object.", L"Error", MB_OK); return false; } return true; } void GraphicsClass::Shutdown() { // Release the texture shader object. if(m_TextureShader) { m_TextureShader->Shutdown(); delete m_TextureShader; m_TextureShader = 0; }
在Shutdown方法中释放DebugWindowClass和RenderTextureClass对象。
// Release the debug window object. if(m_DebugWindow) { m_DebugWindow->Shutdown(); delete m_DebugWindow; m_DebugWindow = 0; } // Release the render to texture object. if(m_RenderTexture) { m_RenderTexture->Shutdown(); delete m_RenderTexture; m_RenderTexture = 0; } // Release the light object. if(m_Light) { delete m_Light; m_Light = 0; } // Release the light shader object. if(m_LightShader) { m_LightShader->Shutdown(); delete m_LightShader; m_LightShader = 0; } // Release the model object. if(m_Model) { m_Model->Shutdown(); delete m_Model; m_Model = 0; } // Release the camera object. if(m_Camera) { delete m_Camera; m_Camera = 0; } // Release the Direct3D object. if(m_D3D) { m_D3D->Shutdown(); delete m_D3D; m_D3D = 0; } return; } bool GraphicsClass::Frame() { // Set the position of the camera. m_Camera->SetPosition(0.0f, 0.0f, -5.0f); return true; } bool GraphicsClass::Render() { D3DXMATRIX worldMatrix, viewMatrix, orthoMatrix; bool result;
第一个pass绘制到纹理。
// Render the entire scene to the texture first. RenderToTexture();
第二个pass进行普通的绘制。
// Clear the buffers to begin the scene. m_D3D->BeginScene(0.0f, 0.0f, 0.0f, 1.0f); // Render the scene as normal to the back buffer. RenderScene();
绘制完成后将debug window作为2D图像绘制在屏幕50x50的位置。
// Turn off the Z buffer to begin all 2D rendering. m_D3D->TurnZBufferOff(); // Get the world, view, and ortho matrices from the camera and d3d objects. m_D3D->GetWorldMatrix(worldMatrix); m_Camera->GetViewMatrix(viewMatrix); m_D3D->GetOrthoMatrix(orthoMatrix); // Put the debug window vertex and index buffers on the graphics pipeline to prepare them for drawing. result = m_DebugWindow->Render(m_D3D->GetDevice(), 50, 50); if(!result) { return false; } // Render the debug window using the texture shader. m_TextureShader->Render(m_D3D->GetDevice(), m_DebugWindow->GetIndexCount(), worldMatrix, viewMatrix, orthoMatrix, m_RenderTexture->GetShaderResourceView()); // Turn the Z buffer back on now that all 2D rendering has completed. m_D3D->TurnZBufferOn(); // Present the rendered scene to the screen. m_D3D->EndScene(); return true; }
RenderToTexture方法将渲染目标视图作为当前的渲染目标,绘制完毕后使用D3Dclass对象将渲染目标重新设置为后备缓存。
void GraphicsClass::RenderToTexture() { // Set the render target to be the render to texture. m_RenderTexture->SetRenderTarget(m_D3D->GetDevice(), m_D3D->GetDepthStencilView());
将渲染纹理的背景清除为蓝色,这样我们就可以把它与常规的场景绘制区分开来。
// Clear the render to texture. m_RenderTexture->ClearRenderTarget(m_D3D->GetDevice(), m_D3D->GetDepthStencilView(), 0.0f, 0.0f, 1.0f, 1.0f); // Render the scene now and it will draw to the render to texture instead of the back buffer. RenderScene(); // Reset the render target back to the original back buffer and not the render to texture anymore. m_D3D->SetBackBufferRenderTarget(); return; }
RenderScene方法绘制整个场景。本教程中我们在RenderToTexture中调用它一次,将场景绘制到一张纹理中。然后再Render方法中再调用一次将场景绘制到常规的后备缓存中。
void GraphicsClass::RenderScene() { D3DXMATRIX worldMatrix, viewMatrix, projectionMatrix; static float rotation = 0.0f; // Generate the view matrix based on the camera's position. m_Camera->Render(); // Get the world, view, and projection matrices from the camera and d3d objects. m_D3D->GetWorldMatrix(worldMatrix); m_Camera->GetViewMatrix(viewMatrix); m_D3D->GetProjectionMatrix(projectionMatrix); // Update the rotation variable each frame. rotation += (float)D3DX_PI * 0.005f; if(rotation > 360.0f) { rotation -= 360.0f; } D3DXMatrixRotationY(&worldMatrix, rotation); // Put the model vertex and index buffers on the graphics pipeline to prepare them for drawing. m_Model->Render(m_D3D->GetDevice()); // Render the model using the light shader. m_LightShader->Render(m_D3D->GetDevice(), m_Model->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, m_Model->GetTexture(), m_Light->GetDirection(), m_Light->GetDiffuseColor()); return; }
总结
现在你理解了绘制到纹理的基本方法。
练习
1.编译并运行程序,你会看到一个旋转的立方体,并且在屏幕左上角显示一个蓝色背景的小立方体,这是绘制到纹理的效果。
2.修改debug window,使它的长宽比与屏幕的长宽比相同。
3.修改3D场景,确认也能正确地绘制到纹理。
4.修改相机的观察角度观察效果。
5.使用这个纹理作为你自己的shader的输入并改变输出结果(例如添加噪点、扫描行等效果)。
文件下载(已下载 1155 次)发布时间:2012/8/10 上午12:28:54 阅读次数:9242