开发者社区> 吞吞吐吐的> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

DirectX-渲染到纹理

简介:
+关注继续查看

什么是纹理

熟悉DX的兄弟们都知道什么叫纹理了,这里简单介绍一下,先看看现实生活中的例子吧,其实纹理的例子比比皆是,比如地板,墙面都是纹理。在图形学中,纹理主要是为了增强场景的真实感,如果你想绘制一个地面,简单一点可以直接使用一个矩形,稍微复杂一点可以用三角形网格,再复杂一点可以使用地面纹理,有了纹理以后真实感明显增强了。DX中的纹理映射其实就是对现实生活中纹理的模拟,D3D中有专门的数据结构来管理纹理。

渲染到纹理

常规的渲染操作都是直接将场景呈现到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。

复制代码
// Save old RenderTarget
g_pd3dDevice->GetRenderTarget(0&g_pOldRenderTarget) ;

//
 Set texture surface as RenderTarget
g_pd3dDevice->SetRenderTarget(0, g_pRenderSurface) ;
g_pd3dDevice
->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff0000ff1.0f0 );
 
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) ; // Draw teapot

     g_pd3dDevice->EndScene();
}
复制代码

渲染纹理本身

接下来将纹理渲染到backbuffer,在这之前要恢复原来的RenderTarget,因为这次是将纹理送到backbuffer,而backbuff而就是原来的RenderTarget。

复制代码
// Restore RenderTarget
g_pd3dDevice
->SetRenderTarget(0, g_pOldRenderTarget) ;

g_pd3dDevice
->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff00ff001.0f0 );
 
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
     g_pd3dDevice
->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID) ;

     
//Draw texture
     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, 0sizeof(Vertex) );
     g_pd3dDevice
->SetFVF(VertexFVF) ;

     g_pd3dDevice
->DrawPrimitive(D3DPT_TRIANGLESTRIP, 02) ;
}
复制代码

最后,看一下效果图

其实这个图并没有真正体现渲染到纹理的威力,虽然技术上是,但给人的感觉就好像直接渲染了一张图片一样,为了实现更加高级的效果,我们可以设置一个Cube,并给这个Cube加上纹理,然后在每个纹理的表面绘制场景,甚至可以是动态场景,效果如下。

其实这个Cube上的茶壶是动态旋转的,并且可以使用鼠标右键来旋转,滚轮来缩放,可以下载下面的文件来看一下动态效果。

动态效果文件

Happy coding!!!

== THE END ==


本文转自zdd博客园博客,原文链接:http://www.cnblogs.com/graphics/archive/2011/04/23/2024294.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
DirectX 矩阵
基础: 下标:第一个下标为该元素所在行的索引,第二个下标为该元素所在列的索引。如下图所示   行向量和列向量:只有单行的向量称为行向量,只有单列的称之为列向量。 相等 维数和元素都相等 数乘(与标量相乘) 每一个元素与标量相乘 加法(矩阵+矩阵=矩阵) 两个矩阵相应元素想加所得的矩阵,必须维数相等 矩阵乘法(矩阵*矩阵=矩阵) 条件:A的列数必须等于B的行数 定义:A(m*n) B(n*p) 则乘积AB有意义,且等于一个矩阵C(m*p),其中乘积C[i][j] = A的第i个行向量 * B的第j个列向量的点积。
962 0
Directx11教程(57) 环境映射
建好skydome后,如果我们想让其中的某个物体,比如那个球体来映射出周围环境的蓝天白云(不包括自己附近的物体),该怎么做呢?此时可以把这个球体当成一面镜子,把我们视点看这个物体上某个顶点p时的反射向量当作cube map查询向量v,得到纹理texel,然后p点的颜色可以用blend的方式,混合当前颜色和采样的纹理texel,就可以实现我们想要的效果。
777 0
Directx11教程(43) 纹理映射(13)-动态纹理映射
本篇教程中,我们将在前面基于光照的地形与水面程序里面加上纹理映射,而且我们会基于时间动态改变水面的纹理坐标,实现水面纹理波动的效果。       地形(山谷)以及水面都是基于网格的平面。
846 0
Directx11教程38 纹理映射(8)
上篇日志中,我们用纹理和光照颜色调制的方式得到最终颜色,本章我们尝试用纹理采样的颜色,直接做为材质的漫反射系数Kd,并用它来做光照计算,最后再做个gamma校正,如果不做的话,效果会偏亮。      lighttex.
759 0
Directx11教程(34) 纹理映射(4)
本篇教程中,我们尝试在myTutorialD3D_27中改变采样状态描述符的各种设置,看纹理贴图的方式有什么变化。 原始的代码是:     // 创建纹理采样描述符 samplerDesc.
769 0
Directx11教程(32) 纹理映射(2)
在写代码之前,我们先制作一个dds文件。从网上找到了一张照片,处理成为512*512,保存为jpg格式。     启动微软的directx texture tool后,把图片拖到其内:      选择文件Format->Generate Mip Maps,可以在图像的标题栏看到Mip 1 of 10的字样,这是因为我们原始图像大小为512*512,生成MipMaps时,会产生256*256, 128*128,…, 1*1,一系列下采样的图像,加上原始图像总共10个。
764 0
Directx11教程36 纹理映射(6)
本章主要是整理代码,做以下两件事情: 1、把世界坐标矩阵的计算,放在GraphicsClass的渲染函数中,之前放在D3DClass中,而且只是返回一个单位矩阵,没任何作用。如果要使其起作用,就要对每个model类都单独设置,很麻烦,比如我要画两个颜色立方体,岂不是要建立两个model类,而只是世界坐标矩阵不同。
722 0
文章
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载