文章目录

  • 纹理
    • 纹理资源格式
    • Direct3D中的纹理
  • 坐标系
    • 视口
  • 代码
  • 离屏表面和纹理内存的比较
  • 参考资料

图片渲染,在前文【DirectX3D - 2】渲染YUV图片(离屏表面方式)已经介绍过使用离屏表面的方式渲染图片了。本文介绍使用纹理内存的方式来渲染图片

纹理

纹理资源格式

  • 图 - 1 [1]

Direct3D中的纹理

表示物体表面细节的一幅或几幅二维图形,也称纹理贴图(texture mapping)当把纹理按照特定的方式映射到物体表面上的时候能使物体看上去更加真实。纹理映射是一种允许我们为三角形赋予图象数据的技术;这让我们能够更细腻更真实地表现我们的场景。[2]

我们在这里使用纹理来渲染图片,简单的我们既可以将纹理视为一张图片,我们的目标就是要将这一张图片,贴在我们预先设置好的区域内。这个区域可以是屏幕窗口的区域,也可以是窗口中某个三维物体的一个表面。在本文中,我们的目的是将图片显示在窗口中。

坐标系

四大变换
世界变换、取景变换、投影变换、视口变换

  • 为了在世界空间中的指定位置绘制图形,需要进行世界变换
  • 为了以不同的视角观察图形,需要进行取景变换
  • 为了将相对较远的图形投影到同一个平面上并体现出“近大远小”的真实视觉效果,需要进行投影变换
  • 为了控制显示图形的窗口大小、比例以及深度,需要用到视口变换

视口

typedef struct D3DVIEWPORT9 {    DWORD X;    DWORD Y;    DWORD Width;    DWORD Height;   float MinZ;    float MaxZ;
} D3DVIEWPORT9, *LPD3DVIEWPORT9;

用DirectX实现多视图有几种方法,可以使用多个Viewport,也可以使用多个Swap Chain,后者实现起来比较复杂,以后再做介绍,先看如何使用多个viewport来实现。那么到底什么是viewport呢?举个现实中的例子,假设你站在一个密封的房子里,这个房子只有一个很小的窗口,你现在就站在窗口前面,通过这个窗口你可以观察到外面的世界,那么这个窗口就相当于一个视口,而外面的世界就是3D中的场景。视口有以下几个属性,长度和宽度,为了确定窗口的位置,我们还需要一个左上角坐标。为了支持Z-Buffer,还需要两个深度值,分别是zMin, zMax,表示最小深度和最大深度。这就是视口的定义。
在D3D中,视口用如上的结构体来表示,X和Y表示视口的左上角坐标,Width和Height表示窗口的宽度和高度,MinZ和MaxZ表示Z-buffer的最小值和最大值。[3]

在本例子中,图片的不同视口,区别不大,我们可以通过改变参数来改变视口的大小, 从而看见不同大小的图片。而在三维渲染中,我们通过不同的视口,能够从不同的角度观察物体, 例如三视图就可以看做是不同视口的观察结果。

关于D3D中的坐标系可以参看以下资料:

https://www.cnblogs.com/kex1n/archive/2011/08/19/2145866.html

代码

/***************************************************************************************创建纹理内存,渲染图片***************************************************************************************/#include <windows.h>
#include <stdio.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>
#include <time.h>
#include "d3dx9math.h"#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib, "winmm.lib") #define WINDOW_WIDTH    1600
#define WINDOW_HEIGHT   900#define Safe_Release(p) if((p)) (p)->Release();HWND g_hwnd;
HINSTANCE g_inst;
static wchar_t g_class_name[] = L"D3D TEST";
static wchar_t g_caption[] = L"D3D Texture";IDirect3D9Ex* g_d3d = NULL;
IDirect3DDevice9* g_d3d_device = NULL;
IDirect3DVertexBuffer9* g_vertex_buffer = NULL;    // 顶点坐标缓存
IDirect3DTexture9* g_texture = NULL;           // 纹理// 3D顶点格式
typedef struct
{float x, y, z;  // 3D 坐标, z = 0, 表示2维平面float u, v;     // 纹理坐标} VERTEX;#define VERTEX_FVF   (D3DFVF_XYZ | D3DFVF_TEX1)long WINAPI Window_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{switch (msg) {case WM_DESTROY:PostQuitMessage(0);return 0;}return (long)DefWindowProc(hwnd, msg, wParam, lParam);
}BOOL d3d_init()
{D3DPRESENT_PARAMETERS present_param;D3DDISPLAYMODE  display_mode;D3DXMATRIX mat_proj, mat_view;BYTE* vertex_ptr;// 纹理坐标(u,v)的范围是[0, 1],在这里的设置,(0,0)(1,0)(0,1)(1,1),表示一个矩形VERTEX verts[] = {{ -200.0f,  200.0f, 0.0f, 0.0f, 0.0f },{  200.0f,  200.0f, 0.0f, 1.0f, 0.0f },{ -200.0f, -200.0f, 0.0f, 0.0f, 1.0f },{  200.0f, -200.0f, 0.0f, 1.0f, 1.0f }};Direct3DCreate9Ex(D3D_SDK_VERSION, &g_d3d);if (FAILED(g_d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &display_mode)))return FALSE;ZeroMemory(&present_param, sizeof(present_param));// 初始化参数present_param.Windowed = TRUE;present_param.SwapEffect = D3DSWAPEFFECT_DISCARD;present_param.BackBufferFormat = display_mode.Format;present_param.EnableAutoDepthStencil = TRUE;present_param.AutoDepthStencilFormat = D3DFMT_D16;// 创建D3D设备if (FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hwnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_param, &g_d3d_device))) {return FALSE;}      // 设置渲染状态// FALSE:关闭渲染灯光g_d3d_device->SetRenderState(D3DRS_LIGHTING, FALSE);// 使能z坐标,这里不需要使用纵坐标注释掉// g_d3d_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);// 创建设置投影矩阵// builds a left-handed perspective projection matrix based on a field of viewD3DXMatrixPerspectiveFovLH(&mat_proj, D3DX_PI / 4.0, 1.33333, 1.0, 1000.0);// sets a single device transformation-related stateg_d3d_device->SetTransform(D3DTS_PROJECTION, &mat_proj);// create and set the view matrixD3DXMatrixLookAtLH(&mat_view,&D3DXVECTOR3(0.0, 0.0, -1000.0),&D3DXVECTOR3(0.0f, 0.0f, 0.0f),&D3DXVECTOR3(0.0f, 1.0f, 0.0f));g_d3d_device->SetTransform(D3DTS_VIEW, &mat_view);// create the vertex buffer and set datag_d3d_device->CreateVertexBuffer(sizeof(VERTEX) * 4, 0, VERTEX_FVF, D3DPOOL_DEFAULT, &g_vertex_buffer, NULL);// locks a range of vertex data and obtains a pointer to the vertex buffer memoryg_vertex_buffer->Lock(0, 0, (void**)& vertex_ptr, 0);memcpy(vertex_ptr, verts, sizeof(verts));// unlocks vertex datag_vertex_buffer->Unlock();// load the texture mapD3DXCreateTextureFromFile(g_d3d_device, L"test.png", &g_texture);return TRUE;
}BOOL d3d_release()
{Safe_Release(g_vertex_buffer);Safe_Release(g_texture);Safe_Release(g_d3d_device);Safe_Release(g_d3d);return TRUE;
}BOOL d3d_render()
{D3DXMATRIX mat_world;// 清理设备缓存g_d3d_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(0, 0, 0, 0), 1.0f, 0);// Begin sceneif (SUCCEEDED(g_d3d_device->BeginScene())){// 创建和设置世界转换矩阵,沿着 z 轴旋转// D3DXMatrixRotationZ(&mat_world, (float)(timeGetTime() / 1000.0));// 创建和设置世界转换矩阵,不旋转D3DXMatrixRotationZ(&mat_world, 0.0);// 平移矩阵, 向左平移200,向下平移100个单位/*D3DXMATRIX mTrans;D3DXMatrixTranslation(&mTrans, -200, -100, 0);mat_world *= mTrans;D3DXMatrixMultiply(&mat_world, &mat_world, &mTrans);*/// 设置视口位置D3DVIEWPORT9 vp = {0, 320, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 1};g_d3d_device->SetViewport(&vp);// 认定矩阵 mat_world 就是世界矩阵g_d3d_device->SetTransform(D3DTS_WORLD, &mat_world);// 设置顶点流、着色器和纹理。// 将顶点缓冲区设置到设备数据流g_d3d_device->SetStreamSource(0, g_vertex_buffer, 0, sizeof(VERTEX));// 设置当前顶点流声明g_d3d_device->SetFVF(VERTEX_FVF);// 设置设备纹理g_d3d_device->SetTexture(0, g_texture);// 从当前数据输入流集中呈现指定类型的无索引几何原语序列。g_d3d_device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);// 清空纹理g_d3d_device->SetTexture(0, NULL);g_d3d_device->EndScene();}return TRUE;
}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR cmd_line, int cmd_show)
{WNDCLASSEX  win_class;MSG         msg;g_inst = hInstance;win_class.cbSize = sizeof(win_class);win_class.style = CS_CLASSDC;win_class.lpfnWndProc = Window_Proc;win_class.cbClsExtra = 0;win_class.cbWndExtra = 0;win_class.hInstance = hInstance;win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);win_class.hCursor = LoadCursor(NULL, IDC_ARROW);win_class.hbrBackground = NULL;win_class.lpszMenuName = NULL;win_class.lpszClassName = g_class_name;win_class.hIconSm = LoadIcon(NULL, IDI_APPLICATION);if (!RegisterClassEx(&win_class))return FALSE;g_hwnd = CreateWindow(g_class_name, g_caption,WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);if (g_hwnd == NULL)return FALSE;ShowWindow(g_hwnd, SW_NORMAL);UpdateWindow(g_hwnd);if (d3d_init() == FALSE)return FALSE;ZeroMemory(&msg, sizeof(MSG));while (msg.message != WM_QUIT) {if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {TranslateMessage(&msg);DispatchMessage(&msg);}d3d_render();g_d3d_device->Present(NULL, NULL, NULL, NULL);}d3d_release();UnregisterClass(g_class_name, hInstance);return (int)msg.wParam;
}

离屏表面和纹理内存的比较

离屏表面的方式,一般只用来显示数据,因为不能定义坐标来丰富显示的方式,所以这种方式使用简单;而使用纹理内存的方式,可以自定义坐标,能够使数据以更加灵活的方式呈现出来,不过用法相较表面(Surface)就复杂一些。
另外,使用纹理内存的方式,可以与CUDA结合操作GPU显存,有更广泛的应用场景。至于D3D与CDUA的互操作性,在后面的文章会陆续讲到。

参考资料

[1] 《Introduction to 3D Game Programming with Directx 11》, 第4.1.3章节
[2] https://baike.baidu.com/item/%E7%BA%B9%E7%90%86/5401676?fr=aladdin
[3] https://www.cnblogs.com/graphics/archive/2011/03/26/1994366.html

【Directx3D-4】渲染图片(纹理贴图方式)相关推荐

  1. LBP算法提取图片纹理特征图

    LBP算法提取图片纹理特征图 一.项目目标 采用LBP算法提取图片的纹理特征图. 二.LBP算法原理 LBP指局部二值模式,英文全称:Local Binary Patterns.最初功能为辅助图像局部 ...

  2. OpenGL png图片 纹理贴图,去除png图片黑边

    http://blog.csdn.net/cjkwin/article/details/6011882 用libpng把png图片读出来就可以用读出的数据生成文理了. 将png图片作为纹理贴图,在图片 ...

  3. opengl1.x版本固定管线的纹理贴图方式

    NeHe OpenGL第六课:纹理映射      PS:上图右为笔者,仅删除第五课中的立方体,加入本课新构建的纹理的立方体后的效果! 纹理映射: 在这一课里,我将教会你如何把纹理映射到立方体的六个面. ...

  4. 渲染图片纹理与原图不一致的原因

    测试平台:ogre 测试条件:图像512512 结果:渲染图像和原图一致 测试条件:图像400400 结果:渲染图像与原图不一致 原因:在当前主流的渲染引擎中,对于非2次幂分辨率图像,在渲染管线中会将 ...

  5. opengl生成图片php,(转)使用OpenGL显示图像(七)Android OpenGLES2.0——纹理贴图之显示图片...

    转:http://blog.csdn.net/junzia/article/details/52842816 前面几篇博客,我们将了Android中利用OpenGL ES 2.0绘制各种形体,并在上一 ...

  6. Android Studio OpenGL ES绘制三棱锥/四面体的多纹理贴图 每个面使用一张图片渲染

    本文参考了王刚的<疯狂Android讲义(第3版)>P554-P559 要求:利用OpenGL ES绘制一个三棱锥,并对每个面进行纹理贴图,每个面使用不同的图片进行渲染. 环境:Andro ...

  7. Three TextureLoader纹理贴图不显示图片(显示黑色)

    本人初学three.js,根据Three中文文档学习,在学习过程中发现TextureLoader纹理贴图不显示图片(显示黑色),在文档中的代码如下所示: // 纹理贴图映射到一个矩形平面上 var g ...

  8. Three TextureLoader纹理贴图不显示图片(显示黑色)的原因分析

    两种原因: 1.物体材质不对 代码: // 纹理贴图映射到一个矩形平面上 var geometry = new THREE.PlaneGeometry(204, 102); //矩形平面 // Tex ...

  9. 实时渲染学习(四)纹理贴图及相关技术

    参考博文:[<Real-Time Rendering 3rd> 提炼总结](五) 第六章 · 纹理贴图及相关技术 概念导览: 纹理管线 The Texturing Pipeline 投影函 ...

最新文章

  1. [生态建设] - js判断小技巧
  2. C和指针之结构体大小和成员变量位置距离结构开始存储的位置偏移字节
  3. java inputstream read_20191209-java部分流处理
  4. Notification使用详解之三:通过服务更新进度通知在Activity中监听服务进度
  5. nginx配置文件注释说明
  6. CSDN Markdown 文本居中、右对齐、左对齐
  7. Python学习笔记(五)--Python数据类型-数字及字符串
  8. 《I'm a Mac:雄狮训练手册》——2.3 账户类型
  9. openmeetings(开源视频会议系统)的详细安装步骤 (windows版)
  10. jsoncpp添加对象、数组与json对象的解析
  11. Ubuntu NumPy 安装
  12. matlab适应度函数为什么有2个输出,基于遗传算法的LQR优化问题,适应度函数总是报错。...
  13. 记YY的一次面试经历
  14. 英语词根词缀记忆法(全集)_语言学习 | 英语词根词缀学习参考
  15. 翻译go项目代码英文注释
  16. 基于Arduino Uno开发板的红外遥控开发
  17. Java逍遥游记_我与《Java逍遥游记》
  18. spring的优点与缺点
  19. Java算法训练:沙盘上的字符串
  20. 【安卓基础】基于Android Studio的家庭理财通项目

热门文章

  1. 深度学习-第T5周——运动鞋品牌识别
  2. 相似度计算(1)——余弦相似度
  3. 前端技术学习记录:react+dvajs+ant design实现暴走计算器的页面重构(一)
  4. win8服务器修改密码,Win8在哪里设置取消开机密码
  5. 【亲测有效】PD虚拟机 17 for Mac功能 pd虚拟机支持m1和12系统
  6. MicroPython开发板
  7. 云计算ACP云服务器ECS实例题库(二)
  8. Linux noVNC 下载安装、配置、运行
  9. 7Z010 引脚功能详解
  10. html连接手机与电视,电视可以连接手机看电视吗