Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Simple scene graph and transforms  (Read 3710 times)

0 Members and 1 Guest are viewing this topic.

rook

  • Newbie
  • *
  • Posts: 4
    • View Profile
Simple scene graph and transforms
« on: June 16, 2014, 10:16:17 pm »
This is a fairly simple question. I have two CircleShapes. Picture a CD with the large CircleShape being the plastic, and the small one being the hole in the center.

 I have tried to implement the scene graph node structure in the SFML tutorials http://www.sfml-dev.org/tutorials/2.1/graphics-transform.php, and I've made it so that you construct a ShapeNode with a CircleShape as the argument. Then I make the other CircleShape and another ShapeNode, and then make the smaller one the child of the bigger one. Note I'm calling it a ShapeNode because I'm using sf::Shapes.

Now I want to rotate the bigger one and have the smaller one rotate with it, and then draw them. Currently I have in the update loop
 
sf::Transform rotation;
rotation.rotate(.01f);
bigshape.setTransform(bigshape.getTransform() * rotation);
bigshape.draw(window, bigshape.getTransform());
 

Lots of problems. First of all, I really don't know the distinction between the member variable for transform (m_transform) in my ShapeNode and the parentTransform that is passed into the draw function. If my object is the parent, then how can I pass in a parent transform? Do I set m_transform beforehand? Right now this code causes both objects to move as one, but not rotate about the center of the view. I did set the origin, but I think it's because the bare transform does not take that into account.

Anyways I guess I'm just unsure of how to use the super simple scene graph. I only added the getTransform and setTransform methods because I didn't know what to do with the member variable.
Thanks.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Simple scene graph and transforms
« Reply #1 on: June 17, 2014, 12:12:16 am »
The draw(target, transform) function is meant to be used internally. Obviously, in a final code, this function would be private and only a draw(target) would be exposed (or you can even inherit sf::Drawable). You then draw the root node of your scene graph with this function, and the rest is done internally with recursion using the other overload of the draw function.

The transform member is meant to be the relative transform of the node (relative to its parent). So you can do whatever you want with it, even remove it and inherit sf::Transformable -- but remember that you set a relative transform, not a global one.

So, with this implementation, your example code would be:

bigshape.rotate(0.1f);
window.draw(bigShape);

... like with any other SFML entity. The details are all cleanly hidden inside the Node class.
Laurent Gomila - SFML developer

rook

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Simple scene graph and transforms
« Reply #2 on: June 17, 2014, 01:39:15 am »
Thanks so much Laurent. I have implemented something but I'm not sure that it works. It seems to kind of work, in that the big circle is in the right place, and the little one is in the right place. The big circle spins but the little one does not, and that's because I have no idea what I'm doing :)

I've tried to simplify the scene graph so it's not really a graph anymore. But I have the "platter":


Platter::Platter(void)
{
        m_shape = sf::CircleShape(300.f);
        m_shape.setFillColor(sf::Color::Green);
}

void Platter::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
        states.transform *= getTransform();
        target.draw(m_shape, states);
        for (std::size_t i = 0; i < m_children.size(); ++i)
                m_children[i]->draw(target, getTransform());
}

void Platter::addChild(Node* n)
{
        m_children.push_back(n);
}
 

And a generic child for this platter:
#pragma once
class Node
{
public:

        Node(sf::Shape* s);
        ~Node(void);
        void draw(sf::RenderTarget& target, const sf::Transform& parentTransform) const
    {
                sf::Transform combined = parentTransform;
            target.draw(*m_shape, combined);
    }
private:
        sf::Shape* m_shape;
};

 

As you can see I have
sf::Transform combined = parentTransform;
I'm am not actually combining anything because I don't want to for this particular child; I just want it to take the parent's transform. But it doesn't rotate at all. If I move the origin a bit it does rotate around the center, but it doesn't actually spin. So I guess it is following the translations but not the rotation?

Basically in main.cpp I want to call
platter.rotate(.1f);
and the platter rotates as well as the smaller circle in the center. I also want that if I add another child, it will follow the circle around but I will still be able to give it its own relative transforms. Thanks.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Simple scene graph and transforms
« Reply #3 on: June 17, 2014, 07:42:51 am »
Can you pack this little example into a complete and minimal code that you can paste on the forum, so that we can see everything and possibly try it?
Laurent Gomila - SFML developer

rook

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Simple scene graph and transforms
« Reply #4 on: June 17, 2014, 11:11:00 pm »
main.cpp
#include <SFML/Graphics.hpp>
#include "Platter.h"
#include "Node.h"

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 600), "Test");
       
        Platter platter;
        platter.setOrigin(300.f,300.f);
        platter.setPosition(400, 300);

        sf::CircleShape platterHoleShape(10.f);
        platterHoleShape.setFillColor(sf::Color::Black);
        platterHoleShape.setPosition(300, 300);
        platterHoleShape.setOrigin(10.f,10.f);

        Node platterHole(&platterHoleShape);
       
        platter.addChild(&platterHole);
       
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

                platter.rotate(.1f);
               
        window.clear();
                window.draw(platter);
        window.display();
    }
    return 0;
}
 

platter.h
#pragma once
#include "Node.h"

class Platter : public sf::Drawable, public sf::Transformable
{
public:
        Platter(void);
        ~Platter(void);
        void addChild(Node* n);
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
private:
        sf::CircleShape m_shape;
        std::vector<Node*> m_children;
};

 

platter.cpp
#include "stdafx.h"
#include "Platter.h"

Platter::Platter(void)
{
        m_shape = sf::CircleShape(300.f);
        m_shape.setFillColor(sf::Color::Green);
}

void Platter::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
        states.transform *= getTransform();
        target.draw(m_shape, states);
        for (std::size_t i = 0; i < m_children.size(); ++i)
                m_children[i]->draw(target, getTransform());
}

void Platter::addChild(Node* n)
{
        m_children.push_back(n);
}
 

node.h
#pragma once
class Node
{
public:
        Node(sf::Shape* s);
        ~Node(void);
        void draw(sf::RenderTarget& target, const sf::Transform& parentTransform) const;
private:
        sf::Shape* m_shape;
};


 

node.cpp
#include "Node.h"


Node::Node(sf::Shape* s):
        m_shape(s)
{
}

void Node::draw(sf::RenderTarget& target, const sf::Transform& parentTransform) const
{
                sf::Transform combined = parentTransform;
            target.draw(*m_shape, combined);
}

 

Thanks for your ongoing help :)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Simple scene graph and transforms
« Reply #5 on: June 18, 2014, 07:44:51 am »
How do you know that it's not working? The hole shape is a black circle, rotating it won't make any visual difference. Have you tried to move it instead?
Laurent Gomila - SFML developer

rook

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Simple scene graph and transforms
« Reply #6 on: June 18, 2014, 04:21:32 pm »
How do you know that it's not working? The hole shape is a black circle, rotating it won't make any visual difference. Have you tried to move it instead?

Well, that's that. I didn't realize I wouldn't be able to tell. It works fine.

Thanks.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Simple scene graph and transforms
« Reply #7 on: June 18, 2014, 05:00:14 pm »
 ;D
Laurent Gomila - SFML developer

 

anything