Skip to: Site menu | Main content


Welcome to PSP-Programming.com, a place for developers to get together.

Welcome to the forums. Here you can find other user tutorials as well as homebrew releases and the source code repository. You can also ask for help with your code here and post your own homebrew!

PSP-Programming.com Forums
February 11, 2012, 01:50:49 AM *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

News: Join our IRC channel: ##psp-programming on freenode
Home Help Search Shop Login Register
Digg This!
Pages: [1]
Print
Author Topic: Sprite Transformations Using GU  (Read 7978 times)
lokust
Full Member
***

Karma: +1/-0
Offline Offline

Posts: 186
0.00 points

View Inventory
Send Money to lokust


View Profile WWW
« on: June 13, 2006, 03:13:21 AM »

[DISCLAIMER: The following is just an observation, and what I have learned so far. I cannot verify 100% whether these methods are better or worse than anything else out there, and I have not done any extensive testing. I also do not claim to be an expert, there may be mistakes, innacuracies, etc. So, be very critical of every detail listed below and of course call me out on anything that looks strange or doesnt make sense!]

This short tutorial will explain how to transform (translate,rotate,scale) "sprites".

[Sprites being 2D images that we draw to the screen and be able to apply said transforms to. I point this out because to the GU sprites (specified by primitive type GU_SPRITE) are always screen-aligned, and when it renders them it completely bypasses the transformation pipeline altogether, which I guess, might be faster sometimes at the cost of flexibility]

^^ That aside, first we must be able to draw our sprite onto the screen. We will represent our sprite as a quadrangle and assemble it as a triangle fan. To do this, we need four *vertices. The order in which we specify the vertices is important, this is known as the winding order. When rendering data, especially 3D data, you want to only draw what is visible, otherwise you are wasting processing time. The easiest way to speed rendering up is to render less data. We can throw away back-facing polygons by adhering to a standard winding order, clockwise or counter-clockwise. We do this with a call to sceGuFrontFace() and pass in a constant that sets the winding order:

GU_CW - Clockwise primitives are not culled
GU_CCW - Counter-clockwise are not culled

This process is known as backface culling, and must be enabled by calling sceGuEnable() and passing in GU_CULL_FACE

When we draw our sprite we it will be centered around the origin, the reason why, will become clear soon. When rendering triangle fans the first three vertices form a triangle and each subsequent vertex creates a new triangle from previous two. Try it out on a sheet of paper if this doesnt make sense!
So all we need to draw our sprite is the width and height, top left texture coordinate (can be thought of as the begining index into the image) and the bottom right uv (can be thought of as the width/height of the image).

Code:

/*
Here we draw a quad with a given width (w) and height (h) around the origin. This way
we can apply translation, scale, and rotation transformations to the modelview matrix
in order to put our image wherever we want.

(0-w/2,0-h/2)                 (w/2,0-h/2)
 *---------------------------*
 |                        .  |
 |                    .      |
 |                .          |
 |          (0,0)            |
 |        .                  |
 |    .                      |
      |.                          |
      *-------------------------- *
(0-w/2,h/2)                   (w/2, h/2)
*/
void CPSPRenderer::DrawImage(float width, float height, float u, float v, float imageWidth, float imageHeight, Image *image)
{
float fHalfWidth = width/2.0f;
float fHalfHeight = height/2.0f;

float fStart = 0.0f-fHalfWidth;
float fEnd = fHalfWidth;
float fStepX = 64.0f;
float fStepU = (imageWidth-u)/width*fStepX;

float fCurU = u;
float fCurX = 0.0f-fHalfWidth;
float fEndX = fHalfWidth;

VertexSprite32F *spriteVerts;
float fSpriteWidth;
float fImageWidth;
for(; fStart < fEnd; fStart += fStepX)
{
spriteVerts = (VertexSprite32F*)sceGuGetMemory(4 * sizeof(VertexSprite32F));

fSpriteWidth = ((fCurX+fStepX) > fEndX) ? (fEndX - fCurX) : fStepX;
fImageWidth = ((fCurU+fStepU) > imageWidth) ? (imageWidth - fCurU) : fStepU;

spriteVerts[0].u = fCurU;
spriteVerts[0].v = 0.0f;
spriteVerts[0].x = fCurX;
spriteVerts[0].y = 0.0f-fHalfHeight;
spriteVerts[0].z = 0.0f;

spriteVerts[3].u = fCurU;
spriteVerts[3].v = -imageHeight;
spriteVerts[3].x = fCurX;
spriteVerts[3].y = fHalfHeight;
spriteVerts[3].z = 0.0f;

fCurX += fSpriteWidth;
fCurU += fImageWidth;

spriteVerts[1].u = fCurU;
spriteVerts[1].v = 0.0f;
spriteVerts[1].x = fCurX;
spriteVerts[1].y = 0.0f-fHalfHeight;
spriteVerts[1].z = 0.0f;

spriteVerts[2].u = fCurU;
spriteVerts[2].v = -imageHeight;
spriteVerts[2].x = fCurX;
spriteVerts[2].y = fHalfHeight;
spriteVerts[2].z = 0.0f;

sceGumDrawArray(GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_3D, 4, 0, spriteVerts);
}
}


Now, before we draw our image we need to set a few very important things.

1. Projection
2. View
3. ModelView

1. Load the projection *matrix. We set the projection matrix to the *identity matrix, and then set an orthographic projection limited to the width and height of the screen. This way we can use screen coordinates to specify our vertex positions.

Code:

sceGumMatrixMode(GU_PROJECTION);
sceGumLoadIdentity();
sceGumOrtho(0.0f, 480.0f, 0.0f, 272.0f, 0.0f, 1.0f);


2. We must set the view matrix, even though our view is fixed and never transformed. I assume this is just because it isnt intialized. We do this by loading the view matrix and setting it to identity.

Code:

sceGumMatrixMode(GU_VIEW);
sceGumLoadIdentity();


3. Transform the modelview matrix to position our object. We can apply transformations to the modelview matrix before we specify objects to be drawn, then, when the vertices are transformed they will first be multiplied by the modelview matrix, then the projection matrix. Applying a transformation to the modelview matrix (or any other matrix for that matter) is as easy as calling the appropriate Gum routine.

Code:

sceGumMatrixMode(GU_MODEL);
// Each time we want to start with a fresh modelview matrix, otherwise we will build off previous transformations. This will set the modelview matrix to the identity matrix.
sceGumLoadIdentity();

// Here we store the current position inside of a 3-component vector
ScePspFVector3 pos = { xPos, yPos, 0.0f };

sceGumTranslate(&pos); // Apply the translation transformation
sceGumRotateZ(u*.01f); // Apply the rotation transformation


All that is left is to draw our object using the above method!

Be sure to take a look at pspgum.h & pspgu.h. There are alot of useful functions for dealing with transformations. One thing that is very handy is to push/pop matrices in order to restore previous transformations. This is useful say, if you are drawing a solar system. The solar system itself can be thought of identity, so when you draw mars, which has two moons, you would want to

1. Push Solar System Matrix on stack (identity)
2. Transform to mars
3. Draw
4. Push Mars Matrix
5. Transform to Phobos
6. Draw
7. Pop Current Matrix (Phobos)
8. Transform to Demois
9. Draw
10. Pop Demois
11. Pop Mars
12. Draw other planets....

I know alot of you are using graphics.c helper library in your current projects, this method should integrate easily but if anyone has trouble with it I might be able to be coerced into adding to graphics.c along with maybe some other useful helper functions. But really, I am working on a more general and flexible library and just trying to share what I learn along the way. Let me know if this helps, makes sense, etc... if it is then Ill keep posting stuff!

Now for the demo Wink

Use R-Trigger to toggle scale/rotation and use Circle/Square/Cross/Triangle to scale/rotate and arrow keys to translate.

Binary
Source


[*1] Vertices are just positions in space. Since we are dealing with 2D objects and setting an orthogonal projection, we only need worry about the (x,y) corrdinate of each point. These points are known as vertices, which together, are used to assemble geometric primitves, such as lines, triangles, triangle strips, etc. Each vertex might have other data associated with it, such as color, (u,v) texture coordinates which are used to map a image to the primitive type at that point, or weights which define the influence of a particular joint in a 3D animation system. Ususally, this data is interpolated between vertices, so if you have a triangle, and set the color of each vertex to red, green, blue respectivley you will see that color blend into each other color at each point. Try it out!

[*2] A matrix is just a grid of numbers and is used in linear algebra for all sorts of calculations. The important thing to know is that matrices can hold transformations, that is translation, scale, rotation.

[*3] A vector is just a single 1D matrix of numbers. Vectors represent things like velocity and magnitute. We can also represent any point in a coordiante space as a vector from the origin (its displacement from (0,0)) so we can represent a position on screen as [x,y,z]. The importatnt thing to know here is that matrices can transform vectors, and that is exactly what we are using them for in this demo. Each vertex is multiplied by the modelview matrix, thus transforming to the correct positions based on the transformations we applied to the modelview.

[*4] The identity matrix represents "no transformation" and looks like this for a 3x3 matrix:

[1 0 0]
[0 1 0]
[0 0 1]

The important thing to know is that anything multipied by the identity matrix is itself, that is a * b = a
Logged

<flashram> we just lack the rock ... everbody is stoned already
<whazilla> i'm the dark Yoda but i speak as the one green


Yeldarb
Miinaturvat Rules!
Administrator
Hero Member
*

Karma: +16/-3
Offline Offline

Posts: 601
4152.65 points

View Inventory
Send Money to Yeldarb


View Profile WWW
« Reply #1 on: June 13, 2006, 03:18:17 AM »

Very nice!  Very Happy

Thanks for all the tutorials/samples you've been doing lately; I haven't gotten a chance to read them throroughly, but they look great!  Mind if (when I get some time) I convert them to tutorial form and put them in the tutorial section where they'll get more attention?
Logged

lokust
Full Member
***

Karma: +1/-0
Offline Offline

Posts: 186
0.00 points

View Inventory
Send Money to lokust


View Profile WWW
« Reply #2 on: June 13, 2006, 03:22:15 AM »

Quote from: "Yeldarb"
Very nice!  Very Happy

Thanks for all the tutorials you've been doing lately; I haven't gotten a chance to read them throroughly, but they look great!  Mind if (when I get some time) I convert them to tutorial form and put them in the tutorial section where they'll get more attention?


Hey, thanks Smile

I suppose it makes sense to have these on the tutorial page ;p So, no - dont mind at all!
Logged

<flashram> we just lack the rock ... everbody is stoned already
<whazilla> i'm the dark Yoda but i speak as the one green
SuperiorIAM
Full Member
***

Karma: +1/-26
Offline Offline

Posts: 116
6015.70 points

View Inventory
Send Money to SuperiorIAM

View Profile
« Reply #3 on: August 17, 2008, 08:09:09 AM »

Quote
Warning: this topic has not been posted in for at least 120 days.
Unless you're sure you want to reply, please consider starting a new topic.

I am Very sorry.  Rolling Eyes

----

Can anyone upload the binaries and src?  The site is down. Sad

This is EXACTLY what I wanted.   Razz
Logged
@rt
You can't just sculpt Willie-Nillie. You've got to go by the book. Follow the rules. Otherwise, you'll never get passed Amateur Hour, here.
Newbie
*

Karma: +0/-0
Offline Offline

Posts: 18
2026.32 points

View Inventory
Send Money to @rt

View Profile
« Reply #4 on: November 09, 2008, 12:16:30 AM »

Bump,,, it would be really nice if someone could re upload this somewhere.
Logged
Yan2Yan
Newbie
*

Karma: +0/-1
Offline Offline

Posts: 12
731.24 points

View Inventory
Send Money to Yan2Yan

View Profile
« Reply #5 on: November 12, 2008, 10:49:29 AM »

Yes, it would be very nice ^^

(please !  Smile )
Logged
Pages: [1]
Print
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!
Page created in 0.38 seconds with 29 queries.
Sister Sites: Guitar Hero 4   BrokeniTouch.com