几个月前,我再次从包装盒中取出了一个满是灰尘的PSP,并决定将以前显示的
发动机移植到
那里 。 软件渲染没有问题-一切都以这种方式工作。 但是使用GU并不是那么简单。 在本文中,我将向您展示如何使用GU为PSP编写简单的三维应用程序的示例。
我提前警告您,PSP的编程指南不足,因此,我的某些结论可能不正确。 但是,要点。
PSP程序的主要功能,如果任何人都不知道,它看起来像这样:
#include <pspkernel.h> #include <pspdebug.h> #include <pspdisplay.h> //---------------------------------------------------------------------------------------- PSP_MODULE_INFO("GUTexture", 0, 1, 1); PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER|THREAD_ATTR_VFPU); void dump_threadstatus(void); bool done=false; int exit_callback(int arg1,int arg2,void *common) { done=true; return(0); } int CallbackThread(SceSize args, void *argp) { int cbid; cbid=sceKernelCreateCallback("Exit Callback",exit_callback,NULL); sceKernelRegisterExitCallback(cbid); sceKernelSleepThreadCB(); return(0); } int SetupCallbacks(void) { int thid = 0; thid=sceKernelCreateThread("update_thread",CallbackThread,0x11,0xFA0,0,0); if(thid>=0) sceKernelStartThread(thid, 0, 0); return(thid); } //---------------------------------------------------------------------------------------- // //---------------------------------------------------------------------------------------- int main(int argc, char **argv) { pspDebugScreenInit(); // SetupCallbacks(); // ………. // sceKernelExitGame(); return(0); }
GU的初始化如下:
首先,我们请求指向三个缓冲区的指针-屏幕缓冲区,屏幕外缓冲区和深度缓冲区(Z缓冲区)。 缓冲区以每行512像素对齐(尽管PSP的行为480像素)。 您还需要考虑像素颜色格式。 在此示例中,使用格式GU_PSM_8888-像素颜色的R,G,B和Alpha分量每个8位。 对于Z缓冲区,仅使用GU_PSM_4444格式是因为它是16位-PSP的16位Z缓冲区。
查询缓冲区指针的函数定义为
#include <pspge.h> #include <pspgu.h> static unsigned int staticOffset=0; static unsigned int getMemorySize(unsigned int width,unsigned int height,unsigned int psm) { switch (psm) { case GU_PSM_T4: return((width*height)>>1); case GU_PSM_T8: return(width*height); case GU_PSM_5650: case GU_PSM_5551: case GU_PSM_4444: case GU_PSM_T16: return(2*width*height); case GU_PSM_8888: case GU_PSM_T32: return(4*width*height); default: return(0); } } void* getStaticVramBuffer(unsigned int width,unsigned int height,unsigned int psm) { unsigned int memSize=getMemorySize(width,height,psm); void* result=(void*)staticOffset; staticOffset+=memSize; return(result); } void* getStaticVramTexture(unsigned int width,unsigned int height,unsigned int psm) { void* result=getStaticVramBuffer(width,height,psm); return((void*)(((unsigned int)result) + ((unsigned int)sceGeEdramGetAddr()))); }
这些不是我的功能-我很久以前从某些程序中获取了它们,只是做了些微改动。 内存分配在视频存储区中。 如果可能的话,还应该在其中放置纹理,并通过getStaticVramTexture请求一个指针,否则性能会急剧下降。 当然,在此类请求期间不会分配动态内存,而只会为屏幕和纹理分配一部分指定的PSP地址空间。 据我所知,PSP只有2 MB的视频内存-很小,无法存储很多纹理。
PSP GU编程与OpenGL编程相似,但有一个区别-命令的执行要求它们在显示列表中的位置,并且该列表的内存必须预先分配和对齐:
静态无符号char __attribute __((aligned(16)))DisplayList [262144];
与坐标转换有关的命令不需要显示列表,并且可以在程序中的任何位置执行。
例如,您可以初始化GU,如下所示:
使用GU完成工作之后,有必要调用sceGuTerm()。
以任何方便的方式加载大小纹理(WidthImage; HeightImage)(指向纹理数据的数据指针-最好将其保存在视频存储区域中)后,我们就可以显示它。
如何显示多边形? 为了绘制GU几何图形,PSP要求将所有点放入一个数组中,必须首先使用sceGuGetMemory命令获取指向其的指针,并向其传递所请求的内存块的大小(以字节为单位)。 在此指针的更下方,您应该编写一个点数组,并要求PSP显示它们,例如,使用带有必要参数的sceGumDrawArray命令。 但是这些点的格式是什么? 对于PSP,点数据按特定顺序排列,描述一个点的数组大小必须为32字节的倍数:顶点权重,纹理坐标,点颜色,点的法线,点坐标。 按此顺序。 为了不打扰格式,我定义了一组结构和函数来使用它们:
然后,您可以指定几何形状(在这种情况下为正方形),例如:
并输出它,例如:
size_t vertex_amount=vector_point.size(); SGuNVCTPoint *sGuNVCTPoint_Ptr=(SGuNVCTPoint*)sceGuGetMemory(vertex_amount*sizeof(SGuNVCTPoint)); if (sGuNVCTPoint_Ptr!=NULL) { for(size_t n=0;n<vertex_amount;n++) sGuNVCTPoint_Ptr[n]=vector_point[n]; sceGumDrawArray(GU_TRIANGLE_FAN,GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D|GU_NORMAL_32BITF|GU_TEXTURE_32BITF,vertex_amount,0,sGuNVCTPoint_Ptr); }
对于输出,我向sceGumDrawArray函数指出了我确切绘制的内容以及该点的格式(GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D | GU_NORMAL_32BITF | GU_TEXTURE_32BITF-该点由颜色,坐标,法线,纹理坐标组成并且需要乘以对应的矩阵)。 绘制仅适用于三角形。 但这还不是全部...
一切似乎都有效,但只有在所有点都在眼前且可见的情况下,它才起作用。 一旦至少一个点进入一定的模糊距离,GU将拒绝绘制整个多边形。 据我了解,PSP的GU要求相对于四个剪切平面(左,右,顶部和底部(并且前一个会自动显示)),该点位于该体积之内,否则,GU不会同意显示它。 问题。 但是在游戏中,存在3D图形,并且未观察到此类伪像! 让我们看看他们如何在PSP Quake 1中解决此问题,因为这些源可用于分析。
我们从源代码分析中看到什么? 但是实际上,这是什么:
也就是说,在《雷神之锤1》中,在得出结论之前,他们只是将所有点转移到限制视图的体积内部,或者将它们全部丢弃(如果整个图不可见)。 怎么做? 您只需要阅读三个矩阵-GU_PROJECTION,GU_MODEL和GU_VIEW。 将它们相乘,得到最终的坐标变换矩阵。 从该矩阵中,您可以拉出所有必要的平面以限制视图(结果向量的4个分量使用等式ax + by + cz + w = 0定义一个平面)。 (a,b,c)是法线向量,并且w = a * x0 + b * y0 + c * z0-表征平面的某个点(x0,y0,z0)。 我们自己不需要点的坐标-只要知道w。
裁剪操作如下(依次循环上述四个平面):
但是为了这个重点,我们需要以下功能(从Quake 1中停用):
仅在执行了此类截断操作之后,您最终才能最终使用GU在PSP上正确接收三维图形的输出。 您可以创建一个游戏! :)

顺便说一句,您也可以将PSP向量处理器用于向量的标量积。 例如,这是一个确定是否完全需要裁剪的函数(从同一Quake 1 for PSP中撕成碎片):
这里的一切都很简单-他们将平面向量和点坐标放置在寄存器中,并要求VFPU执行标量积。
→
链接到最简单的纹理显示应用程序
→使用GU
链接到PSP引擎
PS我知道有PSP的编程专家。 也许他们会告诉您PSP GU的排列方式以及如何正确使用它。