shadows...

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
Visigotico
Posts: 11
Joined: Wed Apr 23, 2008 11:44 am

shadows...

Post by Visigotico »

gta chinatown wars apparently uses stencil shadow volume, but for a scene where there are many shadow cast objects, this technique can be a great performance hit.

does anyone know how shadows are achieved in silent hill game? Based in artifacts sometimes visible in the edges of shadows, the technique used must be shadowmap, but the PSP hardware doesn't have pixel shader or something like the opengl extensions necessary to make it work...
User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

Post by Raphael »

Who says shadow mapping depends on pixel shaders?
http://www.paulsprojects.net/tutorials/smt/smt.html
Also, there are other methods to achieve shadows that don't depend on shaders.
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
Visigotico
Posts: 11
Joined: Wed Apr 23, 2008 11:44 am

Post by Visigotico »

shadowmap implementantion modifying SDK reflexion sample.

----------------------------------------------------------------------------

#include <pspkernel.h>
#include <pspdisplay.h>
#include <pspdebug.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#include <pspgu.h>
#include <pspgum.h>
#include <pspvfpu.h>

PSP_MODULE_INFO("ShadowMap Sample", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);

static unsigned int __attribute__((aligned(16))) list[262144];
extern unsigned char logo_start[];

struct Vertex
{
float u, v;
unsigned int color;
float x,y,z;
};

struct Vertex __attribute__((aligned(16))) obj[36] = {
{0, 0, 0xff6666ff,-1,-1, 1},
{1, 0, 0xff6666ff, 1,-1, 1},
{1, 1, 0xff6666ff, 1, 1, 1},
{0, 0, 0xff6666ff,-1,-1, 1},
{1, 1, 0xff6666ff, 1, 1, 1},
{0, 1, 0xff6666ff,-1, 1, 1},

{1, 1, 0xff66ff66, 1, 1, 1},
{0, 1, 0xff66ff66, 1,-1, 1},
{0, 0, 0xff66ff66, 1,-1,-1},
{1, 1, 0xff66ff66, 1, 1, 1},
{0, 0, 0xff66ff66, 1,-1,-1},
{1, 0, 0xff66ff66, 1, 1,-1},

{0, 1, 0xffff6666,-1, 1, 1},
{0, 0, 0xffff6666, 1, 1, 1},
{1, 0, 0xffff6666, 1, 1,-1},
{0, 1, 0xffff6666,-1, 1, 1},
{1, 0, 0xffff6666, 1, 1,-1},
{1, 1, 0xffff6666,-1, 1,-1},


{1, 1, 0xff6666ff, 1.0f,-1.0f,-1.0f},
{0, 1, 0xff6666ff,-1.0f,-1.0f,-1.0f},
{0, 0, 0xff6666ff,-1.0f, 1.0f,-1.0f},
{1, 1, 0xff6666ff, 1.0f,-1.0f,-1.0f},
{0, 0, 0xff6666ff,-1.0f, 1.0f,-1.0f},
{1, 0, 0xff6666ff, 1.0f, 1.0f,-1.0f},

{1, 0, 0xff66ff66,-1,-1,-1},
{1, 1, 0xff66ff66,-1,-1, 1},
{0, 1, 0xff66ff66,-1, 1, 1},
{1, 0, 0xff66ff66,-1,-1,-1},
{0, 1, 0xff66ff66,-1, 1, 1},
{0, 0, 0xff66ff66,-1, 1,-1},

{0, 1, 0xffff6666,-1,-1,-1},
{0, 0, 0xffff6666, 1,-1,-1},
{1, 0, 0xffff6666, 1,-1, 1},
{0, 1, 0xffff6666,-1,-1,-1},
{1, 0, 0xffff6666, 1,-1, 1},
{1, 1, 0xffff6666,-1,-1, 1},
};

struct Vertex __attribute__((aligned(16))) mirror[6] = {
{0, 0, 0xaa000000, -2.0f, 0, -2.0f},
{2, 2, 0xaa000000, 2.0f, 0, 2.0f},
{2, 0, 0xaa000000, 2.0f, 0, -2.0f},

{0, 0, 0xaa000000, -2.0f, 0, -2.0f},
{0, 2, 0xaa000000, -2.0f, 0, 2.0f},
{2, 2, 0xaa000000, 2.0f, 0, 2.0f}
};

struct Vertex __attribute__((aligned(16))) border[6] = {
{0, 0, 0xff0055aa, -2.125f, -0.01, -2.125f},
{2, 2, 0xff0055aa, 2.125f, -0.01, 2.125f},
{2, 0, 0xff0055aa, 2.125f, -0.01, -2.125f},

{0, 0, 0xff0055aa, -2.125f, -0.01, -2.125f},
{0, 2, 0xff0055aa, -2.125f, -0.01, 2.125f},
{2, 2, 0xff0055aa, 2.125f, -0.01, 2.125f}
};

int SetupCallbacks();

#define BUF_WIDTH (512)
#define SCR_WIDTH (480)
#define SCR_HEIGHT (272)
#define PIXEL_SIZE (2) /* change this if you change to another screenmode */
#define FRAME_SIZE (BUF_WIDTH * SCR_HEIGHT * PIXEL_SIZE)
#define ZBUF_SIZE (BUF_WIDTH * SCR_HEIGHT * 2) /* zbuffer seems to be 16-bit? */

#define ZBUFFER_LINEAR(x) (0x600000 + x)
#define ZBUFFER_UNSWIZ(x) (0x200000 + x)
#define VRAM_OFFSET(x) (0x4000000 + x)
#define ZBUFFER_LINEAR16BPP ZBUFFER_UNSWIZ

ScePspFMatrix4 projMatrix, viewMatrixCam, viewMatrixLight;
ScePspFMatrix4 projFinal, unprojFinal;

void setUnProjMatrix(const float *mat)
{
__asm__ volatile (
"ulv.q C000, 0x0 (%0)\n"
"ulv.q C010, 0x10(%0)\n"
"ulv.q C020, 0x20(%0)\n"
"ulv.q C030, 0x30(%0)\n"
: :"r" (mat) );
}

void setProjMatrix(const float *mat)
{
__asm__ volatile (
"ulv.q C100, 0x0 (%0)\n"
"ulv.q C110, 0x10(%0)\n"
"ulv.q C120, 0x20(%0)\n"
"ulv.q C130, 0x30(%0)\n"
: :"r" (mat) );
}

float output[4] __attribute__((aligned(VFPU_ALIGNMENT)));
void TransformArraysInOutByMatUnProj(const float *vec, float *out)
{
__asm__ volatile (
"ulv.q R200, 0x0(%1)\n"
"vone.s S230\n"

"vtfm4.q R300, E000, R200\n"
"sv.q R300, 0x0(%0)\n"
: : "r"(output) , "r" (vec) );
out[0]=output[0];
out[1]=output[1];
out[2]=output[2];
out[3]=output[3];
}

void TransformArraysInOutByMatProj(const float *vec, float *out)
{
__asm__ volatile (
"ulv.q R200, 0x0(%1)\n"
"vone.s S230\n"

"vtfm4.q R300, E100, R200\n"
"sv.q R300, 0x0(%0)\n"
: : "r"(output) , "r" (vec) );
out[0]=output[0];
out[1]=output[1];
out[2]=output[2];
out[3]=output[3];
}

void toScreen(float nx, float ny, float nz,
int *sx, int *sy, int *sz)
{
*sx = ((nx+1.0f)/2.0f) * 480.0f;
*sy = (1.0f - ((ny+1.0f)/2.0f)) * 272.0f;
*sz = (1.0f-nz)*32768;
}

void fromScreen(int sx, int sy, int sz,
float *nx, float *ny, float *nz)
{
*nx = sx*(2.0f/480.0f)-1.0f;
*ny = 1.0f-sy*(2.0f/272.0f);
*nz = 1.0f-sz/32768.0f;
}

ScePspFMatrix4 finalMatrix;

void gumProjectF2(float objx, float objy, float objz,
float *winx, float *winy, float *winz)
{
float in[4];

in[0]=objx;
in[1]=objy;
in[2]=objz;
in[3]=1.0;

TransformArraysInOutByMatProj(in,in);

if (in[3] == 0.0) return;
*winx = in[0]/in[3];
*winy = in[1]/in[3];
*winz = in[2]/in[3];
}

void gumProjectI2(float objx, float objy, float objz,
int *winx, int *winy, int *winz)
{
float fwx,fwy,fwz;
gumProjectF2(objx,objy,objz,&fwx,&fwy,&fwz);
toScreen(fwx,fwy,fwz,winx,winy,winz);
}


void gumUnProjectF2(float winx, float winy, float winz,
float *objx, float *objy, float *objz)
{
float in[4];

in[0]=winx;
in[1]=winy;
in[2]=winz;
in[3]=1.0;

TransformArraysInOutByMatUnProj(in,in);

if (in[3] == 0.0) return;
*objx = in[0]/in[3];
*objy = in[1]/in[3];
*objz = in[2]/in[3];
}

void gumUnProjectI2(int winx, int winy, unsigned short winz,
float *objx, float *objy, float *objz)
{
float x,y,z;

fromScreen(winx,winy,winz,&x,&y,&z);
gumUnProjectF2(x,y,z,objx,objy,objz);
}

int main(int argc, char* argv[])
{
SetupCallbacks();

pspDebugScreenInit();
// setup GU
sceGuInit();


sceGuStart(GU_DIRECT,list);
sceGuDrawBuffer(GU_PSM_4444,(void*)0,BUF_WIDTH);
sceGuDispBuffer(SCR_WIDTH,SCR_HEIGHT,(void*)(FRAME_SIZE),BUF_WIDTH);
sceGuDepthBuffer((void*)(2*FRAME_SIZE),BUF_WIDTH);

sceGuOffset(2048 - (SCR_WIDTH/2),2048 - (SCR_HEIGHT/2));
sceGuViewport(2048,2048,SCR_WIDTH,SCR_HEIGHT);

sceGuDepthRange(65535,0);
// sceGuDepthRange(0xc350,0x2710);
sceGuScissor(0,0,SCR_WIDTH,SCR_HEIGHT);
sceGuEnable(GU_SCISSOR_TEST);
sceGuDepthFunc(GU_GEQUAL);
sceGuEnable(GU_DEPTH_TEST);
sceGuFrontFace(GU_CCW);
sceGuShadeModel(GU_SMOOTH);
sceGuEnable(GU_CULL_FACE);
sceGuFinish();
sceGuSync(0,0);

sceGumMatrixMode(GU_PROJECTION);
sceGumLoadIdentity();
sceGumPerspective(60.0f,16.0f/9.0f,0.5f,1000.0f);
sceGumStoreMatrix(&projMatrix);

sceDisplayWaitVblankStart();
sceGuDisplay(GU_TRUE);

// run sample

int val = 0;

unsigned short *buf = (void *)VRAM_OFFSET(0);
for(;;)
{
float move = sinf(((float)val / 180.0f) * GU_PI);
if(move < 0) {
move *= -1;
}
move += 1;

float rot = ((float)val / 180.0f) * GU_PI;

sceGuStart(GU_DIRECT,list);
sceGuDepthBuffer((void*)(2*FRAME_SIZE),BUF_WIDTH);
sceGuFrontFace(GU_CW);
sceGuPixelMask(0xFFFFFFFF);
sceGuClearDepth(0);
sceGuClear(GU_DEPTH_BUFFER_BIT);

sceGumMatrixMode(GU_VIEW);
float eye1[3]={0.0f,6.0f,4.0f};
float center1[3]={0,0,0};
float up1[3]={0,1,0};
sceGumLoadIdentity();
sceGumLookAt(eye1,center1,up1);
sceGumStoreMatrix(&viewMatrixLight);

sceGumMatrixMode(GU_MODEL);
sceGumLoadIdentity();

// draw normal view
sceGuDisable(GU_TEXTURE_2D);
sceGumDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D, 6, 0, mirror);
sceGumDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D, 6, 0, border);

{
ScePspFVector3 pos = {0,move,0};
ScePspFVector3 rvec = {0,rot * -0.83f, 0};

sceGumTranslate(&pos);
sceGumRotateXYZ(&rvec);
}
sceGumDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D, 36, 0, obj);

sceGuFinish();

gumMultMatrix(&projFinal, &projMatrix, &viewMatrixLight);
sceGuSync(0,0);

sceGuStart(GU_DIRECT,list);
sceGuDepthBuffer((void*)(2*FRAME_SIZE+ZBUF_SIZE),BUF_WIDTH);
sceGuFrontFace(GU_CCW);
sceGuPixelMask(0);
// clear screen
sceGuClearColor(0xff554433);
sceGuClearDepth(0);
sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT);

// setup matrices for cube

sceGumMatrixMode(GU_VIEW);
float eye2[3]={0.0f,3.0f,5.0f};
float center2[3]={0,0,0};
float up2[3]={0,1,0};
sceGumLoadIdentity();
sceGumLookAt(eye2,center2,up2);
sceGumStoreMatrix(&viewMatrixCam);

sceGumMatrixMode(GU_MODEL);
sceGumLoadIdentity();

// draw normal view

sceGuEnable(GU_TEXTURE_2D);
sceGuTexMode(GU_PSM_4444,0,0,0);
sceGuTexImage(0,64,64,64,logo_start);
sceGuTexFunc(GU_TFX_REPLACE,GU_TCC_RGBA);
sceGuTexFilter(GU_LINEAR,GU_LINEAR);
sceGuTexScale(1.0f,1.0f);
sceGuTexOffset(0.0f,0.0f);
sceGuEnable(GU_BLEND);
sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
sceGumDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D, 6, 0, mirror);
sceGuDisable(GU_BLEND);
sceGuDisable(GU_TEXTURE_2D);

sceGumDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D, 6, 0, border);

sceGuEnable(GU_TEXTURE_2D);
sceGuTexMode(GU_PSM_4444,0,0,0);
sceGuTexImage(0,64,64,64,logo_start);
sceGuTexFunc(GU_TFX_ADD,GU_TCC_RGB);
sceGuTexFilter(GU_LINEAR,GU_LINEAR);
sceGuTexScale(1.0f,1.0f);
sceGuTexOffset(0.0f,0.0f);

{
ScePspFVector3 pos = {0,move,0};
ScePspFVector3 rvec = {0,rot * -0.83f, 0};

sceGumTranslate(&pos);
sceGumRotateXYZ(&rvec);
}

sceGumDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D, 36, 0, obj);
sceGuDisable(GU_TEXTURE_2D);

sceGuFinish();
gumMultMatrix(&unprojFinal, &projMatrix, &viewMatrixCam);
gumFullInverse(&unprojFinal,&unprojFinal);
sceGuSync(0,0);

int i,j;
unsigned short *zbufptr = (void *)VRAM_OFFSET(ZBUFFER_LINEAR16BPP(2*FRAME_SIZE));
unsigned short *zbuf = (void *)VRAM_OFFSET(ZBUFFER_LINEAR16BPP(2*FRAME_SIZE+ZBUF_SIZE));
unsigned short *bufptr = buf;

setUnProjMatrix(&unprojFinal);
setProjMatrix(&projFinal);
#define HALF
#ifdef HALF
for(i=0;i<272;i+=2)
#else
for(i=0;i<272;i++)
#endif
{
#ifdef HALF
for(j=0;j<480;j+=2)
#else
for(j=0;j<480;j++)
#endif
{
float fx,fy,fz;
int x,y,z;

if(zbuf[j]==0) continue;
gumUnProjectI2(j,i,zbuf[j],&fx,&fy,&fz);
gumProjectI2(fx,fy,fz,&x,&y,&z);

int shadow=1;
if((x<0)||(x>479)||(y<0)||(y>271)) shadow=0;
if(z>zbufptr[y*512+x]) shadow=0;
if(shadow)
{
bufptr[j]=(bufptr[j]&0xeeee)>>1;
#ifdef HALF
bufptr[j+1]=(bufptr[j+1]&0xeeee)>>1;
bufptr[j+512]=(bufptr[j+512]&0xeeee)>>1;
bufptr[j+512+1]=(bufptr[j+512+1]&0xeeee)>>1;
#endif
}

}
#ifdef HALF
zbuf+=512*2;
bufptr+=512*2;
#else
zbuf+=512;
bufptr+=512;
#endif
}

sceDisplayWaitVblankStart();
buf = (void *)VRAM_OFFSET(sceGuSwapBuffers());

val++;
}

sceGuTerm();

sceKernelExitGame();
return 0;
}

/* Exit callback */
int exit_callback(int arg1, int arg2, void *common)
{
sceKernelExitGame();
return 0;
}

/* Callback thread */
int CallbackThread(SceSize args, void *argp)
{
int cbid;

cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
sceKernelRegisterExitCallback(cbid);

sceKernelSleepThreadCB();

return 0;
}

/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
int thid = 0;

thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
if(thid >= 0)
{
sceKernelStartThread(thid, 0, 0);
}

return thid;
}
anmabagima
Posts: 87
Joined: Thu Oct 01, 2009 8:43 pm

Post by anmabagima »

Hi,

your example looks very much complicated. I've tried the one delivered with the SDK. This looks more clear to me and I'v already adopted it for my 3D scenes.

I guess some more inline comments would help some times to understand way you are doing certain things in they way you do ;)
a_noob
Posts: 97
Joined: Sun Sep 17, 2006 8:33 am
Location: _start: jr 0xDEADBEEF

Post by a_noob »

In all honesty most scenes can just have baked shadows, then you can just do real time/dynamic shadows on a few select objects that move, saving performance.

Code: Select all

.øOº'ºOø.
'ºOo.oOº'
anmabagima
Posts: 87
Joined: Thu Oct 01, 2009 8:43 pm

Post by anmabagima »

Hi,

did you mean shadow which is precalculated into the textures already ?
This may be difficult as you may need a seperate texture for each object, don't you ?
User avatar
Jim
Posts: 476
Joined: Sat Jul 02, 2005 10:06 pm
Location: Sydney
Contact:

Post by Jim »

If the lights are not dynamic and your objects are tessellated well then you can bake the shadows into the vertex lighting.

Jim
User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

Post by Raphael »

Either that, or if your objects are not tesselated enough to give good enough results, it comes down to lightmapping. In this case, yes, you need seperate (light) texture for each object, but those are relatively low-res, though require a two-pass texturing scheme.
What you thought of was a one-pass scheme, where you'd have to combine the lightmaps into the object textures as a pre-process step. That could waste a lot of memory though for duplicate textures with slightly different lighting, yes.
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
anmabagima
Posts: 87
Joined: Thu Oct 01, 2009 8:43 pm

Post by anmabagima »

Hi,

thanks to both of you. Now I've a clear picture in my mind :o)

Great - maybe I will try that in my currentproject as I've 1 ore 2 lightsources and only 1 moving object ;o)
Visigotico
Posts: 11
Joined: Wed Apr 23, 2008 11:44 am

Post by Visigotico »

Ok, it's complicated and unoptimized because this is only a test code, done in 5 minutes. Actualy I have a optimized (on VFPU) and better code, running at 132 FPS. If anyone has interest...
anmabagima
Posts: 87
Joined: Thu Oct 01, 2009 8:43 pm

Post by anmabagima »

Hi,

sure. I'm interested in, as in my current code I've currently no real clue how to deal with the following issues (may be you have solved them).

Rendering the shadow caster from light point of view results in strange block shadows if the object is far away from light source (due to the resolution of the rendering i guess)

Secondly the usage of texture matrix for rendering of shadow reciever results in shadows applied to an object which is closer to the light than the shadow caster.

Thanks regards
AnMaBaGiMa
Visigotico
Posts: 11
Joined: Wed Apr 23, 2008 11:44 am

Post by Visigotico »

Are you using the SDK samples? The technique I'm using is a little
different, you can read about Shadow Mapping to understand
better how it works, how it should be used and their problems and bugs.
anmabagima
Posts: 87
Joined: Thu Oct 01, 2009 8:43 pm

Post by anmabagima »

Hi,

yes I'm using the SDK samples with some minor adjustments ;)

I've read the article on shadow mapping posted at the beginning of this thread. This is using a multi pass approach which looked very similar to the one implemented in the SDK example. But as I'm a beginner in using GU and all the matrix stuff may be I didn't get the full picture out of this page. The openGL stuff mentioned there as sample code is completely new to me as I've used Direct3D in the past on PC for 3D rendering.

Thanks for any hints as I'm interested more into a "how do I" and I want to understand what I'm doing rather then just copy/paste other once code ;)

Best regards
Post Reply