问题4-Textrue

ncopy.gif

下面是关于D3D贴图的内容。问题很简单,就是给一个去除了上下面的立方体的内外贴图。

问题描述:

在一个窗口中显示一个没有上下底面的立方体,并且用8张图给立方体内部的4个面和外部的4个面贴图,并且让立方体保持旋转。

Textrue.jpg

首先,要用VertexBuffer和IndexBuffer建立一个没有上下底面的立方体,因为要使用贴图,贴图要使用贴图坐标,所以这里我们的Vertex结构体要修改,要加入贴图坐标(u,v),下面的图表示了一个贴图坐标。

Textrue_coordinate.jpg

然后修改我们的结构体:

struct Vertex
{
Vertex(){}
Vertex(
float x, float y, float z,
float nx, float ny, float nz,
float u, float v)
{
_x = x; _y = y; _z = z;
_nx = nx; _ny = ny; _nz = nz;
_u = u; _v = v;
}
float _x, _y, _z;
float _nx, _ny, _nz;
float _u, _v; // texture coordinates};
#define FVF_VERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)


要使用贴图,就还要使用D3DFVF_TEX1。

使用上面的结构构造好立方体后,就可以开始贴图了。可以使用LPDIRECT3DTEXTURE9创建一个结构体。这里要贴8张图片,所以可以创建一个数组。

LPDIRECT3DTEXTURE9* tex = NULL;
tex = new LPDIRECT3DTEXTURE9[8];


然后再使用D3DXCreateTextureFromFile载入要贴图的图片

D3DXCreateTextureFromFile(_device,L"img\\banana1.bmp",&tex[0]);

第一个参数是设备对象,第二个参数是图片的路径,第三个参数就是刚才创建的LPDIRECT3DTEXTURE9数组。

最后显示贴图的时候使用SetTexture,要一个面一个面的分别显示

_device->SetTexture(0, tex[0]);
_device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 6, 0,2);


这样一直把立方体的内外8个面完成为止。

可能有同学不知道在立方体的内部怎么贴图,其实很简单,由于我们要贴8个图,所以我们要创建48个IndexBuffer ,24个在外面,24个在里面,在外面的24个我们用顺时针顺序,里面的24个只要使用反时针的顺序就可以了。比如

//外面的一面
i[0] = 0; i[1] = 1; i[2] = 2;
i[3] = 0; i[4] = 2; i[5] = 3;


//里面的一面
i[24] = 2; i[25] = 1; i[26] = 0;
i[27] = 3; i[28] = 2; i[29] = 0;


最后也要记住使用了LPDIRECT3DTEXTURE9后要释放资源。

*原创内容,转载请注明出处*


问题3-D3D Lighting

ncopy.gif

今天要学习的是dx中的光照。

问题描述:

在一个窗口中显示5个物体,在黑暗的环境中分别用点光源,直线光源,聚光源照射物体,并且照射光源每隔1秒自动变换,物体的颜色也每隔1秒自己随机变换颜色。

Lighting.jpg



DX9供给我们三种光源:点光源(PointLight),直线光源(DirectionalLight)和聚光源(SpotLight)。点光源就是像是太阳一样,在空间一点像各个方向射出光线;直线光源就是从一个方向往另一个方向照射的光;聚光源就像一个手电筒射出的光一样。

首先,在头文件里不仅要想上次一样定义颜色,还要定义材质(Material),和光源。定义材质是为了让物体有颜色。光源可以用D3DLIGHT9这个结构体来定义,材质可以使用D3DMATERIAL9这个结构体来定义。我们来先看看这2个结构体是如何构造的,先看看D3DLIGHT9的结构

typedef struct _D3DLIGHT9 {
D3DLIGHTTYPE Type; 
/*光源类型*/
D3DCOLORVALUE Diffuse;
/* 漫射光的颜色*/
D3DCOLORVALUE Specular;
/* 镜面放射光的颜色 */
D3DCOLORVALUE Ambient;
/* 环境光的颜色*/
D3DVECTOR Position;
/* 光源位置,对于直线光源来说没有意义*/
D3DVECTOR Direction;
/* 光源照射方向,对于点光源来说没有意义*/
float Range;
/* 光照射的距离,对于直线光源来说没有意义*/
float Falloff;
/* 只用来聚光源,决定聚光源圆锥形光照范围内外的强度差异,一般设置为0.1f */
float Attenuation0;
float Attenuation1;
float Attenuation2;
/*这三个主要是决定光强度的衰减程度,对于直线光源没有意义*/
float Theta;
/* 指定聚光源内圆锥形的角度*/
float Phi;
/* 指定聚光源外圆锥形的角度*/
} D3DLIGHT9;


这就是D3DLIGHT9 的结构,里面的内容很多,实际用的时候并没有这么复杂。下面是D3DMATERIAL9结构体。

typedef struct _D3DMATERIAL9 {
D3DCOLORVALUE Diffuse;
/* 漫反射光*/
D3DCOLORVALUE Ambient;
/* 环境光*/
D3DCOLORVALUE Specular;
/* 镜面反射光*/
D3DCOLORVALUE Emissive;
/* 是使物体自身放光的参数*/
float Power;
/* 镜面反射的尖锐程度*/
} D3DMATERIAL9;


这就是D3DMATERIAL9的结构,看起来要比D3DLIGHT9要简单得多。

颜色,材质,光源定义好后,就可以使用了。

Device->SetLight(0, &Light);

这里Light就是上面的D3DLIGHT9定义的结构体。使用的时候一定要打开光照:

Device->LightEnable(0, true);

设置物体材质:

Device->SetMaterial(&Mtrls);

这里Mtrls就是上面的D3DMATERIAL9定义的结构体。

光照设置过程大概就是这样的。下面说一下程序里要求的每隔1秒变换光源。其实就是定义一个Timer,在c++中,Timer是被回调函数回调的,所以Timer要写成回调函数的形式。

void CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime)
{
//这里是操作代码}


调用的时候:

SetTimer(0,1,1000,TimerProc);

第一个参数是窗口句柄,第二个参数是Timer的序号,第三个参数是时间间隔,最后一个参数是回调函数。

时间间隔的问题解决了,剩下就是随机变换颜色的问题了。当然就要使用随机数的函数。为了不让每次取得的随机数相同,所以还要设置随机数种子,一般都是用系统时间来作为种子。

设置随机种子:

srand((unsigned)time(NULL));

time是取得系统时间。然后用rand()函数就可以取得随机数了。我们把材质结构体可以用一个数组的形式表示,然后用随机数来作为数组的下标就可以完成随机变换颜色的功能了。但是rand()取得随机数没有范围,所以我们还要给它设置个范围。在MSDN上查了一圈,发现了个公式:

(double)rand() / (RAND_MAX + 1) * (range_max - range_min)+ range_min;

这个公式用来返回有范围的随机数。这里RAND_MAX是个系统定义的宏,我们可以不去管它,range_max和range_min分别对应我们想要的范围的最大值和最小值。这样我们的功能就都可以实现了。

*原创内容,转载请注明出处。*


问题2-D3D Color

ncopy.gif


这次是学习DX中对颜色的处理。使用ColorVertex这种结构体保存带有染色的顶点,然后对物体进行渲染。

问题描述:

在窗口中显示两个立方体,其中一个使用D3DSHADE_GOURAUD渲染模式,一个使用D3DSHADE_FLAT渲染模式;并且使两个立方体各自绕X,Y,Z轴自转的同时,两个立方体同时绕Y轴公转。

color.jpg

为了要使用带颜色的定点,我们可以先在头文件里定义颜色常量,

const D3DXCOLOR WHITE( D3DCOLOR_XRGB(255, 255, 255) );
const D3DXCOLOR BLACK( D3DCOLOR_XRGB( 0, 0, 0) );


可以像这样定义自己想要的颜色。然后定义带颜色的顶点:

struct ColorVertex
{
ColorVertex(){}
ColorVertex(float x,float y,float z,D3DCOLOR c)
{
_x = x;
_y = y;
_z = z;
_color = c;
}
float _x,_y,_z;
D3DCOLOR _color;
static const DWORD FVF;
};
const DWORD ColorVertex::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;


这里的结构和不带颜色的定点结构是一样的,只不过就多了一个color参数。这种定点的结构也可以当成公式一样记忆下来。要画出一个立方体,我们这里要使用设备的CreateVertexBuffer和CreateIndexBuffer,这里要注意一点,一个立方体有8个顶点,所以我们的顶点数是8,但是index的话,就有36个了,立方体是6个面,一个面是6个index,因为在画每一个面的时候,是用2个三角形组合而成的,每个三角形都要用3个index,在一个四边形中画条对角线,就可以知道了,2个三角形,虽然2个顶点是一样的,但是还是要算在总数里面,所以6×6就是36个index。

Device->CreateVertexBuffer(
8 * sizeof(ColorVertex),
D3DUSAGE_WRITEONLY,
ColorVertex::FVF,
D3DPOOL_MANAGED,
&VB,
0);
ColorVertex* v;

VB->Lock(0,0,(void**)&v,0);

v[0] = ColorVertex(-1.0f, -1.0f, -1.0f, d3d::BLUE);
v[1] = ColorVertex(-1.0f, 1.0f, -1.0f, d3d::PURPLE);
v[2] = ColorVertex( 1.0f, 1.0f, -1.0f, d3d::RED);
v[3] = ColorVertex( 1.0f, -1.0f, -1.0f, d3d::MAGENTA);
v[4] = ColorVertex(-1.0f, -1.0f, 1.0f, d3d::CYAN);
v[5] = ColorVertex(-1.0f, 1.0f, 1.0f, d3d::GREEN);
v[6] = ColorVertex( 1.0f, 1.0f, 1.0f, d3d::YELLOW);
v[7] = ColorVertex( 1.0f, -1.0f, 1.0f, d3d::WHITE);

VB->Unlock();


Device->CreateIndexBuffer(
36 * sizeof(WORD),
D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&IB,
0);

WORD* indices = 0;
IB->Lock(0, 0, (void**)&indices, 0);

// front side
indices[0] = 0; indices[1] = 1; indices[2] = 2;
indices[3] = 0; indices[4] = 2; indices[5] = 3;

// back side
indices[6] = 4; indices[7] = 6; indices[8] = 5;
indices[9] = 4; indices[10] = 7; indices[11] = 6;

// left side
indices[12] = 4; indices[13] = 5; indices[14] = 1;
indices[15] = 4; indices[16] = 1; indices[17] = 0;

// right side
indices[18] = 3; indices[19] = 2; indices[20] = 6;
indices[21] = 3; indices[22] = 6; indices[23] = 7;

// top
indices[24] = 1; indices[25] = 5; indices[26] = 6;
indices[27] = 1; indices[28] = 6; indices[29] = 2;

// bottom
indices[30] = 4; indices[31] = 0; indices[32] = 3;
indices[33] = 4; indices[34] = 3; indices[35] = 7;

IB->Unlock();


上面的代码就是分别设置顶点缓冲和index缓冲,VB,IB分别是

IDirect3DVertexBuffer9* VB = 0;
IDirect3DIndexBuffer9* IB = 0;


在设置顶点和index前一定要调用Lock方法,在设置完成后也一定要Unlock。还有一点要注意的地方,就是在设置index的时候,顺序是有讲究的,也就是说所有三角形(也就是indices[0] = 0; indices[1] = 1; indices[2] = 2;这里决定的三角形)画线的方向必须一致。也就是说所有三角形都是顺时针方向或都是反时针方向。

立方体画好了后,就要设置它的旋转了。上篇文章中已经讲了绕轴自转的方法。这里主要说一下公转的方法。其实公转和简单,我之前也搞不懂,想了很久,在网上问了很多朋友,还是没有解决,最后在一次不经意的测试中发现了公转的秘密。呵呵~

前面说过了,让物体在替他坐标点自转,需要用平移向量点乘旋转向量,而且要注意方向,也就是平移向量要放在前面,如果这2个顺序换一下,把旋转向量放在前面,会出现什么结果呢??答案正是我们想要的公转!所以这里我们只需要交换点乘前后参数的位子就可以了。比如:

D3DXMatrixMultiply(&Position1,&Position1, &Ry);

这样就可以让物体绕Y轴公转,公转后再让物体自转就可以到达我们的要求了。

最后在窗口中显示物体(当然设定投影和摄像机这里省略了):

Device->SetStreamSource(0, VB, 0, sizeof(ColorVertex));
Device->SetIndices(IB);
Device->SetFVF(ColorVertex::FVF);

Device->SetTransform(D3DTS_WORLD,&Position1);
Device->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_GOURAUD);
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);


要显示另一个立方体,再使用后面三句就可以了,不过要改变显示的坐标哦。程序完成后,就可以看到2种不同渲染方法的差别了。

*原创文章,转载请注明出处*

问题1-D3D Drawing

ncopy.gif
  

开学了,一切要学习的东西对于我来说都很新鲜。这个程序是从来没有接触过游戏开发的我的第一个程序,也是我人生中的第一个D3D程序,对我来说很有意义。也许对于有的朋友来说,这个程序很简单。但我仍然把它发出来,希望对学习游戏开发的新朋友有所帮助。

问题描述:
  
  在窗口中显示下面的五个图形,并且用X,Y,Z,R,L键分别控制图形绕X,Y,Z轴顺时针和反时针旋转。

d3ddrawing

  建立Win32窗口和D3D初始化的方法都比较简单和机械化,网上这方面的文章也很多,希望不知道的朋友自己找找资料来看,这里就不详细的说了。这里主要说下绕轴旋转和旋转的控制。
  
  对于一个物体要让它在原点,也就是世界坐标的(0,0,0)点旋转的话很简单,直接使用dx给我们提供的:

D3DXMatrixRotationX( D3DXMATRIX *pOut, FLOAT Angle );
D3DXMatrixRotationY( D3DXMATRIX *pOut, FLOAT Angle );
D3DXMatrixRotationZ( D3DXMATRIX *pOut, FLOAT Angle );


这个三只方法即可。这里第一个参数是要保存的旋转举列,第二个参数是旋转的角度。要想使物体不停的旋转的话,只要把这段代码放到消息循环中就可以了。如果要想让物体在不同的地方自转(公转的情况下个章节会讲),我们首先把五个物体要移动到希望的坐标点上,这里可以平移矩阵,使用:

D3DXMatrixTranslation( D3DXMATRIX *pOut, FLOAT x, FLOAT y, FLOAT z );

同样第一个参数是移动后保存的平移矩阵,后面三个参数就是希望移动的坐标。移动后,我在让它旋转。这里要注意,如果是直接先移动了,再直接旋转是达不到想要的效果的,必须要进行矩阵的内积,也就是点乘。什么和什么相乘呢?就是前面说的用旋转矩阵和平移矩阵相点乘。然后把结果再保存到平移矩阵中。矩阵求内积可以使用:

D3DXMatrixMultiply( D3DXMATRIX *pOut, CONST D3DXMATRIX *pM1, CONST D3DXMATRIX *pM2 );

这个方法。看个例子,比如说要把一个图形放在点(5,5,5)绕X轴旋转:

D3DXMatrixTranslation( &ObjWorldPosition, 5.0f, 5.0f, 5.0f);//平移到点(5,5,5)
D3DXMatrixRotationX( &Rx, timeDelta); 
//timeDelta是旋转角度,在消息循环中不停的改变这个值就可以使物体不停的旋转
D3DXMatrixMultiply( &ObjWorldPosition, &Rx, &ObjWorldPosition); //点乘

最后再把物体显示到世界坐标中:

Device->SetTransform(D3DTS_WORLD,&ObjWorldPosition);

这样就完成了物体平移并且旋转的功能。如果要使物体同时绕多个轴旋转,只需要在点乘的时候,乘以需要旋转的旋转矩阵就可以了。但是要注意点乘的方向,因为矩阵的乘法是不满足交换率的。在这里,平移矩阵和旋转矩阵点乘的时候,一定要把旋转放在前面,如果放在后面,物体不会自转。

*原创文章,转载请注明出处*




自我介绍

Author:三只熊熊
大家好,欢迎来到我的blog!
目前我正在韩国攻读游戏工学研究生,现在在虚拟现实实验室。
作为刚踏入游戏开发领域的初学者,希望大家多多帮助!

잘 부탁드립니다~ ^_^

最新文章
最新留言
最新引用
月份存档
类别
计数器
搜寻栏
RSS连结
连结
Powered By FC2博客

马上开始博客吧!!

Powered By FC2博客