浅谈GU (一)



掌叔
2008-06-09 09:17:30

摘自:bbs.khors.com
作者:Dr.Watson

本篇会和大家说一下 JGE 在GU方面的运用. 我们首先讨论一下像素格式, PSP是有2MB视像记忆, 除了作为萤幕显示之外, 我们也可以把我们的图像存在这里, 增加GPU处理的速度, 因为2MB不是很大, 所以我们在决定游戏用那一种像素格式时就要详细的考虑清楚了. PSP共有以下4 种像素格式:
[code=c]
PSP_DISPLAY_PIXEL_FORMAT_565 //16-bit RGB 5:6:5
PSP_DISPLAY_PIXEL_FORMAT_5551 //16-bit RGBA 5:5:5:1
PSP_DISPLAY_PIXEL_FORMAT_4444 //16-bit RGBA 4:4:4:4
PSP_DISPLAY_PIXEL_FORMAT_8888 //32-bit RGBA 8:8:8:8
[/code]
一般来说, 游戏内的图, 都要有透明色的支援, 所以我们可以除掉 565. 要是我们只需要透明色, 不用以半透明色弄特别效果, 5551 就会比较适合. 至于4444 和 8888, 就是速度和颜色美艳之间的抉择! 4444 只有4096不同的颜色再加16个不同的透明度, 但处理的速度却是快了差不多一半!

举个例子, 要是我们用8888, 那就是每个像素用4BYTES, 一个画面加一个缓冲区, 就是512X272X4X2 = 1,088KB, 只剩下960KB可以留给我们的程序用了, 这样我们可能要把大部份贴图存放在主记忆里了, 这就会减慢GPU的贴图处理.

StarBugz 现在就选择了用4444 的格式, 要是最后完成后的运速理想, 说不定也会转为8888.

现在让我们转入正题吧! 在程序内要调用GU库, 我们先要做一些初始的呼叫, 要是我们的目的只是写2D游戏, 下面这段代码一般情况下都适用的了:

[code=c]
sceGuInit();

// 设定 GU
sceGuStart(GU_DIRECT,list);
mVideoBufferStart = 0;

// 设定画图缓冲
sceGuDrawBuffer(BUFFER_FORMAT, (void *)mVideoBufferStart, FRAME_BUFFER_WIDTH);
mVideoBufferStart += FRAME_BUFFER_SIZE;

// 设定显示缓冲
sceGuDispBuffer(SCREEN_WIDTH, SCREEN_HEIGHT, (void *)mVideoBufferStart, FRAME_BUFFER_WIDTH);

// 计算由那里开始可作为我们存图之用
mVideoBufferStart += FRAME_BUFFER_SIZE;
mCurrentPointer = mVideoBufferStart;

sceGuOffset(2048 - (SCREEN_WIDTH/2), 2048 - (SCREEN_HEIGHT/2));
sceGuViewport(2048, 2048, SCREEN_WIDTH, SCREEN_HEIGHT);

sceGuScissor(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
sceGuEnable(GU_SCISSOR_TEST);
sceGuFrontFace(GU_CW);
sceGuEnable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);

// 透明色/溷色等支援
sceGuEnable(GU_BLEND);
sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);

sceGuClear(GU_COLOR_BUFFER_BIT);
sceGuFinish();
sceGuSync(0,0);

sceDisplayWaitVblankStart();
sceGuDisplay(1);
[/code]

接下来要说的, 就是最重要的贴图了! GU库的原本主要功能, 是用以编写3D游戏为主, 因此用GU库显示图像, 并不是我们在2D编程上常用的LoadImage/DrawImage, 而是要载入贴图(Texture), 然后再把贴图的全部或部份贴在萤幕(缓冲区)上显示.

一般来说, 我们是需要设定一个多边形(Polygon), 例如最基本的是以3个点(vertex), 设定一个3角形和有关贴图的资料, 然后把这些点交给GPU, 完成一个贴图的动作! 但在2D游戏上, 我们常用的图都是四边形的, 所以比较正确的方法, 是用4个点两个3角形组成一个四边形(quad):

[font=Courier New]
v0---v1
| / |
| / |
v2---v3
[/font]

看一下我们的Vertex 的定义:
[code=c]
struct Vertex
{
float u, v;
PIXEL_TYPE color;
float x, y, z;
};
[/code]
我们通常是用x,y 来代表萤幕上的位置, 而u,v 来代表贴图上的位置, 以下面这个作为一个例子:
[attach]59[/attach]
我们想把第一格的动画, 贴在萤幕(100,100)的位置, 而动画格的大小为100x100, 那我们四个vertices的设定就是:
[code=c]
vertices[0].u = 0.0f;
vertices[0].v = 0.0f;
vertices[0].color = color;
vertices[0].x = 100.0f;
vertices[0].y = 100.0f;
vertices[0].z = 0.0f;

vertices[1].u = 100.0f;
vertices[1].v = 0.0f;
vertices[1].color = color;
vertices[1].x = 200.0f;
vertices[1].y = 100.0f;
vertices[1].z = 0.0f;

vertices[2].u = 0.0f;
vertices[2].v = 100.0f;
vertices[2].color = quad->mColor[2];
vertices[2].x = 100.0f;
vertices[2].y = 200.0f;
vertices[2].z = 0.0f;

vertices[3].u = 100.0f
vertices[3].v = 100.0f;
vertices[3].color = color;
vertices[3].x = 200.0f;
vertices[3].y = 200.0f;
vertices[3].z = 0.0f;
[/code]

接着, 就可以用sceGuDrawArray 把图贴出来:
[code=c]
sceGuDrawArray(GU_TRIANGLE_STRIP,GU_TEXTURE_32BITF|TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 4, 0, vertices);
[/code]

看一下sceGuDrawArray 的参数:

GU_TRIANGLE_STRIP:
我们是用一系列的3角形定义

GU_TEXTURE_32BITF|TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D:
我们的vertex的格式, 是贴图u,v 用32bit浮点数, 接着是颜色, 接着是32bit浮点数的萤幕位置. 而贴图是2D形式.

4 是指有4个点.

时间关係, 先说到这里 :)


wuchanghyz
2010-08-30 16:12:53

GU库可以简单的理解成贴图库吗?