向量

  • 第一章 向量代数
    • 向量与坐标系
      • 定义
      • 坐标系
      • 向量的基本运算
      • 利用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=ux​vx​+uy​vy​+uz​vz​
可见,点积就是向量间对应分类的乘积之和。

点积的定义并没有明显地体现出其几何意义。但是我们却能根据余弦定理找到向量点积的几何关系:
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=(uy​vz​−uz​vy​,uz​vx​−ux​vz​,ux​vy​−uy​vx​)
若实际上采用的是左手坐标系,那么伸出左手,四指头伸直指向向量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寄存器里,而不存于栈内。以此方式传递的参数数量取决于用户使用的平台和编译器。因此为了使代码更具通用性,不受具体平台、编译器的影响,我们将利用FXMVECTORGXMVECTORHXMECTORCXMVECTOR类型来传递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游戏开发实践(龙书)第一章 向量代数相关推荐

  1. DirectX 12 3D游戏开发实战 -- 龙书随书源码各章项目运行结果概览

    DirectX 12 3D游戏开发实战 -- 龙书随书源码各章项目运行结果概览 第1章 向量运算 第2章 矩阵运算 第4章 Direct3D初始化 第6章 利用Direct3D绘制几何体Box 第7章 ...

  2. DirectX12 3D游戏开发实践(龙书)第四章 Direct3D的初始化

    目录 Direct3D的初始化 预备知识 Direct3D概述 组件对象模型 纹理格式(Textures Formats) 交换链和页面翻转 深度缓冲 资源与描述符 多重采样技术的原理 利用Direc ...

  3. DirectX12 3D游戏开发实践(龙书)第五章 渲染流水线

    渲染流水线 渲染流水线 3D视觉即错觉? 模型表示 计算机色彩基础 颜色运算 不透明度 XXX位颜色 渲染流水线概述 输入装配器阶段 顶点 图元拓扑 点列表 线条带 线列表 三角形带 三角形列表 具有 ...

  4. DirectX12 3D游戏开发实践(龙书)第二章_矩阵代数

    矩阵 第二章矩阵代数 矩阵代数 定义 矩阵运算 简单代数运算 矩阵乘法 定义 向量与矩阵的乘法 结合律 转置矩阵 单位矩阵 矩阵的行列式 余子阵 行列式的定义 伴随矩阵 逆矩阵 用DirectXMat ...

  5. DirectX12 3D 游戏开发与实战第四章内容(上)

    Direct3D的初始化(上) 学习目标 了解Direct3D在3D编程中相对于硬件所扮演的角色 理解组件对象模型COM在Direct3D中的作用 掌握基础的图像学概念,例如2D图像的存储方式,页面翻 ...

  6. 《DirectX 9.0 3D游戏开发编程基础》 第一章 初始化Direct3D 读书笔记

    REF设备 参考光栅设备,他能以软件计算方式完全支持Direct3D Api.借助Ref设备,可以在代码中使用那些不为当前硬件所支持的特性,并对这此特性进行测试. D3DDEVTYPE 在程序代码中, ...

  7. [3D游戏开发实践] Cocos Cyberpunk 源码解读-高中低端机性能适配策略

    Cocos Cyberpunk 是 Cocos 引擎官方团队以展示引擎重度 3D 游戏制作能力,提升社区学习动力而推出的完整开源 TPS 3D游戏,支持 Web, IOS, Android 多端发布. ...

  8. [3D游戏开发实践] Cocos Cyberpunk 源码解读-一文搞定延迟渲染管线原理与实践

    Cocos Cyberpunk 是 Cocos 引擎官方团队以展示引擎重度 3D 游戏制作能力,提升社区学习动力而推出的完整开源 TPS 3D游戏,支持 Web, IOS, Android 多端发布. ...

  9. DirectX 12 3D 游戏开发与实战第五章内容

    渲染流水线 学习目标: 了解用于在2D图像中表现出场景立体感和空间深度感等真实效果的关键因素 探索如何用Direct3D表示3D对象 学习如何建立虚拟摄像机 理解渲染流水线,根据给定的3D场景的几何描 ...

最新文章

  1. 第五周项目一-三角形类雏形(2)
  2. Windows Server 2008 RemoteApp(四)---发布应用程序
  3. 白话Elasticsearch54-数据建模之通过【应用层join】或者【数据冗余】实现实现用户与博客的关联
  4. Lambda表达式的使用
  5. C语言 | 变量的存储方式
  6. Android开发环境(IDE)
  7. flume简介(大数据技术)
  8. lc filter在matlab哪,基于python实现matlab filter函数过程详解
  9. 10976 - Fractions Again?!
  10. Windows phone 7 之ToggleSwitch
  11. onSaveInstanceState() 和 onRestoreInstanceState()
  12. 从零开始学前端:CSS复合选择器 --- 今天你学习了吗?(CSS:Day10)
  13. php-china,php对chinapay的支持
  14. 刷 携程 地面业务 前端面试经历
  15. MEF程序设计指南四:使用MEF声明导出(Exports)与导入(Imports)
  16. java native2ascii的用法介绍
  17. route命令实现内外网切换
  18. 利用拉格朗日中值定理求极限
  19. 3dB带宽的简要解释
  20. 浅谈android应用之编程语言

热门文章

  1. ERROR: cannot launch node of type [robot_state_publisher/state_publisher]解决办法
  2. Oracle函数练习题
  3. 推荐一个不错的学术资源论坛
  4. [转]SQL Server 2008存储结构之GAM、SGAM
  5. 复制帧数据到内存空间
  6. 名编辑电子杂志大师教程 | 如何制作手机版电子杂志
  7. 12款开源数据资产(元数据)管理平台选型分析(一)
  8. 项目上线那些事之Can't connect to X11 window server异常
  9. Golang淘宝开放平台Api请求基础SDK
  10. MySQL WorkBench 8.0 菜单汉化