GLBasic forum

Codesnippets => 3D-snippets => Topic started by: kanonet on 2012-Apr-20

Title: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2012-Apr-20
Introduction:
If you ever wanted to be able to rotate X_SPRITEs or you want them to be faster (so you can create plenty of them, e.g. for a particle engine), than here is a solution for you:
My TSprite can get scaled, rotated and positioned anywhere in the 3D-scene, it will always turn to the camera (like X_SPRITE does), even if you use X_CAMERAUP (for a 6DOF camera). Its all encapsulated into one Type, for easy transfer to your projects. I tested this lib on Windows, Linux and Android, its all working perfectly and I know no reason why it should not work on any other major platform.

You can find newest libQMATH here: http://www.kanonet.de/downloads/libqmath
You always find the latest version on my website: http://www.kanonet.de/downloads/libsprite


Comparison with X_SPRITE:
differences:advantages:disadvantages:

How to use it:
At game start, define the type:
Code (glbasic) Select
LOCAL sprite AS TSprite
In your gameloop render all your GLB 3D stuff, than call sprite.Start(), draw your sprites and texture them, try to use as few X_SETTEXTURE as possible if some sprites use the same texture, just make only one X_SETTEXTURE and draw all sprites that use it (texture ordering). You can call SetTextureCoords() to use a sprite Atlas (and avoid calls for X_SETTEXTURE)! End your sprite drawing with sprite.Stop(). Just use one Start() and Stop() pair each loop and draw all sprites between them. Do not use any GLB OpenGL calls between Start() and Stop()!
Code (glbasic) Select
sprite.Start()
X_SETTEXTURE 0
sprite.Draw()
sprite.Draw()
sprite.Draw2()
sprite.SetTextureCoords()
sprite.Draw()
sprite.Draw2()
X_SETTEXTURE 1
sprite.Draw()
X_SETTEXTURE 2
sprite.Draw()
sprite.Draw2()
sprite.Stop()



Code:
Code (glbasic) Select
// ------------------------------------------ //
// Project: TSprite
// Start: Sunday, July 24, 2011
// Autor: Kanonet
// Last Update: August 22, 2015
// For a newer Version go to: http://www.kanonet.de/downloads/libsprite
// ------------------------------------------ //

TYPE TSprite
INLINE
namespace libSPRITE {
typedef unsigned int    GLenum;
typedef void            GLvoid;
typedef int             GLint;
typedef int             GLsizei;
typedef float           GLfloat;
#ifdef __WIN32__
#ifndef APIENTRY
#define APIENTRY __stdcall
#endif
#else
#ifndef APIENTRY
#define APIENTRY
#endif
#endif
const GLint GL_TRIANGLE_STRIP = 0x0005;
const GLint GL_FLOAT = 0x1406;
const GLint GL_VERTEX_ARRAY = 0x8074;
const GLint GL_TEXTURE_COORD_ARRAY = 0x8078;
extern "C" {
void APIENTRY glNormal3f( GLfloat nx , GLfloat ny , GLfloat nz );
void APIENTRY glColor4f( GLfloat red , GLfloat green , GLfloat blue , GLfloat alpha );
void APIENTRY glEnableClientState( GLenum cap ); /* 1.1 */
void APIENTRY glDisableClientState( GLenum cap ); /* 1.1 */
void APIENTRY glVertexPointer( GLint size , GLenum typ , GLsizei stride , const GLvoid *ptr );
void APIENTRY glTexCoordPointer( GLint size , GLenum typ , GLsizei stride , const GLvoid *ptr );
void APIENTRY glDrawArrays( GLenum  mode,  GLint  first,  GLsizei  count );
}
struct TSpriteContainer {
float texcoord[8];
float vertices[12];
float m0, m1, m2;
float m4, m5;
float m8, m9, m10;
float normalx, normaly, normalz;
int lastnum;
} static TSpr = { {0.0f,1.0f,1.0f,1.0f,0.0f,0.0f,1.0f,0.0f} };
}
ENDINLINE

// start drawing of sprites, call it one time  each loop, before you draw your sprites and call Stop() when you did draw all your sprites
// do not use any normal GLB OpenGL between Start() and Stop()!
FUNCTION Start%:
STATIC mat#[]
X_GETCAMERAMATRIX mat[]
INLINE
using libSPRITE::TSpr;
TSpr.lastnum = 0;
TSpr.normalx = mat(2);
TSpr.normaly = mat(6);
TSpr.normalz = mat(10);
TSpr.m0  =  -mat(0);
TSpr.m4  =  -mat(4);
TSpr.m8  =  -mat(8);
TSpr.m1  =  mat(1);
TSpr.m5  =  mat(5);
TSpr.m9  =  mat(9);
TSpr.m10 =  qInvSQR(TSpr.normalx*TSpr.normalx + TSpr.normalz*TSpr.normalz);
TSpr.m2  =  TSpr.normalx*TSpr.m10;
TSpr.m10 *= TSpr.normalz;
libSPRITE::glEnableClientState( libSPRITE::GL_VERTEX_ARRAY );
libSPRITE::glEnableClientState( libSPRITE::GL_TEXTURE_COORD_ARRAY );
libSPRITE::glTexCoordPointer( 2, libSPRITE::GL_FLOAT, 0, &TSpr.texcoord );
libSPRITE::glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
ENDINLINE
ENDFUNCTION

// draw a spherical sprite (same like X_SPRITE)
// needs to be after Start() [and before Stop()]
// sprite will be midhandled (unlike X_SPRITE)
FUNCTION Draw%: x AS float, y AS float, z AS float, scale#=1.0, rotation#=0.0
INLINE
using libSPRITE::TSpr;
scale *= 0.5;
float rc = qSIN( rotation + 90 ) * scale;
float rs = qSIN( rotation      ) * scale;

float rot = TSpr.m1 * rs + TSpr.m0 * rc;
float xp  = TSpr.m1 * rc - TSpr.m0 * rs;
float xn  = rot-xp;  xp += rot;
TSpr.vertices[0] = x + xp;  TSpr.vertices[3] = x - xn;  TSpr.vertices[6] = x + xn;  TSpr.vertices[9] = x - xp;

rot = TSpr.m5 * rs + TSpr.m4 * rc;
xp  = TSpr.m5 * rc - TSpr.m4 * rs;
xn  = rot-xp;  xp += rot;
TSpr.vertices[1] = y + xp;  TSpr.vertices[4] = y - xn;  TSpr.vertices[7] = y + xn;  TSpr.vertices[10]= y - xp;

rot = TSpr.m9 * rs + TSpr.m8 * rc;
xp  = TSpr.m9 * rc - TSpr.m8 * rs;
xn  = rot-xp;  xp += rot;
TSpr.vertices[2] = z + xp;  TSpr.vertices[5] = z - xn;  TSpr.vertices[8] = z + xn;  TSpr.vertices[11]= z - xp;

if (TSpr.lastnum != 1) {
libSPRITE::glNormal3f( TSpr.normalx, TSpr.normaly, TSpr.normalz );
TSpr.lastnum = 1;
};
libSPRITE::glVertexPointer( 3, libSPRITE::GL_FLOAT, 0, TSpr.vertices );
libSPRITE::glDrawArrays( libSPRITE::GL_TRIANGLE_STRIP, 0, 4 );
ENDINLINE
ENDFUNCTION

// draw a cylindrical sprite (same like X_SPRITE)
// needs to be after Start() [and before Stop()]
// sprite will be midhandled (unlike X_SPRITE)
FUNCTION Draw2%: x AS float, y AS float, z AS float, scale#=1.0, rotation#=0.0
INLINE
using libSPRITE::TSpr;
scale *= 0.5;
float rc = qSIN( rotation + 90 ) * scale;
float rs = qSIN( rotation      ) * scale;

float rot = TSpr.m10 * rc;
float xn  = TSpr.m10 * rs;
float xp  = rot-xn;  xn += rot;
TSpr.vertices[0] = x - xp;  TSpr.vertices[3] = x + xn;  TSpr.vertices[6] = x - xn;  TSpr.vertices[9] = x + xp;

TSpr.vertices[1] = y + rs + rc;  TSpr.vertices[4] = y - rs + rc;  TSpr.vertices[7] = y + rs - rc;  TSpr.vertices[10]= y - rs - rc;

rot = TSpr.m2 * rc;
xn  = TSpr.m2 * rs;
xp  = rot-xn;  xn += rot;
TSpr.vertices[2] = z + xp;  TSpr.vertices[5] = z - xn;  TSpr.vertices[8] = z + xn;  TSpr.vertices[11]= z - xp;

if (TSpr.lastnum != 2) {
libSPRITE::glNormal3f( TSpr.m2, 0.0f, TSpr.m10 );
TSpr.lastnum = 2;
};
libSPRITE::glVertexPointer( 3, libSPRITE::GL_FLOAT, 0, TSpr.vertices );
libSPRITE::glDrawArrays( libSPRITE::GL_TRIANGLE_STRIP, 0, 4 );
ENDINLINE
ENDFUNCTION

// use this if you want to change texture coords
// its way faster to change texture coords instead of changing texture with X_SETTEXTURE
// it will affect all following draw()/draw2() calls, in all following loops!
// default is (0,1, 1,1, 0,0, 1,0)
FUNCTION SetTextureCoords%: t0x AS float, t0y AS float, t1x AS float, t1y AS float, t2x AS float, t2y AS float, t3x AS float, t3y AS float
INLINE
using libSPRITE::TSpr;
TSpr.texcoord[0] = t0x; TSpr.texcoord[1] = t0y;
TSpr.texcoord[2] = t1x; TSpr.texcoord[3] = t1y;
TSpr.texcoord[4] = t2x; TSpr.texcoord[5] = t2y;
TSpr.texcoord[6] = t3x; TSpr.texcoord[7] = t3y;
ENDINLINE
ENDFUNCTION

// call it after you did draw all your sprites
// its not totally necessary to use this function, but strongly recommended
FUNCTION Stop%:
INLINE
libSPRITE::glDisableClientState( libSPRITE::GL_TEXTURE_COORD_ARRAY );
libSPRITE::glDisableClientState( libSPRITE::GL_VERTEX_ARRAY );
ENDINLINE
ENDFUNCTION

ENDTYPE



Test Program:
Code (glbasic) Select
// --------------------------------- //
// Project: TSprite
// Start: Sunday, July 24, 2011
// Autor: Kanonet
// Last Update: September 06, 2013

SETSCREEN 800,600,0
SYSTEMPOINTER TRUE
ALLOWESCAPE FALSE
AUTOPAUSE FALSE
LIMITFPS -1

// number of sprites to draw:
LOCAL count%=1000

LOCAL root%=SQR(count)/2, line%, row%, fps, timer, mx%, my%=15, mz=-4, selected%=1, rot%

// texture
CREATESCREEN 0, 0, 16,16
USESCREEN 0
DRAWRECT 0,0, 16, 16, RGB(0,0,255)
DRAWRECT 12,0, 4,8, RGB(255,127,0)
DRAWRECT 0,12, 4,4, RGB(255,0,63)
DRAWLINE 0,0, 16,16, 0xffffff
DRAWLINE 0,16, 16,0, 0xffffff
USESCREEN -1
CREATESCREEN 0,-1,0,0

// sprite
LOCAL sprite AS TSprite

// mainloop
REPEAT

line=-root; row=-root; INC rot

// mouse for camera control:
mx = mx + MOUSEAXIS(0)
my = my + MOUSEAXIS(1)
mz = mz + MOUSEAXIS(2)
IF KEY(27) // + more sprites
INC count
root=SQR(count)/2
ENDIF
IF KEY(53) AND count>1 // - less sprites
DEC count
root=SQR(count)/2
ENDIF
IF KEY(2) THEN selected=1
IF KEY(3) THEN selected=2
IF KEY(4) THEN selected=3

X_MAKE3D 0.1, 1000, 45
X_CAMERA my*COS(mx)*root*0.2,mz*2,my*SIN(mx)*root*0.2, 0,0,0

X_DRAWAXES 0,0,0
X_CULLMODE 1

LOCAL cx=my*COS(mx)*root*0.2, cy=mz*2, cz=my*SIN(mx)*root*0.2

IF selected=1
FOR i=1 TO count

X_SPRITE 0, 0, line, row, 0.06

INC row
IF row>root
row=-root
INC line
ENDIF
NEXT
ELSEIF selected=2
sprite.Start()
FOR i=1 TO count

X_SETTEXTURE 0, -1
sprite.Draw(0, line, row, 0.5)

INC row
IF row>root
row=-root
INC line
ENDIF
NEXT
sprite.Stop()
ELSE
sprite.Start()
X_SETTEXTURE 0, -1
FOR i=1 TO count

sprite.Draw(0, line, row, 0.5)

INC row
IF row>root
row=-root
INC line
ENDIF
NEXT
sprite.Stop()
ENDIF

X_MAKE2D
ALPHAMODE 0.9
DRAWRECT 0,0,800,60,RGB(70,70,70)
PRINT "CAMERA CONTROL: MOVE MOUSE / MOUSE WHEEL    |    FPS: "+INTEGER(1000/(timer-fps)), 0,0
PRINT "SPRITES CURRENTLY: "+count+"    |    PRESS (+) FOR MORE SPRITES AND (-) FOR LESS", 0,15
PRINT "SELECT: (1) X_SPRITE    |    (2) TSPRITE    |    (3) TSPRITE WITH TEXTURE ORDERING", 0, 30
PRINT "SELECTED: "+selected, 0, 45

LOCAL b1%, b2%
MOUSESTATE mx, my, b1, b2
PRINT "v",mx,my
DRAWRECT 80,80,20,20,RGB(255,127,127)
PRINT "0", 90,90
IF mx>80 AND mx<100 AND my>80 AND my<100 AND b1 THEN selected=1
DRAWRECT 110,80,20,20,RGB(255,127,127)
PRINT "1", 120,90
IF mx>110 AND mx<130 AND my>80 AND my<100 AND b1 THEN selected=2
DRAWRECT 140,80,20,20,RGB(255,127,127)
PRINT "2", 150,90
IF mx>140 AND mx<160 AND my>80 AND my<100 AND b1 THEN selected=3

SHOWSCREEN
  fps=timer
timer=GETTIMERALL()
UNTIL KEY(1)
END



Finally some test results (FPS), done on my T410s (see signature), which have two graphiccards (i can select one to use):
Intel HD Graphics - 1000 Sprites: 46 / 48 / 393
Intel HD Graphics - 2000 Sprites: 24 / 25 / 253
Intel HD Graphics - 3000 Sprites: 16 / 17 / 196
Intel HD Graphics - 4000 Sprites: 12 / 13 / 152
Intel HD Graphics - 5000 Sprites: 10 / 10 / 125
Intel HD Graphics - 7500 Sprites: 7 / 7 / 88
Intel HD Graphics - 10000 Sprites: 5 / 6 / 68
NVidia NVS 3100M - 1000 Sprites: 85 / 459 / 500 (cant do more)
NVidia NVS 3100M - 2000 Sprites: 50 / 256 / 500 (cant do more)
NVidia NVS 3100M - 3000 Sprites: 35 / 175 / 500 (cant do more)
NVidia NVS 3100M - 4000 Sprites: 27 / 134 / 500 (cant do more)
NVidia NVS 3100M - 5000 Sprites: 22 / 110 / 500 (cant do more)
NVidia NVS 3100M - 7500 Sprites: 15 / 74 / 480
NVidia NVS 3100M - 10000 Sprites: 11 / 56 / 370
Title: Re: (faster) sprite with rotation
Post by: Slydog on 2012-Apr-20
Wow, pretty cool stuff!    :nw:
And using Vertex Arrays too!
Great to see how to work with the OpenGL directly, will be referencing this soon.

By looking at the code, it appears to only support full textured sprites, correct?
ie: You can't have your sprites in a spritesheet / texture map?

It is probably pretty easy I suppose to add this support.
You use
Code (glbasic) Select
DIMDATA self.tex[], 0,1, 1,1, 0,0, 1,0
to define your texture coordinates, and you specify to use the entire texture.

You would just need a way to predefine a sprite's texture locations.
And move the 'glTexCoordPointer( 2, GL_FLOAT, 0, self.tex[] )' command to the .Draw() routine.

Code (glbasic) Select
TYPE TSpriteTexture
  tex[]

  // Set uv location by absolute values (between 0 and 1)
  FUNCTION Set: x1, y1, x2, y2 // y goes from bottom to top
    DIMDATA self.tex[], x1,y1,  x2,y1,  x1,y2,  x2,y2
  ENDFUNCTION

  // Set uv location by pixel and texture size (between 0 and texture size)
  FUNCTION SetByPixel: x1, y1, x2, y2, texture_size_x, texture_size_y
    self.Set(x1/texture_size_x, y1/texture_size_y, x2/texture_size_x, y2/texture_size_y)
  ENDFUNCTION

ENDTYPE


And then pass this to a modified .Draw() function:
Code (glbasic) Select
FUNCTION Draw%: x#,y#,z#, scale#=1, rotation#=0, uv AS TSpriteTexture
  glTexCoordPointer( 2, GL_FLOAT, 0, uv.tex[] )
... Remaining function code as is
ENDFUNCTION


Sample code:
Code (glbasic) Select
GLOBAL st_full AS TSpriteTexture  // Use when sprite is the entire texture
GLOBAL st_sprite1 AS TSpriteTexture // Location of sprite 1 in sprite sheet
GLOBAL st_sprite2 AS TSpriteTexture // Location of sprite 2 in sprite sheet
st_full.Set(0,0, 1,1)
st_sprite1.SetByPixel(10,11,  20,21,   256,256)  // Sprite1 is located from pixels 10,11 to 20,21 of a 256x256 sprite sheet
st_sprite2.SetByPixel(40,41,  50,51,   256,256)  // Sprite2 is located from pixels 40,41 to 50,51 of a 256x256 sprite sheet
sprite.Start()
X_SETTEXTURE 0
sprite.Draw(..., st_sprite1)
sprite.Draw(..., st_sprite2) // Sprite1 and Sprite2 share the same sprite sheet
X_SETTEXTURE 1
sprite.Draw(..., st_full)
sprite.Stop()


And ya, please somebody use this to create a particle generator!!!!!!   :good:


[Edit]  The above changes would slow down this somewhat because of the extra 'glTexCoordPointer' call per SPRITE as opposed to per FRAME.  So maybe for a particle generator you woudn't want these changes as speed would be very important, but you'd be limited to using particle textures that are full sprites.  Maybe two versions!  :D

Cool!  Forum Post #666 !!!  :nw::rant:   he he
Title: Re: (faster) sprite with rotation
Post by: kanonet on 2012-Apr-20
Yeah Slydog your right, it only supports full textures (like X_SPRITE does too), but its easy to add it, like you mentioned. Just a correction at possible speed drop: you would not need to set new texture coordinates each sprite, you just need to push new texturecoordinates, when you define a new texture (just put glTexCoordPointer behind X_SETTEXTURE), or when you change animationframe in this sprite sheet (just call it manually in this case). So you would not have to call it too often and so you would not lose to much speed.

In fact glTexCoordPointer is way faster, than X_SETTEXTURE so it would be fastest, if you pack all sprite textures in one spritesheet and just change the texturecoordinates. Would be good for the particle engine too, of cause.

BTW did you try the test program? What are your results like? Cuz i just tested it on only one pc, so would be interesting to see if its useful on other machines too.
Title: Re: (faster) sprite with rotation
Post by: kanonet on 2012-Apr-21
LOL i just realized, that i forgot to include the test program, its a bit pointless, asking for other peoples results, if you dont give them the code.^^
So its in the first post now. :'(
Title: Re: (faster) sprite with rotation
Post by: mentalthink on 2012-Apr-21
HI Kanoket, thanks a  lot about this program.... very very Nice... no doubt I try in my mobile Devices... perhaps can be awesome including in my space Ships...

Thanks a lot...
Title: Re: (faster) sprite with rotation
Post by: Wampus on 2012-Apr-24
Is this faster than drawing sprites using the same sprite sheet (i.e. just one texture) with POLYVECTOR?
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Kitty Hello on 2012-Apr-24
This is like POLYVECTOR, but for 3D scenes. Top work! Put sticky.
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2012-May-30
Was someone able to test this on other graphic cards or mobile devices?

If you dont want to include the hole gl.gbas (cuz its slow to compile), than you can include the following, it contains all opengl calls that are necessary to get it working:
Code (glbasic) Select
// OpenGL calls, only use gl.gbas _OR_ the following:

INLINE
#ifdef CENTERLINE_CLPP
#define signed
#endif
#define OGL ::
typedef unsigned int    GLenum;
typedef void            GLvoid;
typedef int             GLint;
typedef int             GLsizei;
}
extern "C" {
void __stdcall glEnableClientState( GLenum cap ); /* 1.1 */
void __stdcall glDisableClientState( GLenum cap ); /* 1.1 */
void __stdcall glVertexPointer( GLint size , GLenum typ , GLsizei stride , const GLvoid *ptr );
void __stdcall glNormalPointer( GLenum typ , GLsizei stride , const GLvoid *ptr );
void __stdcall glTexCoordPointer( GLint size , GLenum typ , GLsizei stride , const GLvoid *ptr );
void __stdcall glDrawArrays( GLenum mode , GLint first , GLsizei count );
}
namespace __GLBASIC__ {
ENDINLINE

CONSTANT GL_TRIANGLE_STRIP                                  = 0x0005
CONSTANT GL_FLOAT                                           = 0x1406
CONSTANT GL_DOUBLE                                          = 0x140A
CONSTANT GL_VERTEX_ARRAY                                    = 0x8074
CONSTANT GL_NORMAL_ARRAY                                    = 0x8075
CONSTANT GL_TEXTURE_COORD_ARRAY                             = 0x8078

FUNCTION glEnableClientState: cap
INLINE
OGL glEnableClientState(cap);
ENDINLINE
ENDFUNCTION

FUNCTION glDisableClientState: cap
INLINE
OGL glDisableClientState(cap);
ENDINLINE
ENDFUNCTION

FUNCTION glVertexPointer: size, typ, stride, ptr[]
typ=GL_DOUBLE;
INLINE
OGL glVertexPointer(size, typ, stride, &ptr(0));
ENDINLINE
ENDFUNCTION

FUNCTION glNormalPointer: typ, stride, ptr[]
typ = GL_DOUBLE;
INLINE
OGL glNormalPointer(typ, stride, &ptr(0));
ENDINLINE
ENDFUNCTION

FUNCTION glTexCoordPointer: size, typ, stride, ptr[]
typ = GL_DOUBLE;
INLINE
OGL glTexCoordPointer(size, typ, stride, &ptr(0));
ENDINLINE
ENDFUNCTION

FUNCTION glDrawArrays: mode, first, count
INLINE
OGL glDrawArrays(mode, first, count);
ENDINLINE
ENDFUNCTION
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Jun-18
QuoteNow i want someone to create a decent particle engine with this.

Its already built, all i need to do it splice it in.

1. Is this much faster than polyvector?
2. Why is there only one rotation? you need at least 2.
3. Is this a "point sprite"?

If no to #3, do you know how to implement them?
Spritez3d would go from thousands of particles to millions overnight.



Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2012-Jun-18
1. I think you (and maybe Wampus?) got something wrong. Polyvector is for 2D graphic, this code here replaces X_SPRITE, which means its for 3D graphic. So for your 2D SpriteZ stick with Polyvector, but this code could be really useful for a 3D particle engine, because it has everything that X_SPRITE has, plus some extras and way more speed. This is a 3D-Sprite/Billboard, it can be places anywhere in 3D scene and it will always face the camera, no matter where it is. It just shares with polyvectors, that its fast and that you can optimise it with proper texture ordering (like always in 3D, texture ordering is faster than calling X_SETTEXTURE for each object).

2. In 3D scene you have 3 axes, so you need 3 rotations. But this is a billboard, so it autoimatically faces the camera, the hole point in this code is, that it handles the rotation around 2 axes independently, so it always faces the camera, so you dont need to worry about doing this by yourself. So you just need to worry about the 3rd rotation, thats why it is just 1 rotation, like in a 2D scene. Btw this is one of the advantages of this code over X_SPRITE which does not allow you to change this rotation.

3. No this is not a Pointsprite, i render a quad to the scene for each sprite, but i do this way faster, than native GLB could ever do it. A pointsprite is a special GPU feature on more modern graphic cards, so you dont need to render a quad, but just tell the GPU the point where to place the Sprite (its faster). Pointsprites do not work with older graphic hardware and maybe not with mobile platforms, but i dont know in detail how much its supported nowadays. And i dont know how to implement it, was never interested in it, cuz i wanted a solution that run even on old hardware. If you want to get it working, than you will definitely need to use INLINE, and im definitely the wrong person to ask about this, since i have no C skills.
EDIT: i just noticed, that sometimes every billboard is called a point sprite, but in my opinion this is not correct. But if you just mean a billboard, not the special GPU feature for faster billboards, than this is a point sprite, cuz it draws a 2D sprite on a point in 3D world. :D

How do you render your particles in you 3D SpriteZ now? With X_SPRITE or do you draw your own quads/triangles with GLB commands? Anyways, this code here is way faster than both solutions and it works on all PCs with OpenGL 1.1 or higher. I did not try it on a mobile device, since i don have one of them (besides an old Win Mobile phone).

See here for more details: http://nehe.gamedev.net/article/billboarding_how_to/18011/
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Jun-18
I meant, is this faster than the    X_SETTEXTURE / X_DRAWOBJ ?

The quads are still too slow though, no matter which way you cut the cake.
Oh, how it would rock, if it were taking advantage of the gpu. :bed:

the PE only make one quad, and reuse it:

Code (glbasic) Select

FUNCTION EmitterSys_X_CreateSquare: Color
//flat square object, facing +z direction
LOCAL GenObjNum=GENX_OBJ()
X_AUTONORMALS 1 // smooth edges
X_OBJSTART GenObjNum
X_OBJADDVERTEX 0.5,0.5,0, 1,0, Color
X_OBJADDVERTEX -0.5,0.5,0, 0,0, Color
X_OBJADDVERTEX -0.5,-0.5,0, 0,1, Color
X_OBJNEWGROUP
X_OBJADDVERTEX -0.5,-0.5,0, 0,1, Color
X_OBJADDVERTEX 0.5,-0.5,0, 1,1, Color
X_OBJADDVERTEX 0.5,0.5,0, 1,0, Color
X_OBJEND
RETURN GenObjNum
ENDFUNCTION


This is the draw commands:

Code (glbasic) Select

FUNCTION EmitterSys_X_Trans3d: x,y,z , Scale , rx,ry,rz //move,scale,rotate an object
// This function Handles 3d inputs for,
// Move, Scale, Rotate for 3d objects.

X_MOVEMENT x,y,z
X_SCALING Scale, Scale, Scale
IF rz<>0 THEN X_ROTATION rz,0,0,1
IF rx<>0 THEN X_ROTATION rx,1,0,0
IF ry<>0 THEN X_ROTATION ry,0,1,0

RETURN TRUE //pass completed, return=1 (BOOL=TRUE)
ENDFUNCTION


Code (glbasic) Select

FUNCTION EmitterSys_X_DrawObj: ID , Texture1 , Texture2 , ShaderID // ID, Tex id1 , Tex id2, Shader
// This function Handles 3d inputs for,
// Shaders, Textures, Drawing for 3d objects.
//
// Shaders:
// To use a shader, you must create a SUB.
// The shader SUB MUST be named the same name in GLM_X_LoadShader: shadername$

//beta
IF ShaderID>0
X_SETSHADER ShaderID
sid$=ShadersArray$[ShaderID-1]
ProcessShaderInputsSUB = 1//CALLBYNAME(sid$) //1 will override
IF ProcessShaderInputsSUB = FALSE
GLM_2d_Window("GLM_X_DRAWOBJ")
PRINT "Sub not found" ,100,300
GLM_2d_Window_Sleep(3000)
END
ENDIF
ENDIF

X_SETTEXTURE Texture1 , Texture2
X_DRAWOBJ ID, 0
X_SETSHADER 0
RETURN

ENDFUNCTION


Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2012-Jun-18
My code here is faster than your approach, cuz im using glDrawArrays without any matrix manipulation. For maximum speed pack all your particle textures together into one texture, move the texture coordinates and call just one single X_SETTEXTURE before you draw all your particles. Just use my test program and extend it with your drawing routines to see how much faster it runs.
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Jun-20
hmm, im having trouble getting your sample running  :rant:
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2012-Jun-20
If you give more details, i may be able to help you.
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Jun-20
Compile it, let me see it run.
I dont know how to use your code.
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Jun-20
I cant just add it to my lib...i have over 4000 commands to sort out :P
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2012-Jun-20
If you dont want to copy it together from this posts here, download full lib from my website (http://www.kanonet.de/downloads/libsprite), copy test program from here, add lib and run it.

Btw come to IRC if you want.
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: djtoon on 2012-Nov-15
when i try to compile to iphone i get this
/cygdrive/q/Compiler/platform/iPhone/bin/arm-apple-darwin9-libtool: file: gpc_temp2.o has no symbols
/cygdrive/c/Program Files (x86)/GLBasic/Compiler/platform/iPhone/bin/arm-apple-darwin9-libtool: file: C:\Users\dan\AppData\Local\Temp\glbasic\output.obj(gpc_temp2.o) has no symbols
any ideas? whats wrong?
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2012-Nov-17
I have no idea. I dont have an iDevice and i never compiled something for one. So i just dont know. In theory this here should work on iPhone if you have all dependencies, but i have never tested it on iOS. I just tested under Windows and Linux and if i remember right someone else tested under Android(?). Had you compiled with native opengl calls before? Sorry that i cant help you here, hopefully someone else can.
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Nov-17
I'm giving this another whirl.and im trying to put it all together and get errors.


this is a bug report.

using the pieces libsprite and libmath on your website, and the gl.gbas that you indicated at the top of the thread.
I unremarked the define in the libSprite, so that this is declared:
Code (glbasic) Select
?DEFINE gl_gbas 1

I downloaded this from your website: libSPRITE.gbas libMATH.gbas

I get this error message:
Quote"..\..\KanonetLibs\libSPRITE.gbas"(26) error : syntax error

Inside the TYPE TSprite, the arrow is pointing to this symbol in the first INLINE:
Code (glbasic) Select
}im using ver.10.238

I know you put together a package, i dont know why i like to do things the hard way, but i thinkfound a bug.
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Nov-17
sorry for the spam :P

BTW, which is newer? thread code or the one on your site?

ps. this is what specifically caused the exception:
}
       extern "C" {
}
       namespace __GLBASIC__ {


More about using the lib after I infused libSPRITE with Spritez3d tonight..

Something is not right.
They dont move after they have been placed once.
They are scaled way too large.
And they dont rotate.

Im doing  asmall test where it is set to handle only one emitter.
It was very easy to setup, init in header, start, draw(xyzsr), stop
But for some reason they dont do anything.
I had to declare the sprite as a global, because of the scope didnt work with local in the header.
The call to draw, is in a function, in a for loop.
This shouldnt matter but hey idlike to see this thing work....the variables passed into the sprite.draw(x,y,z,s,r) function call are are declared local in my function and scope into the for loop no problem.

The particle engine runs great as it were, i dont think there is any problem with how i am implementing it because i did exactly how you did your array of particles in your sample....the only real main  betwen your sample and my routine are:
1GLOBAL sprite
2draw is in a function in a for loop
3they move and change scale dynamically.


I am almost ready to publish it, but i was hoping to make a few final tweaks for speed.


Which lib should i be using?


Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2012-Nov-17
Thank you for your feedback. ;)

1st: all my libs have a version date in the header so you always know which one is newest. Unfortunatly i forgot to add that header in the start post. :'( But in this Thread was a very old version and you always find the newest version on my website (its easier to maintain than several threads). I update 1st post.

2nd: you found something strange there. It did work with the earlier V11 beta that i used to create it. But i seems that its not allowed to do it that way in V10 and the current V11 beta. Strange, but easy to fix, just get new version. Btw. if you dont need gl.gbas, dont use it, my INLINE is a tiny bit faster - and it compiles faster too. ;)

3rd: Scale factor is differently calculated from the original X_SPRITE one, which is why you dont get particles in the same size without tweaking scale#.
X_SPRITE: scale=1 is based on texture size (and screen resolution?), so if you decide to use a higher resolution texture your sprite gets bigger!
my replacement: scale=1 is always 1 unit in 3D world, no matter what texture size you've got. In my opinion this is more useful and more logical. Just call it with the absolute size that you want your particle to be.

4th: when i use the test program from 1st post i can not confirm your problem. Scale ->see 3rd and rotation works perfectly for me. Btw. you need to keep in mind that you dont tell the sprite to turn/rotate, you call it with the absolute rotation that you want! So if you call it one time with 30 and next time with 30 again it will be stucked at 30°! If you want to turn it you need to do this manuall, like: call it with 30 1st time and with 60 next time, so you get  a rotation.
Just for you the test program from 1st post, but with rotation:
Code (glbasic) Select
// --------------------------------- //
// Project: TSprite
// Start: Sunday, July 24, 2011
// Autor: Kanonet
// Last Update: November 17, 2012

SETSCREEN 800,600,0
SYSTEMPOINTER TRUE
ALLOWESCAPE FALSE
AUTOPAUSE FALSE
LIMITFPS -1

// number of sprites to draw:
LOCAL count%=1000

LOCAL root%=SQR(count)/2, line%, row%, fps, timer, mx, my=15, mz=-4, selected%=1, rot%

// texture
DRAWRECT 0,0, 16, 16, RGB(0,0,255)
DRAWRECT 12,0, 4,8, RGB(255,127,0)
DRAWRECT 0,12, 4,4, RGB(255,0,63)
DRAWLINE 0,0, 16,16, 0xffffff
DRAWLINE 0,16, 16,0, 0xffffff
GRABSPRITE 0, 0,0, 16,16

// sprite
LOCAL sprite AS TSprite
sprite.Init()


// mainloop
REPEAT

line=-root; row=-root; INC rot

// mouse for camera control:
mx = mx + MOUSEAXIS(0)
my = my + MOUSEAXIS(1)
mz = mz + MOUSEAXIS(2)
IF KEY(27) // + more sprites
INC count
root=SQR(count)/2
ENDIF
IF KEY(53) AND count>1 // - less sprites
DEC count
root=SQR(count)/2
ENDIF
IF KEY(2) THEN selected=1
IF KEY(3) THEN selected=2
IF KEY(4) THEN selected=3

X_MAKE3D 0.1, 1000, 45
X_CAMERA my*COS(mx)*root*0.2,mz*2,my*SIN(mx)*root*0.2, 0,0,0

IF selected=1
FOR i=1 TO count

X_SPRITE 0, 0, line, row, 0.06

INC row
IF row>root
row=-root
INC line
ENDIF
NEXT
ELSEIF selected=2
sprite.Start()
FOR i=1 TO count

X_SETTEXTURE 0, -1
sprite.Draw(0, line, row, 0.5, rot)

INC row
IF row>root
row=-root
INC line
ENDIF
NEXT
sprite.Stop()
ELSE
sprite.Start()
X_SETTEXTURE 0, -1
FOR i=1 TO count

sprite.Draw(0, line, row, 0.5, rot)

INC row
IF row>root
row=-root
INC line
ENDIF
NEXT
sprite.Stop()
ENDIF

X_MAKE2D
ALPHAMODE 0.9
DRAWRECT 0,0,800,60,RGB(70,70,70)
PRINT "CAMERA CONTROL: MOVE MOUSE / MOUSE WHEEL    |    FPS: "+INTEGER(1000/(timer-fps)), 0,0
PRINT "SPRITES CURRENTLY: "+count+"    |    PRESS (+) FOR MORE SPRITES AND (-) FOR LESS", 0,15
PRINT "SELECT: (1) X_SPRITE    |    (2) TSPRITE    |    (3) TSPRITE WITH TEXTURE ORDERING", 0, 30
PRINT "SELECTED: "+selected, 0, 45

SHOWSCREEN
  fps=timer
timer=GETTIMERALL()
UNTIL KEY(1)
END

Or more in general: they do not move/ rotate/ scale, you call them with the absolute position, rotation, scaling. If you want to move it,you need to do this in your engine and just call the sprite with absolute positions, same like you do with XSPRITE.  8)

5th: If you just draw the sprites in one function you can keep sprite local. But if you call it in different functions you need to make it global, or create a local sprite type for each function. You need to try for your self whats faster in your case. Btw. if you really want to speed up things, you need to use texture ordering (or just one texture atlas for all particles), X_SETTEXTURE is slow, so try to use it as few as possible. If you use an texture atlas with all particles in one sprite you save much speed. I can write you a function to change texture coordinates like with POLYVECTOR in 2D, this is faster that X_SETTEXTURE, but if you still sort your particles to avoid unnecessary function calls it would be even faster, obviously.

Hope this helps you. =D
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Nov-18
Ok crash fixed...

The only problems are, alpha and cameraup isnt matching.

Edit: Nice work btw kano, it is an IMPRESSIVE amount faster!
Running 15k particles is WAY overkill for any effect, but thats about the max amount of total particles i can run on my slow machine, without dropping below 30fps.
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Nov-18
Any idea why the alpha isnt working kano?
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: djtoon on 2012-Nov-18
what about compile for the iphone? any ideas?
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Nov-18

Try the new libSPRITE.gbas on his site.
And try using OpenGLES (http://www.glbasic.com/forum/index.php?action=dlattach;topic=7801.0;attach=4797) i think this is for mobile devices...i really dont know if iphone uses it or not though.


Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2012-Nov-18
@Hemlos: uff many posts you gave me there...

1. Nice you got it to work and gratz on your speed increase! Yes i think 15k Particles should be enough.  :P
Btw. thank you for your kind words. I will be happy to see it used in a working particle engine.

2. What is the problem with alpha value? Do you change alpha with ALPHAMODE or using alphachannel on your texture? Or both? Can you please send me one of your textures that has problems (and maybe a short description) so i can have a look on it?

3. I cant confirm your problems with cameraup, i tested it before i published it in the first time and now i tested it again, and it definitely works perfect no matter how i spin around the camera. Not sure, but maybe your problem is related to the following:
Quote from: Hemlos on 2012-Nov-17I assumed the rotation was done for me, like x_sprite ;)
No worry here, i have the vector for this already calculated.
I dont really understand what you mean with this. The rotation gets done for you! You just need to input the rotation angle in degrees, it automatically calculates the rotation vector (and complete matrix), its designed to work without bothering you with evil math. If you input an already precalculated vector (how do you do this?!?), thinks will go horribly wrong! If you did it that way it would explain why your up vector does not work properly.


@djtoon: sorry cant help you there. Btw. which way did you use it, with gl.gbas or without (maybe try both, dont forget the ?DEFINE)? Can you try to just compile my test program for iphone (just change resolution)?
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Nov-19
Quote
2. What is the problem with alpha value? Do you change alpha with ALPHAMODE or using alphachannel on your texture? Or both? Can you please send me one of your textures that has problems (and maybe a short description) so i can have a look on it?
I use both.

QuoteBtw. you need to keep in mind that you dont tell the sprite to turn/rotate, you call it with the absolute rotation that you want!

Edit: ah this statement confused me."absolute rotation"....that input you is to rotate on the local z axis.
And this i put back to 0, and it works as expected.....not sure why i needed to do this, earlier tests showed improper roations, now they work fine.

And about the alpha more...i use a color input to color my old quads vertices so they can be used without a texture and be dynamically colored.
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: djtoon on 2012-Nov-19
on iphone i get the error in somecode
in

GLrunVertexSumbitARM
weird bug that pops up in the xCode debugger

:(
i was wishing to see if i could get a speed boost in my game
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Nov-19
@Kano: I ran my first test demo for 8 hours straight without a problem, no memory leaks or anything, working good.
I was looking around on the net, i noticed there is another command that can be used with the glarrays, a color command, any idea how to implement it?
I think this might be why there is a difference with brightness and color.

@djtoon: did you try to use the opengl.gbas gles version too? Did you try without that file, and use the builtin code?
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: djtoon on 2012-Nov-20
yes
dosent work...
cant figure it out.
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Nov-20
@djtoon: sorry man, i wish i knew about it more.

@kanonet:

Yoo hoooo Kano, Draw2() here


Code (glbasic) Select

// Cylindrical Billboards
// This billboard will only be rotated on Y axes, when the camera moves(not when camera rotates).
// This billboard is rigid on the Y axes, it only rotates facing the camera position.
// When the camera looks around(rotates), the billboard won't move.
// Is this method faster? I dont know. Its good for trees and lightning =D
// This billboard is mid handled.
// X,Y,Z are the billboard xyz coords
// CameraX, CameraY, CameraZ are the camera position
// Scale is absolute, in metric opengl coordinates 1:1, it will increase billboard size.
// rotation shouldnt need to be used, but you can use it to spin the billboard.
// use X_SETTEXTURE #,-1 to set the billboard image after you call type.start()
// -Neil Silver, aka Hemlos on GLBasic forums, hemlos@ymail.com
FUNCTION Draw2%: X#,Y#,Z#, CameraX#, CameraY#, CameraZ#, scale#=1.0, rotation#=360.0

LOCAL CMX#, CMY#, CMZ#, pwidth#, nscale#, pscale#, angx#, angy#
LOCAL vx1#, vy1#, vz1#, vx2#, vy2#, vz2#, vx3#, vy3#, vz3#, vx4#, vy4#, vz4#
rotation=rotation-45.0
angy=angy-(qATAN2((X-CameraX)*-1.0,(Z-CameraZ)*-1.0)-90.0)
width=scale*0.5; nscale=-width; pscale=width
vx1=qSIN(rotation)*qSIN(angy)*pscale; vy1=qCOS(rotation)*pscale; vz1=qSIN(rotation)*qCOS(angy)*nscale
vx2=qCOS(rotation)*qSIN(angy)*pscale; vy2=qSIN(rotation)*nscale; vz2=qCOS(rotation)*qCOS(angy)*nscale
vx3=-vx2; vy3=-vy2; vz3=-vz2; vx4=-vx1; vy4=-vy1; vz4=-vz1

self.vertices[0] = vx1 + X; self.vertices[1] = vy1 + Y; self.vertices[2] = vz1 + Z
self.vertices[3] = vx2 + X; self.vertices[4] = vy2 + Y; self.vertices[5] = vz2 + Z
self.vertices[6] = vx3 + X; self.vertices[7] = vy3 + Y; self.vertices[8] = vz3 + Z
self.vertices[9] = vx4 + X; self.vertices[10]= vy4 + Y; self.vertices[11]= vz4 + Z

?IF DEFINED( gl_gbas )
glVertexPointer( 3, GL_FLOAT, 0, self.vertices[] )
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 )
?ELSE
INLINE
glVertexPointer( 3, GL_DOUBLE, 0, &this->vertices(0) );
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
ENDINLINE
?ENDIF
ENDFUNCTION


Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2012-Nov-21
Just a recap on that function i added to the libSPRITE:

It is a cylindrical billboard, meaning it only rotates on Y axes for Trees, grass, and stuff like that.

It is 3-4 times slower than Draw().
It is still twice as fast as using a quad.

Kano you can rewrite that function and add it to your lib if you want, that function will work immediately if you stick it underneath draw()
However, you might want to rewrite it for better speed considering variables, i tried myself and didnt see any difference in speed.



Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2012-Nov-21
Im almost done with rewriting it, since i was always thinking about adding cylindrical billboards, but was to lazy. :P
Btw. feel free to join me in IRC.
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2012-Nov-22
Ok, new version is online (1st post+website), now there are two drawing functions:
draw()   -> spherical billboard, same like x_sprite, but with rotation
draw2() -> cylindrical billboard, use it for trees etc., can rotate too
I also did rewrite parts of older code, so there is a slight change for a tiny speed improvement, but dont quote me on that.
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2013-Sep-07
(sorry for triple post)

I finally updated the lib, its working on mobile devices now. I tested it on Android, but it should also work on iOS, also Windows and Linux are tested, Mac should work too. Also I did rewrite and encapsulated it better, so that it will never make any problems, if you decide to use it together with some other native OpenGL calls/libs, code looks a bit ugly now, but its all running fine and was definitely worth it. Please note, that the Stop() function is back.
And the 1st Post got updated, cause the informations there became a bit outdated since the initial release of this lib. You find all you need in 1st Post. ;)
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2015-Aug-11
APE goes faster now Ooo Ooo Ooo
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: UBERmonkeybot on 2016-Feb-17
The download link is dead. :'(
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: Hemlos on 2016-Feb-18
The source code in the first message looks legit.
I think i have the latest files here, i put them in a .rar

edit: removed file from message, too old
Title: Re: X_SPRITE replacement - (faster) 3D sprite with rotation (billboards)
Post by: kanonet on 2016-Feb-18
Yes sorry my side is still down. But the code is also in 1st post, this should be the latest version.