请教direct3d9下载中如何将渲染到纹理的纹理与其他纹理混合

游戏中应用的例子:
游戏中打开观察人物的界面,UI上显示的人物就是通过这种方式绘制出来的。
渲染到纹理是D3D中的一项高级技术。一方面,它很简单,另一方面它很强大并能产生很多特殊效果。 比如说发光效果,环境映射,阴影映射,都可以通过它来实现。渲染到纹理只是渲染到表面的一个延伸。我们只需再加些东西就可以了。首先,我们要创造一个纹理,并且做好一些防范措施。第二步我们就可以把适当的场景渲染到我们创建的纹理上了。然后,我们把这个纹理用在最后的渲染上。  ?main.cpp  首先我们得声明所需要的对象。当然我们需要一张用来渲染的纹理。此外,我们还需要两个Surface对象。一个是用来存储后台缓冲区,一个用来当纹理的渲染对象。后面我再详细介绍它们。另外我们还需要两个矩阵,一个是用来当纹理的投影矩阵,另一个是存储原来的矩阵。  LPDIRECT3DTEXTURE9 pRenderTexture = NULL;  LPDIRECT3DSURFACE9 pRenderSurface = NULL,pBackBuffer = NULL;  D3DXMATRIX matProjection,matOldP  现在我们来创建纹理。前两个参数是纹理的宽度和高度,第三个参数是纹理的多级渐进纹理序列参数,在这里是设为1,第四个参数非常重要而且必须设为D3DUSAGE_RENDERTARGET,表明我们所创建的纹理是用来渲染的。剩下的参数就是指纹理格式,顶点缓冲区的内存位置,和一个指向纹理的指针。当纹理是用来当渲染对象时,顶点缓冲区的内存位置必须设为D3D_DEFAILT。  g_App.GetDevice()-&CreateTexture(256,256,1,D3DUSAGE_RENDERTARGET,D3DFMT_R5G6B5,D3DPOOL_DEFAULT,&pRenderTexture,NULL);  为了访问纹理内存对象,我们需要一个Surface对象,因为D3D中的纹理是用这样的一个Surface来存储纹理数据的。为了得到纹理表面的Surface,我们需要调用方法GetSurfaceLevel() 。第一个参数我们设为0,第二个参数为一个指向surface对象的指针。  pRenderTexture-&GetSurfaceLevel(0,&pRenderSurface);  下一步就是创建一个适合纹理维数的投影矩阵,因为纹理的横纵比和后台缓冲区的不一样。  D3DXMatrixPerspectiveFovLH(&matProjection,D3DX_PI / 4.0f,1,1,100);  在我们的循环渲染之前,我们必须保存后台缓冲区和它的投影矩阵。  g_App.GetDevice()-&GetTransform(D3DTS_PROJECTION,&matOldProjection);  g_App.GetDevice()-&GetRenderTarget(0,&pBackBuffer);  渲染循环函数可以分为两个部分。第一部分是渲染到纹理的过程。因此,渲染对象必须设为纹理表面。然后我们就可以把东西渲染到这个对象上了。渲染到另一个表面上和正常地渲染到后台缓冲区差不多。只有一点不同,那就是先不调用Prensent()函数,因为纹理上的内容并不需要显示在屏幕上。象平时一样,我们先要重置表面颜色缓冲区,并且调用BeginSence()和EndSence()方法。为了能够适当的渲染,我们必须设置和纹理表面相符的投影矩阵。否则最后的图象可能被扭曲  //render-to-texture  g_App.GetDevice()-&SetRenderTarget(0,pRenderSurface); //set new render target  g_App.GetDevice()-&Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(100,100,100),1.0f,0); //clear texture  g_App.GetDevice()-&BeginScene();  g_App.GetDevice()-&SetTexture(0,pPyramideTexture);  D3DXMatrixRotationY(&matRotationY,fRotation);  D3DXMatrixTranslation(&matTranslation,0.0f,0.0f,5.0f);  g_App.GetDevice()-&SetTransform(D3DTS_WORLD,&(matRotationY * matTranslation));  g_App.GetDevice()-&SetTransform(D3DTS_PROJECTION,&matProjection); //set projection matrix  g_App.GetDevice()-&SetStreamSource(0,pTriangleVB,0,sizeof(D3DVERTEX));  g_App.GetDevice()-&DrawPrimitive(D3DPT_TRIANGLELIST,0,4);  g_App.GetDevice()-&EndScene();  渲染循环的第二部分就是渲染最后场景的过程(也就是显示到屏幕上的过程)。渲染对象重新设为后台缓冲区,投影矩阵重新设为原来的投影矩阵。由于纹理已经准备好了,所以它和纹理层0相关联。  //render scene with texture  g_App.GetDevice()-&SetRenderTarget(0,pBackBuffer); //set back buffer  g_App.GetDevice()-&Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,0),1.0f,0);  g_App.GetDevice()-&BeginScene();  g_App.GetDevice()-&SetTexture(0,pRenderTexture); //set rendered texture  g_App.GetDevice()-&SetTransform(D3DTS_WORLD,&matTranslation);  g_App.GetDevice()-&SetTransform(D3DTS_PROJECTION,&matOldProjection); //restore projection matrix  g_App.GetDevice()-&SetStreamSource(0,pQuadVB,0,sizeof(D3DVERTEX));  g_App.GetDevice()-&DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);  g_App.GetDevice()-&EndScene();  g_App.GetDevice()-&Present(NULL,NULL,NULL,NULL);  最后我们通过调用Release()方法释放Surface对象。  pRenderSurface-&Release();  pRenderSurface = NULL;  pBackBuffer-&Release();  pBackBuffer = NULL;  渲染到纹理能让你做很多事情,但是你必须注意一些限制。首先深度缓冲区必须总是大于或等于渲染对象的大小。此外,渲染对象和深度缓冲区的格式必须一致。
什么是纹理
熟悉DX的兄弟们都知道什么叫纹理了,这里简单介绍一下,先看看现实生活中的例子吧,其实纹理的例子比比皆是,比如地板,墙面都是纹理。在图形学中,纹理主要是为了增强场景的真实感,比如你想绘制一个地面,简单一点可以直接使用一个矩形,稍微复杂一点可以用三角形网格,再复杂一点可以使用地面纹理,有了纹理以后真实感明显增强了。DX中的纹理其实就是就是对现实生活中纹理的模拟,但是它不仅仅是一张图片那么简单,有着完整的数据结构,比如宽度,高度,内存类型,表面(Surface)等。
渲染到纹理
常规的渲染操作都是直接将场景呈现到backbuffer中的,backbuffer说白了其实就是一个表面,再说白了就是一块内存,场景通过绘制函数载入显存后,再通过Present函数送至显示器。那么为什么还要渲染到纹理呢?这是为了实现一些特殊的效果,比如常见的环境映射,简单的说,想象你有一个光滑的球体,它应该是可以反射周围的物体的,这就是环境映射。
上面说了常规的渲染操作是将场景送至backbuffer,而backbuffer实际上是一个Surface,而纹理恰恰又包含了Surface,所以我们只需要取得纹理的Surface,其次将场景送至这个Surface,最后再把这个纹理渲染到backbuffer中即可。举个例子,假设你要在一面墙壁上画一幅画,你有两种方法
1 直接在墙上画,这个很好理解,就对应常规的backbuffer渲染。
2 先将画画在纸上,然后将纸贴到墙上,这就对应渲染到纹理的过程。
这里墙壁相当于backbuffer,而纸张相当于纹理的Surface,在纸上作画相当于渲染到纹理,把纸贴到墙上相当于把纹理渲染到backbuffer,希望大家没有迷糊就好。具体的步骤如下
1 创建纹理并获得纹理的表面(Surface)
2 向纹理的表面渲染场景
3 渲染纹理本身
创建纹理并获取纹理表面
为了在纹理上渲染,我们应该先准备一个纹理,使用DX的函数CreateTexture就可以创建一个纹理了,注意在设置参数的时候需要将usage设置为D3DUSAGE_RENDERTARGET,因为只有这样才能在纹理上渲染。
IDirect3DTexture9*&&& &&& g_pRenderTexture&&& = NULL ;&//&Create texture&HRESULT hr&=&g_pd3dDevice-&CreateTexture(&256,&256,&1, D3DUSAGE_RENDERTARGET, D3DFMT_R5G6B5, D3DPOOL_DEFAULT,&g_pRenderTexture, NULL) ;&if&(FAILED(hr)) { MessageBox(NULL,&"Create texture failed!",&"Error",&0) ;return&E_FAIL ; }
下面我们要取得纹理对应的Surface,以便在其上绘制场景,
IDirect3DSurface9*&&& &&& g_pRenderSurface&&& = NULL ;&//&Get texture surface&hr&=&g_pRenderTexture-&GetSurfaceLevel(0,&&g_pRenderSurface) ;&if&(FAILED(hr)) { MessageBox(NULL,&"Get surface on texture failed!",&"Error",&0) ;&return&E_FAIL ; }
将场景渲染至纹理表面
下面开始向纹理的Surface中绘制场景,为了简单起见,这里绘制一个茶壶,需要注意的是,绘制时需要将纹理的表面设置为当前的RenderTarget,所以首先要保存原来的RenderTarget。
//&保存旧的RenderTarget&g_pd3dDevice-&GetRenderTarget(0,&&g_pOldRenderTarget) ;&//&设置纹理表面为当前RenderTarget&g_pd3dDevice-&SetRenderTarget(0, g_pRenderSurface) ; g_pd3dDevice-&Clear(&0, NULL, D3DCLEAR_TARGET&|&D3DCLEAR_ZBUFFER,&0xff0000ff,&1.0f,&0&);&&&if( SUCCEEDED( g_pd3dDevice-&BeginScene() ) ) {&g_pd3dDevice-&SetTexture(0, NULL) ;&g_pd3dDevice-&SetRenderState( D3DRS_LIGHTING , FALSE ); g_pd3dDevice-&SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME) ; g_pTeapotMesh-&DrawSubset(0) ;&//&绘制茶壶&g_pd3dDevice-&EndScene(); }
渲染纹理本身
接下来将纹理渲染到backbuffer,在这之前要恢复原来的RenderTarget,因为这次是将纹理送到backbuffer,而backbuff而就是原来的RenderTarget。
//&恢复RenderTarget&g_pd3dDevice-&SetRenderTarget(0, g_pOldRenderTarget) ; g_pd3dDevice-&Clear(&0, NULL, D3DCLEAR_TARGET&|&D3DCLEAR_ZBUFFER,&0xff00ff00,&1.0f,&0&);&&&if( SUCCEEDED( g_pd3dDevice-&BeginScene() ) ) { g_pd3dDevice-&SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID) ;&//&绘制纹理RenderQuad() ;&g_pd3dDevice-&EndScene(); }&&&g_pd3dDevice-&Present( NULL, NULL, NULL, NULL );
虽然是两次渲染,但是只需要调用一次present函数,因为之前的绘制只是将场景送至显存,而Present函数才真正将场景显示出来。
上面的代码用到了自定义函数RenderQuad,这个函数将纹理渲染出来,细节如下
void&RenderQuad() {&//&Setup texture&g_pd3dDevice-&SetTexture(0, g_pRenderTexture) ; g_pd3dDevice-&SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); g_pd3dDevice-&SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); g_pd3dDevice-&SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); g_pd3dDevice-&SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP ); g_pd3dDevice-&SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP );&//&Set stream source&g_pd3dDevice-&SetStreamSource(0, g_pVB,&0,&sizeof(Vertex) ); g_pd3dDevice-&SetFVF(VertexFVF) ; g_pd3dDevice-&DrawPrimitive(D3DPT_TRIANGLESTRIP,&0,&2) ; }
最后,看一下效果图
其实这个图并没有真正体现渲染到纹理的威力,虽然技术上是,但给人的感觉就好像直接渲染了一张图片一样,为了实现更加高级的效果,我们可以设置一个Cube,并给这个Cube加上纹理,然后在每个纹理的表面绘制场景,甚至可以是动态场景,效果如下。
其实这个Cube上的茶壶是动态旋转的,并且可以使用鼠标右键来旋转,滚轮来缩放,可以下载下面的文件来看一下动态效果。
Happy coding!!!
== THE END ==
阅读(...) 评论()您是访问本站的第位客人
&DirectX 10 教程22:绘制到纹理
DirectX 10 教程22:绘制到纹理
原文地址:。
源代码下载:。
本教程介绍如何实现绘制到纹理,代码基于教程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
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();
ID3D10Texture2D* m_renderTargetT
ID3D10RenderTargetView* m_renderTargetV
ID3D10ShaderResourceView* m_shaderResourceV
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 textureD
D3D10_RENDER_TARGET_VIEW_DESC renderTargetViewD
D3D10_SHADER_RESOURCE_VIEW_DESC shaderResourceViewD
// Initialize the render target texture description.
ZeroMemory(&textureDesc, sizeof(textureDesc));
// Setup the render target texture description.
textureDesc.Width = textureW
textureDesc.Height = textureH
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))
// Setup the description of the render target view.
renderTargetViewDesc.Format = textureDesc.F
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))
// Setup the description of the shader resource view.
shaderResourceViewDesc.Format = textureDesc.F
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))
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;
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);
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] =
color[1] =
color[2] =
color[3] =
// Clear the back buffer.
device->ClearRenderTargetView(m_renderTargetView, color);
// Clear the depth buffer.
device->ClearDepthStencilView(depthStencilView, D3D10_CLEAR_DEPTH, 1.0f, 0);
GetShaderResourceView方法以shader资源视图的方式返回绘制到纹理的数据,这样绘制到渲染目标视图的数据就可以作为一张纹理被其他shader使用。你通常会直接将一张纹理传递到shader中,但现在可以调用这个方法达到同样的效果。
ID3D10ShaderResourceView* RenderTextureClass::GetShaderResourceView()
return m_shaderResourceV
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
struct VertexType
D3DXVECTOR3
D3DXVECTOR2
DebugWindowClass();
DebugWindowClass(const DebugWindowClass&);
~DebugWindowClass();
bool Initialize(ID3D10Device*, int, int, int, int);
void Shutdown();
bool Render(ID3D10Device*, int, int);
int GetIndexCount();
bool InitializeBuffers(ID3D10Device*);
void ShutdownBuffers();
bool UpdateBuffers(int, int);
void RenderBuffers(ID3D10Device*);
ID3D10Buffer *m_vertexBuffer, *m_indexB
int m_vertexCount, m_indexC
int m_screenWidth, m_screenH
int m_bitmapWidth, m_bitmapH
int m_previousPosX, m_previousPosY;
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)
// Store the screen size.
m_screenWidth = screenW
m_screenHeight = screenH
// Store the size in pixels that this bitmap should be rendered at.
m_bitmapWidth = bitmapW
m_bitmapHeight = bitmapH
// 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)
void DebugWindowClass::Shutdown()
// Release the vertex and index buffers.
ShutdownBuffers();
bool DebugWindowClass::Render(ID3D10Device* device, int positionX, int positionY)
// Re-build the dynamic vertex buffer for rendering to possibly a different location on the screen.
result = UpdateBuffers(positionX, positionY);
if(!result)
// Put the vertex and index buffers on the graphics pipeline to prepare them for drawing.
RenderBuffers(device);
int DebugWindowClass::GetIndexCount()
return m_indexC
bool DebugWindowClass::InitializeBuffers(ID3D10Device* device)
VertexType*
unsigned long*
D3D10_BUFFER_DESC vertexBufferDesc, indexBufferD
D3D10_SUBRESOURCE_DATA vertexData, indexD
// Set the number of vertices in the vertex array.
m_vertexCount = 6;
// Set the number of indices in the index array.
m_indexCount = m_vertexC
// Create the vertex array.
vertices = new VertexType[m_vertexCount];
if(!vertices)
// Create the index array.
indices = new unsigned long[m_indexCount];
if(!indices)
// 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_indexC i++)
indices[i] =
// Set up the description of the dynamic vertex buffer.
vertexBufferDesc.Usage = D3D10_USAGE_DYNAMIC;
vertexBufferDesc.ByteWidth = sizeof(VertexType) * m_vertexC
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 =
// Now finally create the vertex buffer.
result = device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_vertexBuffer);
if(FAILED(result))
// Set up the description of the index buffer.
indexBufferDesc.Usage = D3D10_USAGE_DEFAULT;
indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexC
indexBufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;
// Give the subresource structure a pointer to the index data.
indexData.pSysMem =
// Create the index buffer.
result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer);
if(FAILED(result))
// Release the arrays now that the vertex and index buffers have been created and loaded.
vertices = 0;
indices = 0;
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;
bool DebugWindowClass::UpdateBuffers(int positionX, int positionY)
float left, right, top,
VertexType*
void* verticesP
// 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))
// 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_bitmapW
// 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_bitmapH
// Create the vertex array.
vertices = new VertexType[m_vertexCount];
if(!vertices)
// 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))
// 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.
vertices = 0;
void DebugWindowClass::RenderBuffers(ID3D10Device* device)
// 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);
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 //
//////////////
////////////////////////////////////////////////////////////////////////////////
// Class name: D3DClass
////////////////////////////////////////////////////////////////////////////////
class D3DClass
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();
bool m_vsync_
ID3D10Device* m_
IDXGISwapChain* m_swapC
ID3D10RenderTargetView* m_renderTargetV
ID3D10Texture2D* m_depthStencilB
ID3D10DepthStencilState* m_depthStencilS
ID3D10DepthStencilView* m_depthStencilV
ID3D10RasterizerState* m_rasterS
D3DXMATRIX m_projectionM
D3DXMATRIX m_worldM
D3DXMATRIX m_orthoM
ID3D10DepthStencilState* m_depthDisabledStencilS
D3dclass.cpp
下面的代码只包含与上一个教程不同的部分。
////////////////////////////////////////////////////////////////////////////////
// Filename: d3dclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "d3dclass.h"
GetDepthStencilView让调用对象可以访问深度模板视图。
ID3D10DepthStencilView* D3DClass::GetDepthStencilView()
return m_depthStencilV
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);
Graphicsclass.h
////////////////////////////////////////////////////////////////////////////////
// Filename: graphicsclass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _GRAPHICSCLASS_H_
#define _GRAPHICSCLASS_H_
/////////////
// GLOBALS //
/////////////
const bool FULL_SCREEN =
const bool VSYNC_ENABLED =
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
GraphicsClass();
GraphicsClass(const GraphicsClass&);
~GraphicsClass();
bool Initialize(int, int, HWND);
void Shutdown();
bool Frame();
bool Render();
新添了两个私有方法,我们需要将绘制分成两个pass(一次绘制到纹理,一次普通绘制)。
void RenderToTexture();
void RenderScene();
D3DClass* m_D3D;
CameraClass* m_C
ModelClass* m_M
LightShaderClass* m_LightS
LightClass* m_L
RenderTextureClass* m_RenderT
DebugWindowClass* m_DebugW
TextureShaderClass* m_TextureS
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)
// Create the Direct3D object.
m_D3D = new D3DC
if(!m_D3D)
// 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);
// Create the camera object.
m_Camera = new CameraC
if(!m_Camera)
// Create the model object.
m_Model = new ModelC
if(!m_Model)
// 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);
// Create the light shader object.
m_LightShader = new LightShaderC
if(!m_LightShader)
// 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);
// Create the light object.
m_Light = new LightC
if(!m_Light)
// 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 RenderTextureC
if(!m_RenderTexture)
// Initialize the render to texture object.
result = m_RenderTexture->Initialize(m_D3D->GetDevice(), screenWidth, screenHeight);
if(!result)
创建并初始化debug window对象。注意我将窗口大小设置为100x100,显然这样做会使图像变形,想要不变形,你只需将上述大小的长宽比设置得和屏幕的长宽比一致即可。
// Create the debug window object.
m_DebugWindow = new DebugWindowC
if(!m_DebugWindow)
// 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);
// Create the texture shader object.
m_TextureShader = new TextureShaderC
if(!m_TextureShader)
// 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);
void GraphicsClass::Shutdown()
// Release the texture shader object.
if(m_TextureShader)
m_TextureShader->Shutdown();
delete m_TextureS
m_TextureShader = 0;
在Shutdown方法中释放DebugWindowClass和RenderTextureClass对象。
// Release the debug window object.
if(m_DebugWindow)
m_DebugWindow->Shutdown();
delete m_DebugW
m_DebugWindow = 0;
// Release the render to texture object.
if(m_RenderTexture)
m_RenderTexture->Shutdown();
delete m_RenderT
m_RenderTexture = 0;
// Release the light object.
if(m_Light)
delete m_L
m_Light = 0;
// Release the light shader object.
if(m_LightShader)
m_LightShader->Shutdown();
delete m_LightS
m_LightShader = 0;
// Release the model object.
if(m_Model)
m_Model->Shutdown();
delete m_M
m_Model = 0;
// Release the camera object.
if(m_Camera)
delete m_C
m_Camera = 0;
// Release the Direct3D object.
m_D3D->Shutdown();
delete m_D3D;
m_D3D = 0;
bool GraphicsClass::Frame()
// Set the position of the camera.
m_Camera->SetPosition(0.0f, 0.0f, -5.0f);
bool GraphicsClass::Render()
D3DXMATRIX worldMatrix, viewMatrix, orthoM
第一个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)
// 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();
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();
RenderScene方法绘制整个场景。本教程中我们在RenderToTexture中调用它一次,将场景绘制到一张纹理中。然后再Render方法中再调用一次将场景绘制到常规的后备缓存中。
void GraphicsClass::RenderScene()
D3DXMATRIX worldMatrix, viewMatrix, projectionM
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());
现在你理解了绘制到纹理的基本方法。
1.编译并运行程序,你会看到一个旋转的立方体,并且在屏幕左上角显示一个蓝色背景的小立方体,这是绘制到纹理的效果。
2.修改debug window,使它的长宽比与屏幕的长宽比相同。
3.修改3D场景,确认也能正确地绘制到纹理。
4.修改相机的观察角度观察效果。
5.使用这个纹理作为你自己的shader的输入并改变输出结果(例如添加噪点、扫描行等效果)。
发布时间: 0:28:54&nbsp&nbsp 阅读次数:5708
Copyright &
上海市第八中学,推荐分辨率以上,推荐浏览器IE9.0及以上

我要回帖

更多关于 opengl和direct3d9 的文章

 

随机推荐