Move individual quads in a single surface system

Blitz3D Forums/Blitz3D Beginners Area/Move individual quads in a single surface system

Nexus6(Posted 2012) [#1]
Hi, Ross. I'm having trouble with............ ;)

Sorry Thundros, couldnt resist it.

Back on track, I want to create approx 200 quads in a single surface and be able to move each one individually. This is were im struggling, ive gone through the docs and i think the Vertexcoords command is the key to this but the docs are a bit thin on its usage. Any help is appreciated.

I dont want to bring up the old "mine is bigger than yours" debate regarding single surface systems v's entities/sprites (mine is by the way) but in this instance will i see much difference if i create a quad in a modelling app and then just copy it 200 times?

Thanks guys.


Yasha(Posted 2012) [#2]
VertexCoords is used to set the position of a vertex. The position is in terms of the entity's local space. All you have to do to move or otherwise transform a quad in a single-surface system is work out where its verts should go relative to the base mesh, and position them using VertexCoords. (Triangle data is entirely composed of which-vertices-make-it-up, so the polygon will effectively update itself, and the UVs will be unmodified.)

The easiest (not the fastest) way to do this is to use a pivot to represent your particle (or whatever) object, correctly parented and so on to represent the movement of the particle (so not taking account of the single surface's root mesh unless the particles happen to be intended to move relative to it). You can then position, scale, rotate this pivot as you would if you wanted to move the particle itself. When the time comes to draw the quad, you can use TFormPoint from where-the-corners-would-be in pivot space (probably X+1/Y+1; X+1/Y-1; X-1/Y-1; X-1/Y+1), to surface entity space, and supply those TFormed values to VertexCoords which will update the surface with the quad now in the right place.

(This is the simplest and most general way to do it, but wasting a whole entity per quad may add up for very large systems. You'll be able to optimise this concept considerably depending on exactly what it is you want to do.)

Last edited 2012


Ross C(Posted 2012) [#3]
Well, just for moving quads, just keep a type collection, or an array, of the first vertex of the quad. Yasha's method about the quad is good.

Type quad
   Field first_vertex
End type


Otherwise, you can use cos/sin to rotate the 4 points about their centre. If you do it this way, you need to do the Z axis first, then x axis, then the y axis.

If you want all you quads to face the camera, the easiest way is to create them facing the camera, then parent the mesh to the camera. Every frame you simply reset to position of each quad, and the actual rotations are performed for you.


Kryzon(Posted 2012) [#4]
The method Yasha described is the same used by the open-source Devil Particle System:

http://devil-engines.dev-ch.de/devil-particle-system

They say the code archives have additional single surf. stuff.

EDIT:
will i see much difference if i create a quad in a modelling app and then just copy it 200 times?

There'll be a clear difference. 200 surfaces will be much slower than 200x2 triangles all under the same one.

Last edited 2012


Nexus6(Posted 2012) [#5]
Sorry im a bit late, but thanks guys. Ive steered clear of types like the plague, just something i could never get my head around, but it looks like ive got a bit of reading to do this weekend.


Adam Novagen(Posted 2012) [#6]
Definitely read up on Types, and feel free to ask us as many questions as you need. Types are generally acknowledged as the most challenging and obfuscated element of Blitz3D, but they're also arguably the most useful.

To sum up the basic principle of Types, think of this:

Let's say you want to have some balls (lol) bouncing around. Each ball might need to keep track of, say, three variables: X/Y coordinates, and colour. A very early programmer would likely manage them like this:

ball1x = 5
ball1y = 2
ball1colour = red

ball2x = 10
ball2y = 13
ball2colour = green

; Etc

A more experienced programmer would probably use an array, like this:

Dim balls(100,3)

That would make the code much more compact and efficient. The problem, however, is that the array would be of a finite size. If you only had one ball, the array would still be taking up the memory for 100 of them, and you wouldn't be able to have more than a hundred balls.

Types solve this problem by attaching several variables - called "fields" - to a single name or identifier, called the "instance name." For the balls, it would look like this:

Type ball
    Field x,y
    Field colour
End Type

You would then make as many balls as you needed - and ONLY as many as needed - like this:

ball.ball = New ball

ball\x = 5
ball\y = 32
ball\colour = blue

The ball.ball = New ball line is more complicated than shown, but there's no need to go into that for the moment. The three lines after it are important, though. The backslash is the significant bit; the word ball before the backslash means that Blitz is looking at the ball that was last created or used. AFTER the backslash is the name of the variable that needs to be altered. So if you had a Type named "box," and needed to change a "width" field, you'd do this:

box\width = 3.5

That's how a single Type works, at least in the most simplified manner. But I'm sure you can see that this is no better than using the original method of ball1x, ball2x, etc. The real power of Types lies in their ability to be used as a group, like this:

For ball.ball = Each ball
    ball\x = ball\x + 1
    ball\y = ball\y + 2
    Oval ball\x - 8,ball\y - 8,15,15
Next

This is the For...Each...Next loop, and it's insanely useful. Types are basically the heart and soul of any halfway decent Blitz program, and this loop is how they're used 90% of the time. What it does is go through each instance of the specified Type. In other words, here in this example it loops through each and every ball, moves it, and then draws it. The main benefit of the F-E-N loop is that it you never need to know how many Types there are to make it work. This loop will go through all of the balls, no matter how many; they can be added or removed at any time, with virtually no limit on their total number. If there are no balls in existence, then the loop simply skips and the program carries on.

The final thing to know about Types is that to get rid of one, you would use the Delete command, like this:

For ball.ball = Each ball
    ball\x = ball\x + 1
    ball\y = ball\y + 2
    Oval ball\x - 8,ball\y - 8,16,16
    
    If ball\x > 50
        Delete ball
    EndIf
Next

There's loads more to them than that, but that's the best I can do at explaining Types in the simplest terms possible. Hope it helps!

Last edited 2012

Last edited 2012


RemiD(Posted 2012) [#7]
Interesting topic. :)


There'll be a clear difference. 200 surfaces will be much slower than 200x2 triangles all under the same one.



Kryzon>>I understand this, but what if i use copyentity(Mesh) to copy 1 mesh with 1 surface in order to display 1000 particles ?

Will it be considered as 1 mesh with 1 surface or as 1000 meshes with 1000 surfaces ?

How Blitz3d manages this ?



Then, suppose i do the exact same thing as explained before, but i also use EntityColor(Mesh,R,G,B) and/or EntityAlpha(Mesh,A) and/or EntityFx(Mesh,Fx), in order to modify the appearance of each particle.
In a modeling software this will be considered as adding a new material and i guess a new surface for each mesh.

How Blitz3d manages this ?

Thanks,

Last edited 2012

Last edited 2012

Last edited 2012


Ross C(Posted 2012) [#8]
It think it uses something called referencing. But, I think when you texture the entity differently, you do away with a reference copy. I'm not 100% sure how that works, but single surface stuff is still faster, and to be honest, it's not that much harder. Once you set up functions for doing the dirty work, it can be as easy as entities.


Function MoveQuad(quad_number,x,y,z)

;Moving the quad code in here

End function


The only drawback is the fact you need one texture for all of the quads in that surface, so you will have to combine textures into the one. Oh, and remember to leave a couple of pixel border round each tile if you are doing this, as bilinear filtering blends together the texels and you get blurring from adjacent tiles.


Matty(Posted 2012) [#9]
Copying a mesh with the copymesh command only copies a mesh and the properties of the mesh like its surface and brushes. An entity can comprise multiple meshes as well as non mesh entities like pivots, cameras, lights in a hierarchy so copying the entity in the case of copying a quad with a surface ie an entity which is only a mesh will duplicate both the mesh and surface. So in example above you would indeed have 1000 surfaces and meshes.


Note the addmesh command, when used in conjunction with a mesh copied with copymesh can reduce surface count by collapsing the surfaces into a single surface for identical mesh surface properties. However you then lose the ability to manipulate the copy at the entity level.

Important to remember the difference between an entity and a mesh. A mesh can be part of an entity and an entity can be made up of lots of different entities some of which are meshes.


Yasha(Posted 2012) [#10]
hat if i use copyentity(Mesh) to copy 1 mesh with 1 surface in order to display 1000 particles


As RossC said, this will be faster than copying the whole thing using CopyMesh, but slower than a single-surface traditional system where you move the quads via VertexCoords.

Texture, alpha, colour etc. and all brush properties can be applied in two places: to the whole entity, and to individual surfaces. So sharing one surface reference across several entities is all very well, but even though you get a huge speed boost by only having to upload that surface data once, the renderer still has to individually upload every bit of data that will modify how the surface data is drawn when its entity comes around. Two entities with different scale, rotation and alpha will be drawn differently, and that entity data (both brush, and transformation) has to be applied during the drawing process. So this still means looping over every entity and uploading a brush and a TForm for each particle.

In contrast, using a pure single-surface system, the alpha, scale etc. is all already held in the vertex data within the surface (verts can have colour and alpha if you set the right EntityFX, by the way). You have to have one upload for the surface data which then includes all the scale and colour and position data for all the particles in that single block; and you have to upload one entity brush and one entity transform for the root particle-surface-mesh-object-thingy only.


RemiD(Posted 2012) [#11]
Thanks for your answers guys, i understand it better now.


You have to have one upload for the surface data which then includes all the scale and colour and position data for all the particles in that single block; and you have to upload one entity brush and one entity transform for the root particle-surface-mesh-object-thingy only.



Yasha>>I see, so i have to make one brush (a kind of material) that i apply to one mesh with one surface, and then i can use the vertices functions to set their positions, colours, alphas.

This means that if i have 2 kinds of particles which need 2 different materials, i have to create 2 different brushs and 2 meshes with one surface each, so that i can have 2 single surface particles systems.

Am i correct ?

Last edited 2012


Yasha(Posted 2012) [#12]
Probably. It depends what you want - different brush effects (e.g. shininess), then yes; if the only difference is texture, you could simply have two texture-areas within a single atlas texture and keep it to one surface.

Note that one mesh can have many surfaces, so you still only need the one mesh, unless you also want to take advantage of some property unique to entities. (Whatever's simpler, though.)


RemiD(Posted 2012) [#13]

if the only difference is texture, you could simply have two texture-areas within a single atlas texture and keep it to one surface.



Yes good idea !