Direct-X学习笔记--变换
1.顶点格式改动:
之前写的几个例子都是2D的例子,使用的顶点格式是已经经过变换的顶点格式。而要写3D程序,我们就必须要用未经过变换的顶点。所以在定义顶点时也要有所改变:
//------------绘制图形步骤1.定义灵活顶点格式
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)//坐标为经过变换的屏幕坐标,顶点的颜色//------------绘制图形步骤2.根据上面定义的顶点格式,创建一个顶点的结构体
struct stVertex
{float x, y, z; //位置坐标DWORD dwColor; //颜色
};
这里我使用了顶点缓冲区绘图,通过三个顶点绘制了一个三角形,顶点坐标如下:
<span style="white-space:pre"> </span>{-1.0f, -1.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0)},{ 1.0f, -1.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0)},{ 0.0f, 1.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 255)}
打开的时候吓了我一跳。。。好大。。。
变换总览:
没有经过变换的3D世界,我们只能通过+z方向看。看到的东西也比较单调。要想看到一个比较真实的3D世界,就要通过各种变换了。
常用的变换一共有3种,世界变换,取景变换,投影变换。当然还有一个视口变换,不过个人感觉不需要矩阵操作,只是单纯的显示区域改变,与前面三种变换还是有点差距的。
WorldTransform(世界变换)
//平移D3DXMATRIXA16 matWorld;//矩阵平移操作D3DXMatrixTranslation(&matWorld, //输出矩阵0.0f, 1.0f, 0.0f //平移的距离,x,y,z);//进行平移变换g_pDevice->SetTransform(D3DTS_WORLD, &matWorld);
![](/assets/blank.gif)
D3DXMATRIXA16 matWorld;//生成绕Y轴旋转矩阵,存储于矩阵中D3DXMatrixRotationY(&matWorld, //输出矩阵timeGetTime()/150.0f //角度);g_pDevice->SetTransform(D3DTS_WORLD, &matWorld);
![](/assets/blank.gif)
缩放:
//缩放D3DXMATRIXA16 matScaling;//矩阵缩放,存入上面的矩阵中D3DXMatrixScaling(&matScaling, //输出矩阵0.5f, 0.5f, 1.0f //缩放的比例);g_pDevice->SetTransform(D3DTS_WORLD, &matScaling);
从这里我们发现,不论是哪种操作,都是预先定义一个矩阵,然后通过一个固定的函数,接受相关参数,生成一个矩阵,存储于我们定义的矩阵中,然后通过SetTransform()方法,将矩阵作为参数,进行相应的变换。
//矩阵相乘D3DXMATRIXA16 matWorld;D3DXMatrixMultiply(&matWorld, //结果&matScaling, //缩放矩阵&matTurn //旋转矩阵);//将第一次的结果再和平移矩阵相乘D3DXMatrixMultiply(&matWorld, //结果&matWorld, //第一次的结果&matMove //平移矩阵);//将结果用于世界变换g_pDevice->SetTransform(D3DTS_WORLD, &matWorld);
//上面的一大段乘法代码可以用这一句替换。。。
matWorld = matScaling * matTurn * matMove;
ViewTransform (取景变换)
//ViewTransform:取景变换D3DXVECTOR3 vEyePt(0.0f, 0.0f, -5.0f); //摄像机世界坐标D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f); //观察点世界坐标D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f); //摄像机的上向量,通常为(0.0f, 1.0f, 0.0f)D3DXMATRIXA16 matView; //View变换的矩阵//根据上面的结果计算出矩阵,存入矩阵中D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);//进行取景变换g_pDevice->SetTransform(D3DTS_VIEW, &matView);
ProjectionTransform (投影变换)
![](/assets/blank.gif)
D3DXMATRIXA16 matProj; //投影变换矩阵//生成投影变换矩阵,存入上面的矩阵中D3DXMatrixPerspectiveFovLH(&matProj, //输出结果矩阵D3DX_PI / 4, //视域角度,一般为PI/41.0f, //显示屏的长宽比1.0f, //视截体中近截面距离摄像机的位置100.0f //视截体中远截面距离摄像机的位置);//进行投影变换g_pDevice->SetTransform(D3DTS_PROJECTION, &matProj);
//ViewportTransform:视口变换D3DVIEWPORT9 vp = {0, //视口的左上角X坐标0, //视口的左上角Y坐标800, //视口的宽度500, //视口的高度0, //深度缓存中的最小深度值1 //深度缓存中的最大深度值};g_pDevice->SetViewport(&vp);
完整的Demo
学会了这几种基本的变换,综合运用一下。这里我画了一个三角形,使其绕着Y轴旋转。并改变了视口以及视角。
// D3DDemo.cpp : 定义应用程序的入口点。
//#include "stdafx.h"
#include "D3DDemo.h"#define MAX_LOADSTRING 100// 全局变量:
HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名// 此代码模块中包含的函数的前向声明:
HWND g_hWnd;
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//---------改造3D窗口需要的内容------------
LPDIRECT3D9 g_pD3D = NULL; //D3D接口指针
LPDIRECT3DDEVICE9 g_pDevice = NULL;//D3D设备指针//------------绘制图形步骤1.定义灵活顶点格式
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)//坐标为经过变换的屏幕坐标,顶点的颜色//------------绘制图形步骤2.根据上面定义的顶点格式,创建一个顶点的结构体
struct stVertex
{float x, y, z; //位置坐标DWORD dwColor; //颜色
};//----------绘制图形步骤3.声明一个顶点缓冲区指针&一个索引缓冲区指针
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;//初始化顶点缓冲区
void initVB()
{//----------绘制图形步骤4.定义一个结构体数组用来给每个顶点赋值//数组中存储当前程序中顶点的数据stVertex vertex[] = {{-1.0f, -1.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0)},{ 1.0f, -1.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0)},{ 0.0f, 1.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 255)}};//----------绘制图形步骤5.为定点缓冲区分配内存,并将数组中的顶点值拷贝到顶点缓冲区中//通过设备指针来创建顶点缓冲区,用来存储顶点数据g_pDevice->CreateVertexBuffer(sizeof(vertex), //顶点缓冲区大小D3DUSAGE_WRITEONLY, //顶点缓冲区作用D3DFVF_CUSTOMVERTEX, //通知系统顶点格式D3DPOOL_MANAGED, //顶点缓冲区存储位置,此处表示由系统处理&g_pVB, //返回顶点缓冲区指针NULL //系统保留参数,NULL);void* pVertices = NULL;//锁定顶点缓冲区,向其中拷贝数据g_pVB->Lock(0, //锁定的偏移量sizeof(vertex), //锁定的大小&pVertices, //锁定之后存储空间0 //锁定的标识,0);//将数组中的内容拷贝到缓冲区中memcpy(pVertices, vertex, sizeof(vertex));//解锁g_pVB->Unlock();}void onCreatD3D()
{g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);if (!g_pD3D)return;//检测硬件设备能力的方法/*D3DCAPS9 caps;ZeroMemory(&caps, sizeof(caps));g_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);*///获得相关信息,屏幕大小,像素点属性D3DDISPLAYMODE d3ddm;ZeroMemory(&d3ddm, sizeof(d3ddm));g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);//设置全屏模式D3DPRESENT_PARAMETERS d3dpp;ZeroMemory(&d3dpp, sizeof(d3dpp));/*d3dpp.Windowed = false;d3dpp.BackBufferWidth = d3ddm.Width;d3dpp.BackBufferHeight = d3ddm.Height;*/d3dpp.Windowed = true;d3dpp.BackBufferFormat = d3ddm.Format;d3dpp.BackBufferCount = 1;d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;//交换后原缓冲区数据丢弃//是否开启自动深度模板缓冲d3dpp.EnableAutoDepthStencil = true;//当前自动深度模板缓冲的格式d3dpp.AutoDepthStencilFormat = D3DFMT_D16;//每个像素点有16位的存储空间,存储离摄像机的距离g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pDevice);if (!g_pDevice)return;//设置渲染状态,设置启用深度值g_pDevice->SetRenderState(D3DRS_ZENABLE, true);//设置渲染状态,关闭灯光g_pDevice->SetRenderState(D3DRS_LIGHTING, false);//设置渲染状态,裁剪模式g_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);//g_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE) ;}void Transform()
{//WorldTransform:世界变换D3DXMATRIXA16 matWorld;//生成绕Y轴旋转矩阵,存储于矩阵中D3DXMatrixRotationY(&matWorld, //输出矩阵timeGetTime()/150.0f //角度);g_pDevice->SetTransform(D3DTS_WORLD, &matWorld);//ViewTransform:取景变换D3DXVECTOR3 vEyePt(0.0f, 0.0f, -5.0f); //摄像机世界坐标D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f); //观察点世界坐标D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f); //摄像机的上向量,通常为(0.0f, 1.0f, 0.0f)D3DXMATRIXA16 matView; //View变换的矩阵//根据上面的结果计算出矩阵,存入矩阵中D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);//进行取景变换g_pDevice->SetTransform(D3DTS_VIEW, &matView);//ProjectionTransform:投影变换D3DXMATRIXA16 matProj; //投影变换矩阵//生成投影变换矩阵,存入上面的矩阵中D3DXMatrixPerspectiveFovLH(&matProj, //输出结果矩阵D3DX_PI / 4, //视域角度,一般为PI/41.0f, //显示屏的长宽比1.0f, //视截体中近截面距离摄像机的位置100.0f //视截体中远截面距离摄像机的位置);//进行投影变换g_pDevice->SetTransform(D3DTS_PROJECTION, &matProj);//ViewportTransform:视口变换D3DVIEWPORT9 vp = {0, //视口的左上角X坐标0, //视口的左上角Y坐标800, //视口的宽度500, //视口的高度0, //深度缓存中的最小深度值1 //深度缓存中的最大深度值};g_pDevice->SetViewport(&vp);
}void onInit()
{//初始化D3DonCreatD3D();//初始化顶点缓冲区initVB();}void onDestroy()
{if (!g_pDevice)g_pDevice->Release();g_pDevice = NULL;
}void onLogic(float fElapsedTime)
{}void onRender(float fElasedTime)
{//前两个参数是0和NULL时,清空整个游戏窗口的内容(清的是后台)//第三个是清除的对象:前面表示清除颜色缓冲区,后面表示清除深度缓冲区,D3DCLEAR_STENCIL清空模板缓冲区g_pDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,100,100), 1.0f, 0);g_pDevice->BeginScene();Transform();//----------绘制图形步骤6.设置数据源,设置灵活顶点格式,绘制图元//设置数据流来源g_pDevice->SetStreamSource(0, //数据流管道号(0-15)g_pVB, //数据来源0, //数据流偏移量sizeof(stVertex) //每个数据的字节数大小);//通知系统数据格式,以便解析数据g_pDevice->SetFVF(D3DFVF_CUSTOMVERTEX);//绘制图元 g_pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, //三角形列0, //起始点编号1 //图元数量);g_pDevice->EndScene();g_pDevice->Present(NULL, NULL, NULL, NULL);
}int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPTSTR lpCmdLine,_In_ int nCmdShow)
{UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);// TODO: 在此放置代码。MSG msg;HACCEL hAccelTable;// 初始化全局字符串LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadString(hInstance, IDC_D3DDEMO, szWindowClass, MAX_LOADSTRING);MyRegisterClass(hInstance);// 执行应用程序初始化:if (!InitInstance (hInstance, nCmdShow)){return FALSE;}hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_D3DDEMO));ZeroMemory(&msg, sizeof(msg));while (msg.message != WM_QUIT){if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);}else{static DWORD dwTime = timeGetTime();DWORD dwCurrentTime = timeGetTime();DWORD dwElapsedTime = dwCurrentTime - dwTime;float fElapsedTime = dwElapsedTime * 0.001f;//------------渲染和逻辑部分代码----------onLogic(fElapsedTime);onRender(fElapsedTime);//-----------------------------------------if (dwElapsedTime < 1000 / 60){Sleep(1000/ 60 - dwElapsedTime);}dwTime = dwCurrentTime;}}onDestroy();return (int) msg.wParam;
}//
// 函数: MyRegisterClass()
//
// 目的: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WndProc;wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_D3DDEMO));wcex.hCursor = LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName = MAKEINTRESOURCE(IDC_D3DDEMO);wcex.lpszClassName = szWindowClass;wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));return RegisterClassEx(&wcex);
}//
// 函数: InitInstance(HINSTANCE, int)
//
// 目的: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{hInst = hInstance; // 将实例句柄存储在全局变量中g_hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);if (!g_hWnd){return FALSE;}SetMenu(g_hWnd, NULL);ShowWindow(g_hWnd, nCmdShow);UpdateWindow(g_hWnd);onInit();return TRUE;
}//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND g_hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{switch (message){case WM_KEYDOWN:if (wParam == VK_ESCAPE)PostQuitMessage(0);break;case WM_CLOSE:DestroyWindow(g_hWnd);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(g_hWnd, message, wParam, lParam);}return 0;
}
![](/assets/blank.gif)
Direct-X学习笔记--变换相关推荐
- Direct 3D学习笔记(三)——光照与材质
Direct 3D学习笔记(三)--光照与材质 现实世界中物体的颜色是一个复杂的系统,物体在不同的光照下,可能呈现在我们面前的就是不同的颜色.根据物理中的光学知识,物体在各种环境光照下,根据物体自身特 ...
- 单目深度估计 | Learning Depth from Monocular Videos using Direct Methods 学习笔记
文章目录 摘要 1. 论文主要贡献: 2. 从视频中学习预测深度 2.1 尺度模糊 2.2 建模姿态估计预测器 3. 可微分直接视觉测距法 3.1 直接视觉测距法(DVO) 3.2 可微分的实现 4 ...
- Direct 3D学习笔记三:矩阵
仍然是基于先前的程序. 首先来介绍三个基本的矩阵,这是direct 3d中必须设置的三个矩阵,即世界矩阵,视图矩阵,投影矩阵.而对应的三个变换就是世界变换(World Transform),摄 ...
- dx12 龙书第三章学习笔记 -- 变换
1.线性变换: 函数的输入和输出都是3D向量,我们称为线性变换 矩阵表示法: ⭐所以已知一个线性变换,只要将i,j,z也就是标准基向量代入线性变换,就能构造一个变换矩阵 A:线性变换的矩阵表示法 ...
- 【学习笔记】超简单的快速数论变换(NTT)(FFT的优化)(含全套证明)
整理的算法模板合集: ACM模板 目录 一.前置知识 二.快速数论变换(NTT) 三.NTT证明(和FFT的关系) 四.NTT模板 数组形式的实现 vector形式的实现 点我看多项式全家桶(●^◡_ ...
- OpenCV学习笔记(十六)——CamShift研究 OpenCV学习笔记(十七)——运动分析和物体跟踪Video OpenCV学习笔记(十八)——图像的各种变换(cvtColor*+)imgproc
OpenCV学习笔记(十六)--CamShift研究 CamShitf算法,即Continuously Apative Mean-Shift算法,基本思想就是对视频图像的多帧进行MeanShift运算 ...
- 数字图像处理学习笔记(三):ORB算法(尺度不变特征变换)Oriented FAST and Rotated BRIEF
数字图像处理学习笔记(三):ORB算法(尺度不变特征变换)Oriented FAST and Rotated BRIEF 一.概述 参考:特征点匹配+特征检测方法汇总 ORB的全称是Oriented ...
- 数字图像处理学习笔记(二):SIFT(尺度不变特征变换)算法
数字图像处理学习笔记(二):SIFT(尺度不变特征变换)算法 一.概述: 提到特征点算法,首先就是大名鼎鼎的SIFT算法了.SIFT的全称是Scale Invariant Feature Transf ...
- opengl源码 实现无缝切换图片过场_OpenGL学习笔记(六)变换
本文为学习LearnOpenGL的学习笔记,如有书写和理解错误还请大佬扶正: 教程链接: https://learnopengl-cn.github.io/01%20Getting%20started ...
最新文章
- STM32中GPIO的8种工作模式
- oracle spool用法
- 豪掷十亿拿下CUBA运营权,阿里体育未来也许并不轻松
- Springboot解决IDEA读取properties配置文件的中文乱码问题
- Centos5.5上vsftpd安装使用
- 一条数据的漫游奇遇记
- 从零搭建自己的SpringBoot后台框架(七)
- 12个有趣的C语言面试题
- sqlserver垮库查询_SQLServer跨库查询--分布式查询
- 电源变换适用于非独立源码_适用于非None测试的Python程序
- 组策略里更改更新和设置客户端首页
- 开源GIS(五)——openlayers中interaction的select、draw与modify
- 好的架构不是设计出来的,而是演进出来的
- 解决POI导出Excel时无法把单元格格式设置成数值类型,而不是变为货币或者自定义(附带相关问题的解决方法)
- python双色球数据抓取及模拟生成高概率的号码
- 洛谷 P1007 独木桥 思维
- C# 博思得 POSTEK 打印机 打码机 SDK 二次开发 指令打印
- JAVA——34.集合函数-List
- UINO优锘科技:一台物理发动机带你看懂数字孪生八要素
- Minos嵌入式虚拟化方案 - 系统架构介绍