a couple of questions i need answers to.

Started by
5 comments, last by Enerjak 11 years, 10 months ago
I need some advice on a certain number of things: 1) Creating a scene graph (I know the theory behind it, it basically has to do with each node having it's own matrix then if the object has a child or is a child of another object you multiple the matrices together to get the new one. Just not totally sure on how to go about doing that, Also, I was wondering if anyone could give me the theory behind mouse look, like something that will work for anything given some work. I don't really know the steps to take to get mouse look to work but it should be language independent.
So, what ever you guys give me, i'll take.
Advertisement
Your questions are a little vague, but I'll try...


I need some advice on a certain number of things: 1) Creating a scene graph (I know the theory behind it, it basically has to do with each node having it's own matrix then if the object has a child or is a child of another object you multiple the matrices together to get the new one. Just not totally sure on how to go about doing that,


Doing what? Representing the nodes or performing the multiplication?

To represent the graph in C or C++ you might use pointers in the node structure to refer to any children. In many other languages (Java, Python, C#, ...) nullable references will do the same thing. Or you can create a pool of node objects and use indices in to the pool rather than pointers to represent child links.

If your question is about the multiplication, are you wondering about the mechanics of traversing the graph, or the nuts and bolts of matrix multiplication itself?


Also, I was wondering if anyone could give me the theory behind mouse look,
[/quote]
There's not a lot of theory there. You maintain two angles, yaw and pitch. Moving the mouse updates these angles. Typically you'll want to clamp pitch to (-pi/2, pi/2), unless you want to allow somersaults.

Given those angles you can construct two rotation matrices, one for each axis and multiply them to get the resulting transformation. The order in which you perform the multiplication is significant, but other than that and some trivial optimizations, that's about all there is to it.
Ok, i'll try to explain this as best as I can. first code:

.h

#ifndef INODE_H
#define INODE_H
#include <string>
#include <d3dx9.h>
#include "Container.h"
#include <vector>
#include "IrrException.h"
#include "IrrRenderList.h"
#include "IrrRenderSystem.h"
#include "IrrMatrix4.h"
#include "IrrVector3.h"
#include "..//IrrD3D9Renderer/IrrD3D9Utility.h"
namespace IrrGraphics
{
// Class to create a scene node. this is the base class for other nodes.
class INode
{
protected:
INode* child;
INode* parent;
IrrMatrix4 parentMat;
IrrMatrix4 childMat;
IrrVector3 childPos;
IrrVector3 parentPos;
IrrVector3 parentScale;
IrrVector3 childScale;
std::vector<INode*> Children;
std::vector<ID3DXMesh*> meshes;
std::string m_nodeName;
public:
INode(std::string nodeName);
// node constructor (node's name)

INode();
// default constructor.
INode* getParentNode() const;
// returns the parent node of this node.
int getNumChildren() const;
// returns the number of children this node has.
INode* getChild(std::string childName) const;
// returns the child with the given name.
INode* getChild(int index) const;
// returns the child with the given index.
void setPosition(float xpos,
float ypos,
float zpos);
// sets the node's position.
IrrVector3 getPosition() const;
// returns the position vector of the node.
void setScale(float xscale,
float yscale,
float zscale);
// sets the scale of the node.
IrrVector3 getScale() const;
// get scale of node.

void addChild(INode* otherChild);
// adds a child.
void attachMesh(ID3DXMesh* mesh);
// adds mesh to the node.
// add a child to this node.
void updateNode(); // updates the node.
protected:
bool isNodeAttached(INode* child);
// checks if a node is connected to this one.
// if not, it just
void setParent(INode* p);

};
}
#endif


.cpp

#include "INode.h"
namespace IrrGraphics
{
INode::INode(std::string nodeName)
{
this->m_nodeName = nodeName;
this->child = NULL;
this->parent = NULL;
this->childMat.identity();
this->childPos.Set(0,0,0);
this->childScale.Set(1,1,1);
}
void INode::attachMesh(ID3DXMesh* mesh)
{
meshes.push_back(mesh);
}
void INode::addChild(INode* otherChild)
{
Children.push_back(otherChild);
setParent(this);
}
bool INode::isNodeAttached(INode* child)
{
if(child != NULL)
{
if(parent->child == child)
{
return true;
}
else
{
parent = parent->child;
}
}
else
{
throw IrrException("Node not attach");
}
}
void INode::setParent(INode* p)
{
parent = p;
}
void INode::updateNode()
{

parentMat.identity();
D3DXMATRIX world;
D3DXMatrixTranslation(&world,parentPos.getX(),
parentPos.getY(),
parentPos.getZ());
//D3DXMatrixScaling(&world,1,1,1);
parentMat = IrrD3D9Util::D3DMatrixToIrrMatrix(world);
IrrRenderList::getSingletonPtr()->getRenderSystem()->_setWorldMatrix(parentMat);
for(int x = 0; x < meshes.size(); x++)
{
ID3DXMesh* mesh = meshes[x];
mesh->DrawSubset(0);
}
}
INode::INode()
{
m_nodeName = "_untittled# ";
child = NULL;
parent = NULL;
childMat.identity();
childPos.Set(0,0,0);
childScale.Set(1,1,1);
}
void INode::setPosition(float xpos, float ypos, float zpos)
{
parentPos.Set(xpos,ypos,zpos);
parentMat.setTranslation(parentPos.getX(),parentPos.getY(),parentPos.getZ());
}
IrrVector3 INode::getPosition() const
{
return childPos;
}
INode* INode::getChild(std::string childName) const
{
for(int x = 0; x < Children.size(); x++)
{
INode* c = Children[x];
if(c->m_nodeName == childName)
{
return c;
}
}
}

}


now as you can see from this i sorta do add the matrices together (well, not really.) As im not sure if i got to do something like this:

if(parent->child != null)
{
childmat * parentMat;
}
else
{
childmat = NULL;
}


so yea, that's something i need help with, most of those are place holders anyways especially the one where i add the ID3DXMesh interface.
Let's simmer this down to the essentials:



class renderer
{
public:
// ...
void draw(const mat4x4 &item2world, const renderable &item);
// ...
};

struct scene_node;
typedef boost::shared_ptr<scene_node> scene_node_ptr;

struct scene_node
{
renderable instance; // data to render
mat4x4 local2parent;

std::vector<scene_node_ptr> children; // child nodes
};

// Assumes no cycles in scene graph.
void render_traversal(const scene_node &node, renderer &rend, const mat4x4 &parent2camera)
{
mat4x4 node2camera = parent2camera * node.local2parent; // order of operands depends on how you do matrix multiplication
rend.draw(node2camera, node.instance);

BOOST_FOREACH(const scene_node_ptr &child, node.children)
{
render_traversal(*child, rend, node2camera);
}
}

// To render the entire graph, assuming it only has a single root node:
void render_scene(const camera &cam, renderer &rend, const scene_node &root)
{
mat4x4 base = cam.world_to_camera();
render_traversal(root, rend, base);
}


The exact way in which you represent a position relative to the parent node doesn't matter, but I've used a single matrix here. As you walk the graph, you concatenate the transforms as you go.

Does this make sense? Note that I didn't modify the data in any of the nodes in order to render it. There's simply no need.

It's quite common for scene graph nodes to contain modifiers too. You'd concatenate those in an entirely analogous way. As a crude example, if a valley is foggy, a tree in the valley should also be foggy, and so should its branches, etc.
question: what do you mean "no cycles"?
Consider a graph where A has B as a child and B has A as a child. render_traversal() as it's currently written would cause infinite recursion. Typically scene graphs are DAGs, so it shouldn't be a concern in practice.
Ah, thanks for all your help

This topic is closed to new replies.

Advertisement