 |
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
| View previous topic :: View next topic |
| Author |
Message |
Calv!n

Joined: 13 Aug 2007 Posts: 10
|
Posted: Wed Jul 29, 2009 4:42 am Post subject: [SOLVED]Bézier Patches on PSP |
|
|
Greetings everyone.
I have been working on a dynamic LOD system of terrain rendering based on using cubic Bézier patches.
I have done similar previous work on PC (http://jj.iamjunkie.net/pc.php). Now I am trying to create an entire terrain engine system from the ground up for PSP. The model for which I'm basing my terrain engine off of is the method described here:
http://www.gamasutra.com/view/feature/3004/dynamic_level_of_detail_terrain_.php?print=1
I have been making some progress. These are just showing off the terrain being rendered. No specific LOD has been used yet. Just showing off that the ability to subdivide any patch at a certain level is there.
The problem comes now. I have a camera system setup for FPS style of viewing and movement, but in order to have the effect of walking on the terrain I need to get a height value from a patch at any given camera_x, camera_z.
The way I had done cubic Bézier patches on PC was using a basis function:
| Code: | | P0*t^3 + P1*3t^2(1-t) + P2*3t(1-t)^2 + P3*(1-t)^3 |
The PSP has a built in render call for drawing bpatches.
| Code: | sceGuPatchDivide(u, v);
sceGumDrawBezier(GU_VERTEX_32BITF|GU_TRANSFORM_3D, 4, 4, 0, bpatchArray[i].nodes); |
The first call will tell the GU to what level to subdivide the patch. The second function does the rendering of the patch. 4x4 nodes per patch.
My problem is, the way the GU strips together the geometry is abstracted away and I seem to be having an issue. I can render the landscape just fine, but the height lookup is incorrect.
| Code: | float
getHeightAt(float a_x, float a_z)
{
/* account for map scaling and centering */
a_x /= SCALE_X;
a_z /= SCALE_Z;
a_x += mapCenter;
a_z += mapCenter;
/* calculate the patch lookup index */
/* get current patch corresponding to a_x and a_z */
int i = (int)((floor(a_z / 3) * (mapWidth / 3)) + floor(a_x / 3));
/* 4 control nodes per patch width & height */
a_x /= 4;
a_z /= 4;
float u = a_x - floor(a_x);
float v = a_z - floor(a_z);
pspDebugScreenSetXY(0, 4);
pspDebugScreenPrintf("patch lookup index: %d ", i);
pspDebugScreenSetXY(0, 5);
pspDebugScreenPrintf("num patches: %d ", numPatches);
/* basis function */
/* P0*t^3 + P1*3t^2(1-t) + P2*3t(1-t)^2 + P3*(1-t)^3 */
float result_y = 0.0f;
float u1 = 1.0f - u;
float v1 = 1.0f - v;
float bu[4] = {u*u*u, 3*u1*u*u, 3*u1*u1*u, u1*u1*u1};
float bv[4] = {v*v*v, 3*v1*v*v, 3*v1*v1*v, v1*v1*v1};
int s, t;
for(s = 0; s < 4; s++)
{
for(t = 0; t < 4; t++)
{
result_y += bpatchArray[i].nodes[(s * 4) + t].y * bu[s] * bv[t];
}
}
return result_y;
} |
I used this same basis function for PC for stripping together my vertices, and I used the first order derivative of this basis function for normals (lighting) calculations and it all worked out fine on PC.
Perhaps there is some stupid error that I am overlooking (I really hope this is the case). I have been continuing to debug this for quite a few days and I am rather stuck. Perhaps some fresh eyes could spot some errors in my methodology. Thanks in advance! :)
bpatch.h
| Code: | #ifndef _BPATCH_H_
#define _BPATCH_H_
/* ____________________ S T R U C T S ____________________ */
struct Vertex
{
float x, y, z;
};
struct BPatch
{
struct Vertex nodes[16];
};
#endif
|
terrain.h
| Code: | #ifndef _TERRAIN_H_
#define _TERRAIN_H_
/* ____________________ D E F I N E S ____________________ */
#define SCALE_X 4.0f
#define SCALE_Y 0.5f
#define SCALE_Z 4.0f
/* __________ P U B L I C F U N C T I O N S __________ */
int
loadMap(const char *a_filename);
float
getHeightAt(float a_x, float a_z);
void
renderTerrain(unsigned int a_renderMode);
int
destroyTerrain(void);
#endif
|
terrain.c
| Code: | #include <stdio.h>
#include <malloc.h>
#include <math.h>
#include <pspgu.h>
#include <pspgum.h>
#include <pspdebug.h>
#include "terrain.h"
#include "bpatch.h"
/* __________ P R I V A T E V A R I A B L E S __________ */
static unsigned int mapWidth, mapHeight, mapSize;
static float mapCenter;
static unsigned int numPatches;
static struct BPatch *bpatchArray;
/* __________ P R I V A T E F U N C T I O N S __________ */
static int
createPatches(unsigned char *a_map);
/* __________ F U N C T I O N S __________ */
int
loadMap(const char *a_filename)
{
FILE * pFile = NULL;
if (!a_filename)
{
return -1;
fclose(pFile);
}
pFile = fopen(a_filename, "rb");
if (!pFile)
{
printf("ERROR: Can't find map file!");
fclose(pFile);
return -1;
}
fseek(pFile, 0, SEEK_END);
mapSize = ftell(pFile);
mapWidth = (int)sqrtf(mapSize);
mapHeight = mapWidth;
mapCenter = (int)(mapWidth / 2);
unsigned char *heightmapData;
heightmapData = malloc(sizeof(unsigned char)*mapSize);
if (heightmapData == NULL)
{
fclose(pFile);
free(heightmapData);
return -1;
}
fseek(pFile, 0, SEEK_SET);
fread(heightmapData, 1, mapSize, pFile );
int result = ferror(pFile);
if (result)
{
printf("ERROR: Failed to get data!");
fclose(pFile);
free(heightmapData);
return -1;
}
fclose(pFile);
numPatches = (int)(mapWidth / 3) * (int)(mapHeight / 3);
//printf("num patches: %d\n", numPatches);
bpatchArray = malloc(sizeof(struct BPatch) * numPatches);
int errorCheck = createPatches(heightmapData);
if (errorCheck != 1)
{
fclose(pFile);
free(heightmapData);
free(bpatchArray);
return -1;
}
free(heightmapData);
return 1;
}
static int
createPatches(unsigned char * a_map)
{
int u, v, x, z, patchIndex = 0, nodeIndex = 0;
for (u = 0; u < mapHeight - 3; u += 3)
{
//printf("u: %d\n", u);
for (v = 0; v < mapWidth - 3; v += 3)
{
//printf("v: %d\n", v);
//patchIndex = (u * mapWidth) + v;
nodeIndex = 0;
for (x = u; x < u + 4; x++)
{
//printf("z: %d\n", z);
for(z = v; z < v + 4; z++)
{
//printf("x: %d\n", x);
bpatchArray[patchIndex].nodes[nodeIndex].x = (float)((x - mapCenter) * SCALE_X);
bpatchArray[patchIndex].nodes[nodeIndex].y = (float)(a_map[(x * mapWidth) + z] * SCALE_Y);
bpatchArray[patchIndex].nodes[nodeIndex].z = (float)((z - mapCenter) * SCALE_Z);
nodeIndex++;
}
}
/*
if (patchIndex == 0)
{
int temp = 0;
for (temp = 0; temp < 16; temp++)
{
printf("patch: %d\n", patchIndex);
printf("node: %d\n", temp);
printf("x: %f\n", bpatchArray[patchIndex].nodes[temp].x);
printf("y: %f\n", bpatchArray[patchIndex].nodes[temp].y);
printf("y: %f\n\n", bpatchArray[patchIndex].nodes[temp].z);
}
}
*/
//printf("patchIndex: %d\n", patchIndex);
//printf("nodeIndex: %d\n\n", nodeIndex);
patchIndex++;
}
}
return 1;
}
float
getHeightAt(float a_x, float a_z)
{
/* account for map scaling and centering */
a_x /= SCALE_X;
a_z /= SCALE_Z;
a_x += mapCenter;
a_z += mapCenter;
/* calculate the patch lookup index */
/* get current patch corresponding to a_x and a_z */
int i = (int)((floor(a_z / 3) * (mapWidth / 3)) + floor(a_x / 3));
/* 4 control nodes per patch width & height */
a_x /= 4;
a_z /= 4;
float u = a_x - floor(a_x);
float v = a_z - floor(a_z);
pspDebugScreenSetXY(0, 4);
pspDebugScreenPrintf("patch lookup index: %d ", i);
pspDebugScreenSetXY(0, 5);
pspDebugScreenPrintf("num patches: %d ", numPatches);
/* basis function */
/* P0*t^3 + P1*3t^2(1-t) + P2*3t(1-t)^2 + P3*(1-t)^3 */
float result_y = 0.0f;
float u1 = 1.0f - u;
float v1 = 1.0f - v;
float bu[4] = {u*u*u, 3*u1*u*u, 3*u1*u1*u, u1*u1*u1};
float bv[4] = {v*v*v, 3*v1*v*v, 3*v1*v1*v, v1*v1*v1};
int s, t;
for(s = 0; s < 4; s++)
{
for(t = 0; t < 4; t++)
{
result_y += bpatchArray[i].nodes[(s * 4) + t].y * bu[s] * bv[t];
}
}
return result_y;
}
void
renderTerrain(unsigned int a_renderMode)
{
//sceGuPatchDivide(4, 4);
if (a_renderMode == 0)
sceGuPatchPrim(GU_POINTS);
else if (a_renderMode == 1)
sceGuPatchPrim(GU_LINE_STRIP);
else if (a_renderMode == 2)
sceGuPatchPrim(GU_TRIANGLE_STRIP);
//sceGuColor(0xffffffff);
/* just some coloring stuff and strip stuff at different subdivide levels for testing */
int i, colorIndex = 0, u = 4, v = 4;
for (i = 0; i < numPatches; i++)
{
if (colorIndex == 0) /* red */
{
u = 8;
v = 8;
sceGuColor(0x000000ff);
}
if (colorIndex == 1) /* green */
{
u = 4;
v = 4;
sceGuColor(0x0000ff00);
}
if (colorIndex == 2) /* blue */
{
u = 6;
v = 6;
sceGuColor(0x00ff0000);
}
sceGuPatchDivide(u, v);
sceGumDrawBezier(GU_VERTEX_32BITF|GU_TRANSFORM_3D, 4, 4, 0, bpatchArray[i].nodes);
if (colorIndex == 2)
{
colorIndex = -1;
}
colorIndex++;
}
}
int
destroyTerrain(void)
{
free(bpatchArray);
return 1;
}
|
_________________ http://jj.iamjunkie.net/
Last edited by Calv!n on Sat Aug 01, 2009 5:42 am; edited 2 times in total |
|
| Back to top |
|
 |
slasher2661996
Joined: 22 Feb 2009 Posts: 91 Location: Melbourne Australia ZOMG
|
Posted: Wed Jul 29, 2009 1:45 pm Post subject: |
|
|
| wicked engine, can i have the current source? |
|
| Back to top |
|
 |
Calv!n

Joined: 13 Aug 2007 Posts: 10
|
Posted: Wed Jul 29, 2009 2:56 pm Post subject: |
|
|
| slasher2661996 wrote: | | wicked engine, can i have the current source? |
I'm not sure why you would need that. I don't give out full source to my engine, especially for no good reason. _________________ http://jj.iamjunkie.net/ |
|
| Back to top |
|
 |
Calv!n

Joined: 13 Aug 2007 Posts: 10
|
Posted: Sat Aug 01, 2009 5:43 am Post subject: |
|
|
Well, its finally fixed now. I rewrote most of it and then a friend had a look-see to spot a last couple of fixes.
I'll post some screens later on once the dynamic LOD has been implemented and i apply some texturing. _________________ http://jj.iamjunkie.net/ |
|
| Back to top |
|
 |
J.F.
Joined: 22 Feb 2004 Posts: 2906
|
Posted: Sat Aug 01, 2009 7:12 am Post subject: |
|
|
| Cool, looking forward to it... and get out of the rain! Or at least, get an umbrella. ;) |
|
| Back to top |
|
 |
slasher2661996
Joined: 22 Feb 2009 Posts: 91 Location: Melbourne Australia ZOMG
|
Posted: Sat Aug 01, 2009 5:19 pm Post subject: |
|
|
| I didn't mean the source, i mean't i working binary that i could use, but no biggie :D |
|
| Back to top |
|
 |
Calv!n

Joined: 13 Aug 2007 Posts: 10
|
Posted: Wed Aug 05, 2009 12:26 am Post subject: |
|
|
Well you asked for the source so what else was I supposed to assume? ;)
The LOD is working.
LOD
---------
green = 16 tris / patch (low LOD - anything further than 250 meters from viewpoint)
blue = 36 tris / patch (medium LOD - up tp 250 meters from viewpoint)
red = 48 tris / patch (high LOD - up to 25 meters from viewpoint) _________________ http://jj.iamjunkie.net/ |
|
| Back to top |
|
 |
imhotep
Joined: 13 Dec 2005 Posts: 41
|
Posted: Tue Aug 11, 2009 6:37 am Post subject: |
|
|
| what are you doing this for? for you or for the public? would be cool to have this included into the sdk :p |
|
| Back to top |
|
 |
a_noob
Joined: 17 Sep 2006 Posts: 97 Location: _start: jr 0xDEADBEEF
|
Posted: Tue Aug 18, 2009 4:56 pm Post subject: |
|
|
Calvin, of course I like your work as always, but you need to realize that the psp is usually handicapped when it comes to rendering large amounts of scenery, so a MipMap idea would be more suited, where you have 3 or so levels of detail already built out, and you just toggle a flag for which level to render. I'd like to know the FPS on this, along with how the gu is setup. _________________
| Code: | .øOº'ºOø.
'ºOo.oOº' |
|
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Tue Aug 18, 2009 10:10 pm Post subject: |
|
|
You sorta use sceGuPatchDivide to set the level of details as it is GE which will subdivide your nodes into a 2 x udiv x vdiv vertex list to draw. Is it your intention for getHeightAt not to be aware of the level of details? If you really want to have a more accurate height, you need to take into account udiv and vdiv of your bpatch and if it is not accurate enough, you also need to take the intersection of your Y axis on the closest triangle computed by your function.
Or am I wrong somewhere ? |
|
| Back to top |
|
 |
Calv!n

Joined: 13 Aug 2007 Posts: 10
|
Posted: Wed Sep 09, 2009 5:14 am Post subject: |
|
|
a_noob: I'm not sure what your point is. What you described is the essence of this project.
hlide: the bezier patches are the raw data. When you desire a point from the point list of nodes it doesn't matter what LOD you get it at. The function getHeightAt() will retrieve a point on the surface at any given percentage across u, v on the patch.
The render function just takes the point cloud of nodes and go through each path and subdivides accordingly on the GE.
When I work on this further I will post more results. _________________ http://jj.iamjunkie.net/ |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|