第五十七章 试着制作3D背景吧(1)
DX Library是2D专用的库。
然而也有唯一一个能够使用3D的函数。
(译者注:DX Library目前已经完全支持3D,以上两句话已经被原作者撤销掉。)
(→DX Library从ver3开始,已经完全对应3D了。现在我们制作3D程序已经可以不用使用这么复杂的手段了。)
这就是 DrawPolygon3D这个函数。(关于这个函数的使用,请尽量先通过链接阅读一下DX Library参考手册(Reference))。
使用这个函数,用DX Library也来模拟出3D背景吧!——这就是本章的主题。
另外,这一次我们也使用新的工程。如果您是自行准备工程的话,请把已经57章的“mydat/img”下的图像给拷到已经准备好的工程中。
那么,现在我就想进入3D相关的解说了。
首先,在此之前我们一直在使用的矩形图像已经不能继续像以前那样使用了。我们没有“四角形”的说法。
在此之前我们使用的这样子的形状,我们使用“2个三角形”来表示。
如果我们用2个三角形来表示四角形的话,那么任何形状的四角形我们都能表示出来了。
我们试着分开绘制三角形abc和三角形def吧。
那么,坐标要怎么办呢。
这里需要大家注意的是“3D情况下坐标原点在左下角”这一点。迄今为止我们都认为往下是增加y的值。那是因为之前原点在左上角呢。
由于在3D下左下角为原点,因此请注意y的增加是往上走的。
因此,比如中心点为(u,v)的话,a的坐标的就变为(u-x/2, v+y/2)了。
另外,还请注意图像的尺寸只能使用2的幂次大小。
只能处理2,4,8,16,32,64,256,512…这样子尺寸的图像。※1
如果想要使用90×120这样子的图像的话,必须要把90×120的图像放入128×128的图像中,然后“只使用图像中90×120的部分”。
另外,像(128×256)、(512×32)这样,只要是2的幂次,横向和纵向的尺寸不一样也无所谓。
那么我们具体地进行程序讲解吧。
在DX Library使用的每一个3D坐标我们像下面那样通过结构体管理。
struct VECTOR
{
float x, y, z ;
} ;
struct VERTEX_3D
{
VECTOR pos ;
unsigned char b, g, r, a ;
float u, v ;
} ;
可能会考虑到对于每一个坐标会有相当多的变量。
必要的信息除了(x,y,z)的坐标数据以外,还有r,g,b这样子的颜色信息、a这样子的透明度。
以及在※1中说到的表示使用图像的哪个部分的u,v。
对一个多边形而言,它是需要相当多的变量来表示的。
不过为每一个坐标指定颜色和透明度这样子的分量,似乎就可以做到在图像中表现出彩虹色、或者表现出仅在图像的边角逐渐渗透,这样子精致漂亮的效果。
在这里可能有人不是很明白为什么我们要再加上u,v这个分量。
通过设置u,v的值在0.0f~1.0f之间,我们可以指定出使用图像的哪个部分。u相当于x,v相当于y。
比如用前面的例子来说明,如果图像为128×128,我们想要使用的部分为90×120的话
我们将a设置为(u,v)=(0.0f,0.0f),把b设置为(u,v)=(90.0f/128.0f,0)。如果在横向128像素中我们只想使用到90为止的话,那么就像90/128这样子指定,不管哪个都要指定0~1中的值。
这样一来,比如d就是i(u,v)=(90.0f/128.0f,120.0f/128.0)。
要为每一个坐标都加上这样的信息稍微有点麻烦呢。
使用前面的VERTEX_3D在Vertex[6]中保存6个点的时候,要各个点要如何保存这些信息才好呢? ([0]为a、[1]为b….、[5]为f)
现在,为了描绘中心点为(320,240)、宽度为100、高度为100、深度为Z的图像,
在对a的位置代入必要信息的时候,我们像下面那样为之代入。
// 对画面中央以100的宽高进行绘制
Vertex[0].pos.x = 320.0F - 50.0F ; Vertex[0].pos.y = 240.0F + 50.0F ; Vertex[0].pos.z = Z ;
Vertex[0].u = 0.0F ; Vertex[0].v = 0.0F ;
在此之上,我们试着看看放在DX Library的参考文档中的范例吧(我修正了一部分)。
在这个范例中,我们使用上面所说的内容,让2个三角形像是促使它们拼成四角形一般彼此靠近着绘制,而在Z轴上时而远离时而靠近,这样子使画像动起来。
※ 此处的源代码借用了DX Library原站中的参考手册。
— main.cpp —
#include "../../../include/DxLib.h"
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{
int GrHandle ;
float Z, ZAdd ;
VERTEX_3D Vertex[6] ; //因为有2个多边形,因此顶点为6个
ChangeWindowMode(TRUE);
//DX Library初始化处理
if( DxLib_Init() == -1 )
return -1 ; // 如果发生错误直接终止
// 将绘制目标变为里画面
SetDrawScreen( DX_SCREEN_BACK ) ;
// 读入纹理
GrHandle = LoadGraph( "mydat/img/kabe.png" ) ;
// 初始化z值
Z = 0.0F ;
// 初始化z值的附加值(最开始为靠近)
ZAdd = -1.0F ;
// 循环直至某个键被按下
while( CheckHitKeyAll() == 0 )
{
// 消息处理
if( ProcessMessage() != 0 ) break ;
// 画面初始化
ClearDrawScreen() ;
// z值的处理
Z += ZAdd ;
// 当超过规定边界的时候翻转前进方向
if( Z < -300.0F || Z > 300.0F ) ZAdd = -ZAdd ;
// 设置顶点信息
{
// 对画面中央以100宽高进行绘制
Vertex[0].pos.x = 320.0F - 50.0F ; Vertex[0].pos.y = 240.0F + 50.0F ; Vertex[0].pos.z = Z ;
Vertex[0].u = 0.0F ;
Vertex[0].v = 0.0F ;
Vertex[1].pos.x = 320.0F + 50.0F ; Vertex[1].pos.y = 240.0F + 50.0F ; Vertex[1].pos.z = Z ;
Vertex[1].u = 1.0F ;
Vertex[1].v = 0.0F ;
Vertex[2].pos.x = 320.0F - 50.0F ; Vertex[2].pos.y = 240.0F - 50.0F ; Vertex[2].pos.z = Z ;
Vertex[2].u = 0.0F ;
Vertex[2].v = 1.0F ;
Vertex[3].pos.x = 320.0F + 50.0F ; Vertex[3].pos.y = 240.0F - 50.0F ; Vertex[3].pos.z = Z ;
Vertex[3].u = 1.0F ;
Vertex[3].v = 1.0F ;
Vertex[4].pos.x = 320.0F - 50.0F ; Vertex[4].pos.y = 240.0F - 50.0F ; Vertex[4].pos.z = Z ;
Vertex[4].u = 0.0F ;
Vertex[4].v = 1.0F ;
Vertex[5].pos.x = 320.0F + 50.0F ; Vertex[5].pos.y = 240.0F + 50.0F ; Vertex[5].pos.z = Z ;
Vertex[5].u = 1.0F ;
Vertex[5].v = 0.0F ;
// 亮度分量全部为100%
Vertex[0].r = Vertex[0].g = Vertex[0].b = 255 ;
Vertex[1].r = Vertex[1].g = Vertex[1].b = 255 ;
Vertex[2].r = Vertex[2].g = Vertex[2].b = 255 ;
Vertex[3].r = Vertex[3].g = Vertex[3].b = 255 ;
Vertex[4].r = Vertex[4].g = Vertex[4].b = 255 ;
Vertex[5].r = Vertex[5].g = Vertex[5].b = 255 ;
// a也为最大值
Vertex[0].a = 255 ;
Vertex[1].a = 255 ;
Vertex[2].a = 255 ;
Vertex[3].a = 255 ;
Vertex[4].a = 255 ;
Vertex[5].a = 255 ;
}
// 不使用透明度绘制两个多边形
DrawPolygon3D( Vertex, 2, GrHandle, TRUE ) ;
// 将里画面的内容反映到表画面中
ScreenFlip() ;
}
// DX Library使用终止处理
DxLib_End() ;
// 结束程序
return 0 ;
}
运行结果