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,  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 ) ;  //  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,  0xff00ff00 1.0f 0  );
 
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,  0 sizeof (Vertex) );
     g_pd3dDevice
-> SetFVF(VertexFVF) ;

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

最后,看一下效果图

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

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

动态效果文件

Happy coding!!!

== THE END ==


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

相关文章
|
前端开发
Threejs - 加载视频纹理渲染 实现一个3D视频播放器
Threejs - 加载视频纹理渲染 实现一个3D视频播放器
2055 0
Threejs - 加载视频纹理渲染 实现一个3D视频播放器
|
2月前
|
缓存 图形学
Unity3D学习笔记12——渲染纹理
Unity3D学习笔记12——渲染纹理
33 2
|
4月前
|
开发工具 图形学
【推荐100个unity插件之11】Shader实现UGUI的特效——UIEffect为 Unity UI 提供视觉效果组件
【推荐100个unity插件之11】Shader实现UGUI的特效——UIEffect为 Unity UI 提供视觉效果组件
164 0
|
存储 图形学
浅谈Unity之模型裁剪shader
Unity之模型裁剪shader
|
负载均衡 安全 vr&ar
【Unity渲染】一文看懂!Unity通用渲染管线URP介绍
Unity 的渲染管线包含内置渲染管线、SRP、URP和HDRP。自从Unity2019.3开始,Unity将轻量级渲染管线修改为了通用渲染管线,这是一种快速、可扩展的渲染管线,支持所有的移动设备,适用于 2D、3D、虚拟现实 (VR) 和增强现实 (AR) 项目。
|
缓存 BI API
从0开发游戏引擎之纹理管理器实现 纹理数据绑定OpenGL滤波方式选择线性滤波
从0开发游戏引擎之纹理管理器实现 纹理数据绑定OpenGL滤波方式选择线性滤波
|
编解码 数据可视化 图形学
webgl系列之对光栅化的理解
前言 周末没事的学习了光栅化进一步理解, 从底层去学习,遇到问题才会从容不迫, 并同时把这些知识分享给大家, 如果大家没时间看视频的话,废话不多说, 直接开始吧, 这里先做一个概念的铺垫在3D即将渲染到我们屏幕当中来的时候。而接下来我们要做的是把这个标准立方体绘制到屏幕上,这样才能最终被我们所看见。 不清楚的同学看下这篇文章吧 可视化入门跳转到坐标系转换那里 我们简单看下这张图: 图片 变换过程 而光栅化的过程发生在哪里 ,其实 就是物体通过MVP变换,把摄像机观测的空间压缩成了一个标准立方体。然后将标准的立方体【-,1,】绘制到屏幕上的这些过程 图片 转换 在做这步操作之前,我们首
webgl系列之对光栅化的理解
|
存储 缓存 算法
OpenGL图像渲染以及渲染问题解决方案
在绘制3D场景的时候,我们需要决定哪些部分是对观察者可见的,或者哪些部分是对观察者不可见的,对于不可见的部分,应该及早丢弃。例如在一个不透明的墙壁后,就不应该有渲染,这种情况叫做隐藏面消除(Hidden surface elimination).
610 0
OpenGL图像渲染以及渲染问题解决方案
|
开发工具 索引
WebGL 单通道wireframe渲染
WebGL 单通道wireframe渲染