SFML community forums

Help => Graphics => Topic started by: gsaurus on February 12, 2010, 04:23:30 pm

Title: a tree of geom transforms
Post by: gsaurus on February 12, 2010, 04:23:30 pm
I just wanted to make sure this is right.

I want to render a composed object by applying a tree of 2D geom transformations before rendering the leafs (like on VRML, openGL, etc, but only using SFML).
So I'm going to extend a class from Drawable that owns other drawable objects. On the render function I call the draw of the children drawables.
The leafs are sprites, text, etc.
This will work just perfect, right?
Title: a tree of geom transforms
Post by: Laurent on February 12, 2010, 04:25:28 pm
Yes sir.
Title: a tree of geom transforms
Post by: gsaurus on February 21, 2010, 12:26:01 pm
Ok, I have my drawable objects tree, but I got confronted with one thing:

I want to flip my whole tree of drawables by scalling it's root by -1. But sf::Drawable::SetScale methods only accepts positive values.
With this limitation, I'll have to multiply all the drawables translations by -1, change their centers and flip sprite images all over the tree! :(

We can flip a sprite image, but we can't actually flip a sprite over it's center. To do that we have to flip the image and change the center to size-center.
It's also impossible to flip a sf::String :(

I wish this positive check doesn't exist and let the user decide whether a negative scale can be useful or not, or give a "Mirror" method to sf::Drawable in case the Scale theoretical concept is being considered to be always a positive thing.
Title: a tree of geom transforms
Post by: Laurent on February 21, 2010, 12:29:10 pm
Negative scales have some bad consequences on coordinates, and may create inconsistencies.

However I'll think about it, negative scale may indeed be very useful in certain situations.
Title: a tree of geom transforms
Post by: gsaurus on February 21, 2010, 01:44:56 pm
Thanks
I'll implement a workaround somehow..

Edit:
I understand about possible inconsistencies (maybe a mirror concept helps?), but what bad consequences on coordinates do you say?

I tried applying my own scale factors on a Drawable derivated class, on the Render method by using glScalef before rendering the children drawables. On first tests it's looking ok.  :roll:
Title: a tree of geom transforms
Post by: Laurent on February 21, 2010, 02:47:34 pm
Yes, it works perfectly fine. The inconsistencies I'm talking about are not visual, it's more about how this will affect the other functions.

I have no example to tell you right now, but I remember that it was why I added this limitation on scales.
Title: a tree of geom transforms
Post by: gsaurus on February 21, 2010, 04:31:36 pm
Quote from: "Laurent"
how this will affect the other functions.

If you remember of something, let me know  :wink:
Title: a tree of geom transforms
Post by: Laurent on February 21, 2010, 06:32:52 pm
Sure :)
Title: a tree of geom transforms
Post by: gsaurus on February 23, 2010, 08:33:11 pm
Ok, I think I found the problem: the rotation transform (I was suspecting it was that)
If all transforms are set at once on the modelview, the final result with a negative scale isn't symmetric, because the rotation is performed after the scale (or something like that).

This morning I tried to fix it by defining and applying my own matrices, but I still didn't solved it completely. It's working only when the origin is (0,0). But I hadn't much time to work on it yet...
It was a long time since I learnt openGL at univ, so I don't remember well this things and how to solve it. But you should know better than me :wink:

This is also :?, I work on my engine on scare free times, but now I got this limitation to work around, slowing down my project a bit more :(
I could try to solve it ad hoc, but I'm not sure whether I'll need other methods (like transformToLocal), best would be to solve it once and for all  :roll:

Here, an example:
2 images with origin (0,0), position (100,100), and both rotated by 45ยบ. One has scale (1,1), the other has scale (-1,1)

(http://img97.imageshack.us/img97/2889/wronginverse.png)(http://img52.imageshack.us/img52/3724/rightinverse.png)

Left: Applying all transforms at once on the modelview matrix.
Right: Applying everything but rotation first, then rotation. (not working yet for different origins..)
Title: a tree of geom transforms
Post by: Laurent on February 23, 2010, 08:49:27 pm
Quote
If all transforms are set at once on the modelview, the final result with a negative scale isn't symmetric, because the rotation is performed after the scale (or something like that).

It is symetric, because rotation is applied after the scale. It works just fine, and I don't think that negative scales will change that.
So what do you mean exactly?
Title: a tree of geom transforms
Post by: gsaurus on February 23, 2010, 09:05:15 pm
Hm, I was expecting the negative scale to perform a symmetry like on the second image, it looks more natural and useful to me.
My characters will be composed of several drawable objects, some of them can be rotated or scaled. When they walk left and right they should act symmetrically.

But, if you say rotation order isn't the problem, what could be the reason for limiting scale to positive values?
Do you think you can give symmetric/mirror methods for drawable objects?  :roll:
Title: a tree of geom transforms
Post by: Laurent on February 23, 2010, 11:18:16 pm
Ah, sorry I misunderstood your previous post. Now I see exactly what you want.

Quote
But, if you say rotation order isn't the problem, what could be the reason for limiting scale to positive values?

I don't remember, so I guess I'll remove the limitation and run a bunch of tests -- again :)

Quote
Do you think you can give symmetric/mirror methods for drawable objects?

Unfortunately, with the current API it seems impossible. The only "solution" would be to use a RenderImage (in SFML 2) to render your sprite, and flip it to produce the mirror effect. But that's kind of ugly :lol:
Title: a tree of geom transforms
Post by: gsaurus on February 23, 2010, 11:27:09 pm
Quote from: "Laurent"
The only "solution" would be to use a RenderImage (in SFML 2) to render your sprite, and flip it to produce the mirror effect. But that's kind of ugly :lol:

Yeah, I though that too  :P
Well, negative scale should already be a good help, makes me no need to redefine scale fields and methods, which aren't protected nor virtual on SFML (makes all sense not to be), so a bunch of ugly changes are needed on my derived drawable class
Title: a tree of geom transforms
Post by: Laurent on February 23, 2010, 11:36:43 pm
Hey, what about using a positive scale + FlipX/FlipY functions to simulate a negative scale?

I really need to find out why I did it that way...
Title: a tree of geom transforms
Post by: gsaurus on February 24, 2010, 12:13:24 am
Yes, I can do that simulation :wink:, still not great, but better than rendering on a temporary image  :P
I can use a bool variable on all my drawable tree, and when going to render, if it's flipped I multiply the translation of the node by -1, rotate by symmetric angle, change center/origin to GetWidth().x - GetOrigin().x, and in case it is a sprite node, flip image.
Even if I decide to flip some nodes but not others, I can pass my flip from parents to clildren to actually invert the flip state of the children, so by flipping the root (for instace), I invert all flip states of the nodes. I think I'll have to go with that.
In other words, I do my own symmetric/mirror method

I just was trying to understand if there is a way to do it simply with geometry :P
Title: a tree of geom transforms
Post by: gsaurus on February 26, 2010, 09:38:53 pm
Quote from: "Laurent"
rotation is applied after the scale.

Does that have to be like that, or is it possible (on the Matrix3 class) to invert this order?


In the meanwhile I solved my mirroring by deriving a class from sf::Drawable which has another Drawable inside. The parent takes care of translation and scale (my own scale for negative values), the child takes care of rotation and origin. This way rotation is applied before the scale, making the desired effect.

The bad of this on my tree is that I double the number of drawables (and so double the recursive calls), and I had to "redefine" scale, rotation and origin setters and getters. They aren't virtual on sf::Drawable, so I can't use my drawables as sf::Drawable*, or the methods called are the sf::Drawable instead of mine. But I can live with it.

Edit: I just started using sfml2 and I'm not yet very familiar with the new class sf::Renderer. It is passed on the Render method, but since I have to draw my drawable child, I do nothing with the renderer parameter:
Code: [Select]
void DrawableBox::Render(sf::RenderTarget& target, sf::Renderer& renderer) const{
    // apply my own matrix (because of my scale allowing negative values)
    (...)
    // render child
    target.Draw(*child);
}

Is it ok? What can happen by ignoring that parameter?
Title: a tree of geom transforms
Post by: Laurent on February 26, 2010, 10:08:07 pm
Quote
Does that have to be like that, or is it possible (on the Matrix3 class) to invert this order?

It is possible, but I won't make it possible in the SFML API, sorry.

Quote
Is it ok? What can happen by ignoring that parameter?

It's perfectly ok, the renderer must be used when you reach the lowest level of rendering, it is a replacement for direct OpenGL calls. So as long as you still deal with drawables, you can safely ignore it.
Title: a tree of geom transforms
Post by: gsaurus on February 26, 2010, 10:12:55 pm
Quote from: "Laurent"
Quote
is it possible (on the Matrix3 class) to invert this order?

It is possible, but I won't make it possible in the SFML API, sorry.


I guess it's a question of efficiency, it's ok :wink: I deal with it as I can  :wink:
Title: a tree of geom transforms
Post by: Laurent on February 26, 2010, 10:38:39 pm
Not at all :lol:
It is a question of consistent / simple / clean interface.
Title: a tree of geom transforms
Post by: gsaurus on March 11, 2010, 07:50:20 pm
Ok, so, on my derived drawable class, I solved my flip operations this way:
   - I remove (inverse operations) the origin and rotation transformations applied by the sf::Drawable class (note that I let position and scale unchanged)
   - apply my flip (scale by -1 on x and/or y)
   - apply the origin and rotation back again.

Note that I didn't changed order of any original operation, just added a negative factor in a different order than the scale relatively to origin and rotation.

This works great, drawables are now just equal to what they where before, except that they now have FlipX and FlipY methods, that truly flips them over their origin.
I think this is a very consistent/simple/clean concept and interface, don't you? I think flip shouldn't be limited to sprites, it should be provided for all drawable objects.
Also I think Sprite::Flip methods aren't that useful nor consistent, because it isn't a flip over their origin. The origin doesn't coincide with the same pixel anymore, and that's not concordant with the expected properties of the geometric flip operation.

The bad of my implementation is that it requires some extra matrices to be applied on the renderer.

Would you consider to change sf::Drawable (and sf::Matrix3), adding a myIsFlippedX and myIsFlippedY and inverting scale directly on the matrix, in an order that doesn't change anything of the current operations order? So that drawables become with a geometric flip operation. I think it would be of great use! Shouldn't be hard to do and keeps interface simple.
Oh, just if you find that scale by -1 has any problem (didn't find any yet, maybe you restricted it to avoid scale by zero?).
Title: a tree of geom transforms
Post by: Laurent on March 11, 2010, 10:14:37 pm
I'll think about that, do my own tests and decide whether it deserves to be added or not :)

Thanks for your help, I'll let you know when I do it (I'm currently destroying the network API, so it may take a while).
Title: a tree of geom transforms
Post by: gsaurus on March 11, 2010, 10:26:56 pm
Quote from: "Laurent"

Thanks for your help, I'll let you know when I do it (I'm currently destroying the network API, so it may take a while).

Wow! eheh
Thanks, take your time  :)
Title: a tree of geom transforms
Post by: gsaurus on March 16, 2010, 01:17:09 pm
I did a video of my first experimentations with my drawable tree and "flippable" drawables :P
It's a weird test :roll:, but you know... :P

http://www.youtube.com/watch?v=dHQqyc6CjX0

I didn't used shapes nor text this time, but since it's all about geometric transformations on drawable classes, it doesn't matter. When it's flipped on X, it does a mirror over the character center (it's feet).
Title: a tree of geom transforms
Post by: Laurent on March 16, 2010, 01:29:16 pm
This is exactly the kind of stuff that I wanted to do (in another life), very nice :)
Title: a tree of geom transforms
Post by: panithadrum on March 16, 2010, 01:59:51 pm
By the name of the post I couldn't know what was the thing you were working on.
I made an animation system like yours long time ago, but it made it so simple (just to fit with the game I was doing).
Now I'm going to remake it so I'm going to do the same you do :D

I want to see this finished!

BTW, if you want to check the game I'm talking about, watch a video here (http://www.youtube.com/watch?v=JAyKMTx769M)
Title: a tree of geom transforms
Post by: gsaurus on March 16, 2010, 08:19:24 pm
Eheh. I see. Yeah the test I did is quite simple too.

 - A class named DrawableNode extends sf::Drawable. It contains drawable children, with methods like "addChild".

 - A class for InversibleDrawables that adds the FlipX and FlipY methods for true geom flip around the drawable origin. This class works for any kind of drawable objects.
Unfortunately the flip code isn't great, it's as I said above: reverts rotation and origin previously applied by sf::Drawable, apply the negative scale, and apply the rotation back again. But I'm hoping that Laurent implement flip methods directly on sf::Drawable so I can discard my workaround class. While it doesn't happen, this class works fine :P.


Doing this example was just create some nodes and access them directly (nodes and sprite leafs) to change geometric properties.
This is a feature for my project EvE (Evolution Engine) (I posted about it (http://www.sfml-dev.org/forum/viewtopic.php?t=2016) on the SFML projects board some time ago ;))
Title: a tree of geom transforms
Post by: panithadrum on March 16, 2010, 09:23:48 pm
Oh yes, I remember that post. It looks amazing.

So will you make an animation editor?

What a coincidence: my game was called Apocalyptic "Evolution" lol
Title: a tree of geom transforms
Post by: gsaurus on March 16, 2010, 09:33:36 pm
Thanks :)
Yeah, it will have editors for "everything", and will use Lua scripting for characters behaviour and stuff like that :P
Title: a tree of geom transforms
Post by: EatMyShorts on November 03, 2010, 07:31:14 pm
I know I am digging this up, but did you bother to do any kind of soring draw queues? IS performance OK?

I am working on similar solution with extending Drawable class and I am not sure if this will not be an issue.

I know that SFML 2.0 had something like render queue, but AFAIK this was removed.
Title: a tree of geom transforms
Post by: gsaurus on November 03, 2010, 07:47:42 pm
What do you need exactly?

For a tree-structured drawable I just created a "DrawableNode" class, which has a vector of Drawables inside (the children). The render function just draws them in the vector order. If perhaps some children are DrawableNodes themselves then it becomes recursive.
Title: a tree of geom transforms
Post by: EatMyShorts on November 03, 2010, 08:09:18 pm
I understand this part, but what about sorting your objects by i.e. Textures or Shaders? Changing these assets often will decrease your performance significantly.

I was thinking about creating my own Matrix class. I want to avoid it, but this would allow me to:

1. Update all scene nodes
2. Gather all visible objects
3. Sort them by Texture or Shader
4. Draw in one single loop

Generally I need to create a scene graph and want to know if proposed earlier solution (with extended Drawable class) is OK and how complicated scene can be managed with it.
Title: a tree of geom transforms
Post by: gsaurus on November 06, 2010, 02:19:53 am
Quote from: "EatMyShorts"

Sort them by Texture or Shader

Why do you need this? By sorting you mean to change the drawing order of the children of a node?
Title: a tree of geom transforms
Post by: EatMyShorts on November 08, 2010, 08:27:01 pm
I have 3 objects (A, B, C)
Objects A and C are using same texture i.e. Wall.png and object B is using different texture i.e grass.png

Now, drawing objects like this: A->B->C will be inefficient (2 texture changes). To increase performance you will need to sort your objects by texture to have this drawing order A->C->B (1 texture change).

I do not know if the SFML 2.0 is using some internal batching mechanism to minimize device state changes.

I think I will run the test my self.