DirectX12 3D游戏开发实践(龙书)第一章 向量代数
向量
- 第一章 向量代数
- 向量与坐标系
- 定义
- 坐标系
- 向量的基本运算
- 利用DirectXMath库对向量运算
- DirectXMath使用环境
- 向量类型
- 加载方法和存储方法
- 参数传递
- 常向量
- 运算符重载
- 杂项
- Setter函数
- 向量函数
- 浮点数误差
第一章 向量代数
向量与坐标系
定义
一种兼具大小和方向的量
坐标系
下图展现了向量v以及控件中俩组不同的标架(frame)
每当我们根据坐标来确定一个向量时,其对应的坐标总是相当于某一个参考系而言的。在3D计算图形学中,我们通常会用到较多的参考系。因此我们需要记录向量的每一种坐标系中对应的坐标。另外我们也需要知道如何将向量坐标在不同标架之间进行转换。
Direct3D采用的是左手坐标系,左手坐标系Z轴指向屏幕里,也就是眼睛看向方向,右手坐标系Z轴指向屏幕外,见下俩图。
向量的基本运算
点积是一种计算结果为标量值的向量乘法运算,因此有些时候也称标量积。设向量u=(ux,uy,uz)u=(u_x,u_y,u_z)u=(ux,uy,uz),v=(vx,vy,vz)v=(v_x,v_y,v_z)v=(vx,vy,vz),则点积的定义为:
u⋅v=uxvx+uyvy+uzvzu·v=u_xv_x+u_yv_y+u_zv_zu⋅v=uxvx+uyvy+uzvz
可见,点积就是向量间对应分类的乘积之和。
点积的定义并没有明显地体现出其几何意义。但是我们却能根据余弦定理找到向量点积的几何关系:
u⋅v=∣∣u∣∣∣∣v∣∣cosθ\qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad u·v=\mid \mid u \mid \mid \, \mid \mid v \mid \mid cos\thetau⋅v=∣∣u∣∣∣∣v∣∣cosθ
如果uuu与vvv是单位向量的话,那么有:
u⋅v=cosθ\qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad u·v=cos\thetau⋅v=cosθ
此时我们就能通过点积计算得到向量的夹角的余弦值,也就能得到夹角度数。
正交投影投影线垂直于投影面的投影。
正交化一个集合里的向量都与一向量正交,且这个集合的向量都为单位向量,那我们将此集合称为规范正交,而将普通向量集正交化为规范正交集的过程叫做正交化。而这个过程就要使用格拉姆——施密特正交化(Gram-Schmidt Orthogonalization)方法进行处理。规范化步骤:wi=wi∣∣wi∣∣w_i=\frac{w_i}{||w_i||}wi=∣∣wi∣∣wi。
叉积(亦称向量积、外积)是向量的第二种乘法形式。与计算结果为标量的点积不同,叉积的计算结果亦为向量。叉积的计算方法为:
w=u×v=(uyvz−uzvy,uzvx−uxvz,uxvy−uyvx)\qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad w=u×v=(u_yv_z-u_zv_y,u_zv_x-u_xv_z,u_xv_y-u_yv_x)w=u×v=(uyvz−uzvy,uzvx−uxvz,uxvy−uyvx)
若实际上采用的是左手坐标系,那么伸出左手,四指头伸直指向向量uuu,四指做握拳动作,四指弯曲的方向则是向量vvv的方向,那么此时,大拇指指向的方向则是向量www的方向。(注:如若此处用的是右手坐标系,那么用右手做同样操作即可),这个方法叫左手拇指法则,有的文献也称之为左手定则。
利用DirectXMath库对向量运算
DirectXMath使用环境
对于Windows8及其以上版本来讲,DirectXMath(其前身为XNA Math数据库,DirectXMath正是基于此而成)是一款Direct3D应用程序量身打造的3D数学库,而它也自此成为了WindowsSDK的一部分。该数据库采用了SIMD流指令扩展2(Streaming SIMD
Extensions2,SSE2)指令集。借助128位宽的单指令多数据(single instruction multiple data,SIMD)寄存器,利用一条指令SIMD指令即可同时对4个32位浮点数或整数进行运算。这对于向量运算带来的收益是不言而喻的。
为了使用DirectXMath库,我们需要添加头文件#include <DirectXMath.h>
,为了一些相关数据类型还需要加入头文件#include <DirectXPackedVector.h>
,除此之外并不需要其他库文件,因为所有的代码都以内联的方式是现在头文件里。DirectXMath.h文件中的代码都存于DirectX
命名空间中,DirectXPackedVector.h的代码则都位于DirectX::PackedVector
中。
另外对于x86平台,我们需要启用SSE2指令集(Project Properties(工程属性) > Configuration Properties(配置属性) >
C/C++ > Code Generation(代码生成) > Enable Enhanced Instruction Set(启用增强子令) )。
对于所有平台,我们还应当启用快速浮点模型/fp:fast (Project Properties(工程属性) >
Configuration Properties(配置属性) > C/C++ > Code Generation(代码生成) > Floating Point Model(浮点模型))。
对于x64平台来说,我们却不必开启SSE2指令集,这是因为所有的x64 CPU对此均有支持。
向量类型
DirectXMath中,核心向量时XMVECTOR,它将被映射到SIMD硬件寄存器中。通过SIMD指令的配合,利用这种具有128位的类型能一次性处理4个32位的浮点数。在开启SSE2后,此类型在x86和x64的定义是:
typedef __m128 XMVECTOR;
此处m128是特殊的SIMD类型(定义见xmmintrin.h)(采用联合的形式,这样用法的好处是可以同一段地址空间,做不同变量长度的字节数组使用)
typedef union __declspec(intrin_type) __declspec(align(16)) __m128 {float m128_f32[4];unsigned __int64 m128_u64[2];__int8 m128_i8[16];__int16 m128_i16[8];__int32 m128_i32[4];__int64 m128_i64[2];unsigned __int8 m128_u8[16];unsigned __int16 m128_u16[8];unsigned __int32 m128_u32[4];} __m128;
对于类中的数据成员建议分别使用XMFLOAT2(2D),XMFLOAT2(3D),XMFLOAT2(4D)
struct XMFLOAT2
{float x;
float y;
XMFLOAT2() {}
XMFLOAT2(float _x, float _y) : x(_x), y(_y) {}
explicit XMFLOAT2(_In_reads_(2) const float *pArray)
:
x(pArray[0]), y(pArray[1]) {}
XMFLOAT2& operator= (const XMFLOAT2& Float2)
{ x = Float2.x; y = Float2.y; return *this; }
};
struct XMFLOAT3
{float x;
float y;
float z;
XMFLOAT3() {}
XMFLOAT3(float _x, float _y, float _z) : x(_x),
y(_y), z(_z) {}
explicit XMFLOAT3(_In_reads_(3) const float *pArray)
:
x(pArray[0]), y(pArray[1]), z(pArray[2]) {}
XMFLOAT3& operator= (const XMFLOAT3& Float3)
{ x = Float3.x; y = Float3.y; z = Float3.z; return
*this; }
};
struct XMFLOAT4
{float x;
float y;
float z;
float w;
XMFLOAT4() {}
XMFLOAT4(float _x, float _y, float _z, float _w) :
x(_x), y(_y), z(_z), w(_w) {}
explicit XMFLOAT4(_In_reads_(4) const float *pArray)
:
x(pArray[0]), y(pArray[1]), z(pArray[2]),
w(pArray[3]) {}
XMFLOAT4& operator= (const XMFLOAT4& Float4)
{ x = Float4.x; y = Float4.y; z = Float4.z;
w = Float4.w; return *this; }
};
加载方法和存储方法
如果把上面的类型用于计算,却依然不能发挥SIMD技术的高效性,为此我们还需要将这些类型实例化转换为XMVECTOR
类型。转换过程可以通过DirectXMath
库的加载函数(loading function)实现。相反地,DirectXMath
库也提供了用来将XMVECTOR
类型转换为XMVECTn
类型的存储函数。(想了很久不清楚它这里为什么要分别用俩种类型互相转换,而不是直接用XMVECTOR
直接定义,我自己趋向的结果是类型明确,加上此程序开发者不关心其他类型的冗余数据,如果有什么官方解释,麻烦请留言,谢谢)。
用下面的方法将数据类型从XMFLOATn
类型加载到XMVECTOR
类型 :
XMVECTOR XM_CALLCONV XMLoadFloat2(const XMFLOAT2 *pSource);
XMVECTOR XM_CALLCONV XMLoadFloat3(const XMFLOAT3 *pSource);
XMVECTOR XM_CALLCONV XMLoadFloat4(const XMFLOAT4 *pSource);
用下面的方法将数据类型从XMVECTOR
类型存储到XMFLOATn
类型:
void XM_CALLCONV XMStoreFloat2(XMFLOAT2 *pDestination, FXVECTOR V);
void XM_CALLCONV XMStoreFloat3(XMFLOAT3 *pDestination, FXVECTOR V);
void XM_CALLCONV XMStoreFloat4(XMFLOAT4 *pDestination, FXVECTOR V);
当我们只期望从XMVECTOR
实例中得到某一向量分量或将某一向量转换为XMVECTOR
类型时,相关存取方法如下:
float XM_CALLCONV XMVectorGetX(FXMVECTOR V);
float XM_CALLCONV XMVectorGetY(FXMVECTOR V);
float XM_CALLCONV XMVectorGetZ(FXMVECTOR V);
float XM_CALLCONV XMVectorGetW(FXMVECTOR V);XMVECTOR XM_CALLCONV XMVectorSetX(FXMVECTOR V, float
x);
XMVECTOR XM_CALLCONV XMVectorSetY(FXMVECTOR V, float
y);
XMVECTOR XM_CALLCONV XMVectorSetZ(FXMVECTOR V, float
z);
XMVECTOR XM_CALLCONV XMVectorSetW(FXMVECTOR V, float
w);
参数传递
为了提高效率,可以将XMVECTOR
类型的值作为函数的参数,直接送至SSE/SSE2寄存器里,而不存于栈内。以此方式传递的参数数量取决于用户使用的平台和编译器。因此为了使代码更具通用性,不受具体平台、编译器的影响,我们将利用FXMVECTOR
、GXMVECTOR
、HXMECTOR
和CXMVECTOR
类型来传递XMVECTOR
类型的参数。基于特定的平台和编译器,它们会被自动地定义为适当的类型。
传递XMVECTOR
参数的规则如下:
在32位的Windows系统上,编译器将根据__vectorcall
调用约定将前3个,XMVECTOR参数传递到寄存器中,而把其余参数都存于栈上。
在64位的Windows系统上,编译器将根据__fastcall
调用约定将前6个,`XMVECTOR参数传递到寄存器中,而把其余参数都存于栈上。
前3个XMVECTOR
参数的类型都是应当用类型:FXMVECTOR
;
第4个XMVECTOR
参数应当用类型:GXMVECTOR
;
第5、6个XMVECTOR
参数应当用类型:HXMVECTOR
;
其余的XMVECTOR
参数应当用类型:CXMVECTOR
;
构造函数对于这些规则来说是个例外,在编写时,前三个XMVECTOR
参数用FXMVECTOR
类型,其余用CXMVECTOR
类型,另外对于构造函数,不要用XM_CALLCONV
注解。
下面是截取自DirectXMath
源码库:
inline XMMATRIX XM_CALLCONV XMMatrixTransformation(
FXMVECTOR ScalingOrigin,
FXMVECTOR ScalingOrientationQuaternion, .
FXMVECTOR Scaling,//第1~3个参数用FXMVECTOR
GXMVECTOR RotationOrigin,//第4个参数用GXMVECTOR
HXMVECTOR RotationQuaternion,
HXMVECTOR Translation);//5~6个参数用CXMVECTOR
当我们在这些参数之间掺杂其他不是XMVECTOR
参数类型,此规则依旧可用:
inline XMMATRIX XM_CALLCONV XMMatrixTransformation2D(
FXMVECTOR ScalingOrigin,
float ScalingOrientation,
FXMVECTOR Scaling,
FXMVECTOR RotationOrigin,
float Rotation,
GXMVECTOR Translation);//第4个XMVECTOR参数
传递XMVECTOR
参数的规则仅适用“输入”参数。“输出”的XMVECTOR
参数则不会占用SSE/SSE2寄存器,所以他们的处理方式与非XMVECTOR
类型的参数一致。
常向量
XMVECTOR
类型的惨了实例应当用XMVECTORF32
类型来表示。在DirectX SDK中就可以看到这种实例的运用:
static const XMVECTORF32 g_vHalfVector = { 0.5f, 0.5f,
0.5f, 0.5f };
static const XMVECTORF32 g_vZero = { 0.0f, 0.0f, 0.0f,
0.0f };
XMVECTORF32 vRightTop = {vViewFrust.RightSlope,
vViewFrust.TopSlope,
1.0f,1.0f
};
XMVECTORF32 vLeftBottom = {vViewFrust.LeftSlope,
vViewFrust.BottomSlope,
1.0f,1.0f
};
数学库中提供了将XMVECTORF32
转换成XMVECTOR
类型的运算符:
__declspec(align(16)) struct XMVECTORF32
{union
{float f[4];
XMVECTOR v;
};
inline operator XMVECTOR() const { return v; }
inline operator const float*() const { return f; }
#if !defined(_XM_NO_INTRINSICS_) &&
defined(_XM_SSE_INTRINSICS_)
inline operator __m128i() const { return
_mm_castps_si128(v); }
inline operator __m128d() const { return
_mm_castps_pd(v); }
#endif
};
另外,也可以通过XMVECTORU32类型来创建由整数数据结构构成的XMVECTOR常量:
static const XMVECTORU32 vGrabY = {0x00000000,0xFFFFFFFF,0x00000000,0x00000000
};
运算符重载
XMVECTOR类型针对于向量的加、减、标量乘、除,都分别提供了对应的重载运算符。
XMVECTOR XM_CALLCONV operator+ (FXMVECTOR V);
XMVECTOR XM_CALLCONV operator- (FXMVECTOR V);
XMVECTOR& XM_CALLCONV operator+= (XMVECTOR& V1,
FXMVECTOR V2);
XMVECTOR& XM_CALLCONV operator-= (XMVECTOR& V1,
FXMVECTOR V2);
XMVECTOR& XM_CALLCONV operator*= (XMVECTOR& V1,
FXMVECTOR V2);
XMVECTOR& XM_CALLCONV operator/= (XMVECTOR& V1,
FXMVECTOR V2);
XMVECTOR& operator*= (XMVECTOR& V, float S);
XMVECTOR& operator/= (XMVECTOR& V, float S);
XMVECTOR XM_CALLCONV operator+ (FXMVECTOR V1,
FXMVECTOR V2);
XMVECTOR XM_CALLCONV operator- (FXMVECTOR V1,
FXMVECTOR V2);
XMVECTOR XM_CALLCONV operator* (FXMVECTOR V1,
FXMVECTOR V2);
XMVECTOR XM_CALLCONV operator/ (FXMVECTOR V1,
FXMVECTOR V2);
XMVECTOR XM_CALLCONV operator* (FXMVECTOR V, float
S);
XMVECTOR XM_CALLCONV operator* (float S, FXMVECTOR
V);
XMVECTOR XM_CALLCONV operator/ (FXMVECTOR V, float
S);
杂项
DirectXMath库定义了一组与π\piπ有关的常用常量近似值:
const float XM_PI = 3.141592654f;
const float XM_2PI = 6.283185307f;
const float XM_1DIVPI = 0.318309886f;
const float XM_1DIV2PI = 0.159154943f;
const float XM_PIDIV2 = 1.570796327f;
const float XM_PIDIV4 = 0.785398163f;
另外,它用下列内联函数实现了弧度和角度间的互相转化:
inline float XMConvertToRadians(float fDegrees)
{ return fDegrees * (XM_PI / 180.0f); }
inline float XMConvertToDegrees(float fRadians)
{ return fRadians * (180.0f / XM_PI); }
DirectXMath库还定义了求出俩个数间较大值及较小值的函数:
template<class T> inline T XMMin(T a, T b) { return (a
< b) ? a : b; }
template<class T> inline T XMMax(T a, T b) { return (a
> b) ? a : b; }
Setter函数
DirectXMath库提供了下列函数,以设置XMVECTOR类型中的数据:
// Returns the zero vector 0
XMVECTOR XM_CALLCONV XMVectorZero();
// Returns the vector (1, 1, 1, 1)
XMVECTOR XM_CALLCONV XMVectorSplatOne();
// Returns the vector (x, y, z, w)
XMVECTOR XM_CALLCONV XMVectorSet(float x, float y,
float z, float w);
// Returns the vector (s, s, s, s)
XMVECTOR XM_CALLCONV XMVectorReplicate(float Value);
// Returns the vector (vx, vx, vx, vx)
XMVECTOR XM_CALLCONV XMVectorSplatX(FXMVECTOR V);
// Returns the vector (vy, vy, vy, vy)
XMVECTOR XM_CALLCONV XMVectorSplatY(FXMVECTOR V);
// Returns the vector (vz, vz, vz, vz)
XMVECTOR XM_CALLCONV XMVectorSplatZ(FXMVECTOR V);
实例程序:
#include <windows.h> //
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include
using namespace std;
using namespace DirectX;
using namespace DirectX::PackedVector;
//重载运算符<<,这样就可以通过Cout函数输出XMVECTOR对象
ostream& XM_CALLCONV operator<<(ostream& os, FXMVECTOR v)
{XMFLOAT3 dest;XMStoreFloat3(&dest, v);os << "(" << dest.x << ", " << dest.y << ", " <<dest.z << ")";return os;
}
int main()
{cout.setf(ios_base::boolalpha);//检查是否支持SSE2指令集(Pentium4,AMD K8及后续版本的处理器)if (!XMVerifyCPUSupport()){cout << "directx math not supported" << endl;return 0;}XMVECTOR p = XMVectorZero();XMVECTOR q = XMVectorSplatOne();XMVECTOR u = XMVectorSet(1.0f, 2.0f, 3.0f, 0.0f);XMVECTOR v = XMVectorReplicate(-2.0f);XMVECTOR w = XMVectorSplatZ(u);cout << "p = " << p << endl;cout << "q = " << q << endl;cout << "u = " << u << endl;cout << "v = " << v << endl;cout << "w = " << w << endl;return 0;
}
运行结果:
向量函数
DirectXMath库提供了下面的函数来执行向量的各种运算,类似的有2D、3D、4D,下面的就是3D的部分函数。
XMVECTOR XM_CALLCONV XMVector3Length(FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVector3LengthSq(FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVector3Dot(FXMVECTOR V1,FXMVECTOR V2);
XMVECTOR XM_CALLCONV XMVector3Cross(FXMVECTOR V1,FXMVECTOR V2);
XMVECTOR XM_CALLCONV XMVector3Normalize(FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVector3Orthogonal(FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVector3AngleBetweenVectors(FXMVECTOR V1,FXMVECTOR V2);
void XM_CALLCONV XMVector3ComponentsFromNormal(XMVECTOR* pParallel,XMVECTOR* pPerpendicular,FXMVECTOR V,FXMVECTOR Normal);
bool XM_CALLCONV XMVector3Equal(FXMVECTOR V1,FXMVECTOR V2);
bool XM_CALLCONV XMVector3NotEqual(FXMVECTOR V1,FXMVECTOR V2);
下面Demo演示一些函数与重载的使用:
#include <windows.h> // for XMVerifyCPUSupport
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <iostream>
using namespace std;
using namespace DirectX;
using namespace DirectX::PackedVector;ostream& XM_CALLCONV operator<<(ostream& os, FXMVECTORv)
{XMFLOAT3 dest;XMStoreFloat3(&dest, v);os << "(" << dest.x << ", " << dest.y << ", " <<dest.z << ")";return os;
}
int main()
{cout.setf(ios_base::boolalpha);if (!XMVerifyCPUSupport()){cout << "directx math not supported" << endl;return 0;}XMVECTOR n = XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f);XMVECTOR u = XMVectorSet(1.0f, 2.0f, 3.0f, 0.0f);XMVECTOR v = XMVectorSet(-2.0f, 1.0f, -3.0f, 0.0f);XMVECTOR w = XMVectorSet(0.707f, 0.707f, 0.0f,0.0f);XMVECTOR a = u + v;XMVECTOR b = u - v;XMVECTOR c = 10.0f * u;XMVECTOR L = XMVector3Length(u);XMVECTOR d = XMVector3Normalize(u);XMVECTOR s = XMVector3Dot(u, v);XMVECTOR e = XMVector3Cross(u, v);XMVECTOR projW;XMVECTOR perpW;XMVector3ComponentsFromNormal(&projW, &perpW, w, n);bool equal = XMVector3Equal(projW + perpW, w) != 0;bool notEqual = XMVector3NotEqual(projW + perpW, w)!= 0;XMVECTORangleVec = XMVector3AngleBetweenVectors(projW, perpW);float angleRadians = XMVectorGetX(angleVec);floatangleDegrees = XMConvertToDegrees(angleRadians);cout << "u = " << u << endl;cout << "v = " << v << endl;cout << "w = " << w << endl;cout << "n = " << n << endl;cout << "a = u + v = " << a << endl;cout << "b = u - v = " << b << endl;cout << "c = 10 * u = " << c << endl;cout << "d = u / ||u || = " << d << endl;cout << "e = u x v = " << e << endl;cout << "L = || u || = " << L << endl;cout << "s = u.v = " << s << endl;cout << "projW = " << projW << endl;cout << "perpW = " << perpW << endl;cout << "projW + perpW == w = " << equal << endl;cout << "projW + perpW != w = " << notEqual << endl;cout << "angle = " << angleDegrees << endl;return 0;
}
运行结果如下:
浮点数误差
在用计算机处理向量有关工作时,我们应当了解以下工作内容,在比较浮点数时,一定要注意浮点数存在误差。我们认为相等的俩个浮点数可能会因此有细微的差别。例如,已知在数学上规范化向量长度为1,但是在计算机程序中的表达上,向量的长度只能接近于1。此外,在数学中,对于任意实数ppp有1p=11^p=11p=1。但是,当只能在数值上逼近1时,随着幂ppp的增加,所求近似值的误差也在逐渐增大,由此可见,数值误差时可以积累的。下面这个小程序可以印证这些观点:
#include <windows.h>
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <iostream>
using namespace std;
using namespace DirectX;
using namespace DirectX::PackedVector;
int main()
{cout.precision(8);//检查是否支持SSE2指令集(Pentium4,AMD K8以及其后续版本的处理器)if (!XMVerifyCPUSupport()){cout << "directx math not supported" << endl;return 0;}XMVECTOR u = XMVectorSet(1.0f, 1.0f, 1.0f, 0.0f);XMVECTOR n = XMVector3Normalize(u);float LU = XMVectorGetX(XMVector3Length(n));cout << LU << endl;if (LU == 1.0f)//在数学上,此向量的长度应当为1.cout << "Length 1" << endl;elsecout << "Length not 1" << endl;float powLU = powf(LU, 1.0e6f);cout << "LU ^ (10 ^ 6) = " << powLU << endl;
}
运算结果:
因此为了弥补浮点数精确性上的不足,我们通过比较俩个浮点数是否近似相等来加以解决。在比较的时候,我们需要定义一个Epsilon
常量,我们就说这俩个数是近似相等的。换句话说,Epsilon
是针对浮点数的误差问题所指定的容差。下面函数解释了如何利用Epsilon
来检测俩个浮点数是否相等:
const float Epsilon = 0.001f;
bool Equals(float lhs, float rhs)
{//lhs与rhs的相差值是否小于EPSILON?
return fabs(lhs - rhs) < Epsilon ? true : false;
}
对此,DirectXMath库提供了XMVector3NearEqual
函数,用于以Epsilon
作为容差,测试比较的向量是否相等:
// Returns
// abs(U.x – V.x) <= Epsilon.x &&
// abs(U.y – V.y) <= Epsilon.y &&
// abs(U.z – V.z) <= Epsilon.z
XMFINLINE bool XM_CALLCONV XMVector3NearEqual(
FXMVECTOR U,
FXMVECTOR V,
FXMVECTOR Epsilon);
DirectX12 3D游戏开发实践(龙书)第一章 向量代数相关推荐
- DirectX 12 3D游戏开发实战 -- 龙书随书源码各章项目运行结果概览
DirectX 12 3D游戏开发实战 -- 龙书随书源码各章项目运行结果概览 第1章 向量运算 第2章 矩阵运算 第4章 Direct3D初始化 第6章 利用Direct3D绘制几何体Box 第7章 ...
- DirectX12 3D游戏开发实践(龙书)第四章 Direct3D的初始化
目录 Direct3D的初始化 预备知识 Direct3D概述 组件对象模型 纹理格式(Textures Formats) 交换链和页面翻转 深度缓冲 资源与描述符 多重采样技术的原理 利用Direc ...
- DirectX12 3D游戏开发实践(龙书)第五章 渲染流水线
渲染流水线 渲染流水线 3D视觉即错觉? 模型表示 计算机色彩基础 颜色运算 不透明度 XXX位颜色 渲染流水线概述 输入装配器阶段 顶点 图元拓扑 点列表 线条带 线列表 三角形带 三角形列表 具有 ...
- DirectX12 3D游戏开发实践(龙书)第二章_矩阵代数
矩阵 第二章矩阵代数 矩阵代数 定义 矩阵运算 简单代数运算 矩阵乘法 定义 向量与矩阵的乘法 结合律 转置矩阵 单位矩阵 矩阵的行列式 余子阵 行列式的定义 伴随矩阵 逆矩阵 用DirectXMat ...
- DirectX12 3D 游戏开发与实战第四章内容(上)
Direct3D的初始化(上) 学习目标 了解Direct3D在3D编程中相对于硬件所扮演的角色 理解组件对象模型COM在Direct3D中的作用 掌握基础的图像学概念,例如2D图像的存储方式,页面翻 ...
- 《DirectX 9.0 3D游戏开发编程基础》 第一章 初始化Direct3D 读书笔记
REF设备 参考光栅设备,他能以软件计算方式完全支持Direct3D Api.借助Ref设备,可以在代码中使用那些不为当前硬件所支持的特性,并对这此特性进行测试. D3DDEVTYPE 在程序代码中, ...
- [3D游戏开发实践] Cocos Cyberpunk 源码解读-高中低端机性能适配策略
Cocos Cyberpunk 是 Cocos 引擎官方团队以展示引擎重度 3D 游戏制作能力,提升社区学习动力而推出的完整开源 TPS 3D游戏,支持 Web, IOS, Android 多端发布. ...
- [3D游戏开发实践] Cocos Cyberpunk 源码解读-一文搞定延迟渲染管线原理与实践
Cocos Cyberpunk 是 Cocos 引擎官方团队以展示引擎重度 3D 游戏制作能力,提升社区学习动力而推出的完整开源 TPS 3D游戏,支持 Web, IOS, Android 多端发布. ...
- DirectX 12 3D 游戏开发与实战第五章内容
渲染流水线 学习目标: 了解用于在2D图像中表现出场景立体感和空间深度感等真实效果的关键因素 探索如何用Direct3D表示3D对象 学习如何建立虚拟摄像机 理解渲染流水线,根据给定的3D场景的几何描 ...
最新文章
- 第五周项目一-三角形类雏形(2)
- Windows Server 2008 RemoteApp(四)---发布应用程序
- 白话Elasticsearch54-数据建模之通过【应用层join】或者【数据冗余】实现实现用户与博客的关联
- Lambda表达式的使用
- C语言 | 变量的存储方式
- Android开发环境(IDE)
- flume简介(大数据技术)
- lc filter在matlab哪,基于python实现matlab filter函数过程详解
- 10976 - Fractions Again?!
- Windows phone 7 之ToggleSwitch
- onSaveInstanceState() 和 onRestoreInstanceState()
- 从零开始学前端:CSS复合选择器 --- 今天你学习了吗?(CSS:Day10)
- php-china,php对chinapay的支持
- 刷 携程 地面业务 前端面试经历
- MEF程序设计指南四:使用MEF声明导出(Exports)与导入(Imports)
- java native2ascii的用法介绍
- route命令实现内外网切换
- 利用拉格朗日中值定理求极限
- 3dB带宽的简要解释
- 浅谈android应用之编程语言
热门文章
- ERROR: cannot launch node of type [robot_state_publisher/state_publisher]解决办法
- Oracle函数练习题
- 推荐一个不错的学术资源论坛
- [转]SQL Server 2008存储结构之GAM、SGAM
- 复制帧数据到内存空间
- 名编辑电子杂志大师教程 | 如何制作手机版电子杂志
- 12款开源数据资产(元数据)管理平台选型分析(一)
- 项目上线那些事之Can't connect to X11 window server异常
- Golang淘宝开放平台Api请求基础SDK
- MySQL WorkBench 8.0 菜单汉化