310 likes | 769 Views
Scene Graph Data Structures . Modeling/Rendering C++ Classes. Modeling/Rendering. Graphical Model. Rendering Parameters. Rendering. Output Device. Does OpenGL Support Modeling. NO! OpenGL only renders You can skip the model, but… Difficult to deal with variable objects
E N D
Scene Graph Data Structures • Modeling/Rendering • C++ Classes
Modeling/Rendering Graphical Model Rendering Parameters Rendering Output Device
Does OpenGL Support Modeling • NO! • OpenGL only renders • You can skip the model, but… • Difficult to deal with variable objects • Loaded objects? • It is often assumed you will utilize some modeling API • Open Inventor from SGI is an example • Video games, High end modeling, etc.
Why Modeling is Important • All of the model is in a uniform format • Alternative rendering can be supported • Advanced techniques can be supported • Shadows, Transparency, Fog, etc. • Auxiliary functions can be supported • Level of detail, navigation, collision detection • Store static content • Textures, bump maps
Project 1 • You must, I repeat, must implement the entire room as a graphical model that is then rendered. Do not simply draw your float using OpenGL calls!
Standards for Modeling • There are surprisingly few standards for modeling • Models tend to be VERY application specific • Games have different requirements from CAD, which has different requirements from animation, etc. • Models tend to be very “programmer visible”
What a Model Is… • Fundamentally: A Data Structure • Typically a set of objects that represent the elements of a “scene graph” • Scene graph: Hierarchical representation of a graphical scene
A Simple Polygon Model… class CPolygon { public: CPolygon(); virtual ~CPolygon(); void glRender(); void AddVertex(double x, double y, double z); private: // A polygon is a list of vertices std::list<CGrPoint> m_vertices; }; Note: Too Simple, don’t use
That CGrPoint class… class CGrPoint { public: CGrPoint() {} CGrPoint(double x, double y, double z=0, double w=1.) {m[0] = x; m[1] = y; m[2] = z; m[3] = w;} CGrPoint(const CGrPoint &p) {m[0]=p.m[0]; m[1]=p.m[1]; m[2]=p.m[2]; m[3]=p.m[3];} CGrPoint &operator=(const CGrPoint &p) {m[0]=p.m[0]; m[1]=p.m[1]; m[2]=p.m[2]; m[3]=p.m[3]; return *this;} double X() const {return m[0];} double X(double p) {return m[0] = p;} double Y() const {return m[1];} double Y(double p) {return m[1] = p;} double Z() const {return m[2];} double Z(double p) {return m[2] = p;} double W() const {return m[3];} double W(double p) {return m[3] = p;} void Set(double x, double y, double z, double w=1.) {m[0] = x; m[1] = y; m[2] = z; m[3] = w;} void glVertex() const {glVertex4dv(m);} private: double m[4]; };
We really need… • Scene Graph • Primitives (Things that actually render) • Composite objects • Modeling of • Transformations • Color • Other...
Example How do youRender? Barbell Composite Translate Translate Translate BarbellBar BarbellEnds Color Color Composite Composite … … Polygon Polygon Polygon Polygon
Tree Node Superclass class CGrObject { public: CGrObject() {} virtual ~CGrObject(); virtual void glRender() = 0; }; This is an abstract base class
A Primitive class CGrPolygon : public CGrObject { public: CGrPolygon(); virtual ~CGrPolygon(); virtual void glRender(); void AddVertex3d(double x, double y, double z); void AddVertex3dv(double *p); void AddVertices(double *a, double *b, double *c, double *d=NULL); private: // A polygon is a list of vertices std::list<CGrPoint> m_vertices; };
Using this class d // Non-equilateral tetrahedron points double a[3] = {1.5, 0, 0}; double b[3] = {0, 0, 1.5}; double c[3] = {-1.5, 0, 0}; double d[3] = {0, 3, 0}; CGrPolygon *poly1, *poly2, *poly3; poly1 = new CGrPolygon(); poly1->AddVertex3dv(a); poly1->AddVertex3dv(b); poly1->AddVertex3dv(c); poly2 = new CGrPolygon(); poly2->AddVertices(d, b, a); poly3 = new CGrPolygon(d, c, b); Polygon 1 c a b Polygon 2 Polygon 3
Question: What about memory management • We are allocating, so how do we ensure we deallocate? • We can’t deallocate when link removed • We have a multigraph, not a tree • Ideas?
Reference Counters class CGrObject { public: CGrObject() {m_refs = 0;} virtual ~CGrObject(); virtual void glRender() = 0; void IncRef() {m_refs++;} void DecRef() {m_refs--; if(m_refs == 0) {delete this;}} private: int m_refs; };
A Template Pointer Class template <class T> class CGrPtr { public: CGrPtr() {m_ptr = NULL;} CGrPtr(T *p_ptr) {m_ptr = p_ptr; if(m_ptr) m_ptr->IncRef();} CGrPtr(CGrPtr &p_ptr) {m_ptr=p_ptr.m_ptr; if(m_ptr) m_ptr->IncRef();} ~CGrPtr() {Clear();} void Clear() {if(m_ptr) {m_ptr->DecRef(); m_ptr = NULL;}} T *operator=(T *t) {if (t) t->IncRef(); Clear(); m_ptr = t; return m_ptr;} T *operator=(CGrPtr &t) {if (t.m_ptr) t.m_ptr->IncRef(); Clear(); m_ptr = t.m_ptr; return m_ptr;} operator T *() const {return m_ptr;} T *operator->() const {return m_ptr;} private: T *m_ptr; }; Example:CGrPtr<CGrPolygon> poly = new CGrPolygon();
Previous Example Revised // Non-equilateral tetrahedron points double a[3] = {1.5, 0, 0}; double b[3] = {0, 0, 1.5}; double c[3] = {-1.5, 0, 0}; double d[3] = {0, 3, 0}; CGrPtr<CGrPolygon> poly1, poly2, poly3; poly1 = new CGrPolygon(); poly1->AddVertex3dv(a); poly1->AddVertex3dv(b); poly1->AddVertex3dv(c); poly2 = new CGrPolygon(); poly2->AddVertices(d, b, a); poly3 = new CGrPolygon(d, c, b);
Procedures in CGrPolygon void CGrPolygon::AddVertex3d(double x, double y, double z) { m_vertices.push_back(CGrPoint(x, y, z)); } void CGrPolygon::AddVertices(double *a, double *b, double *c, double *d) { m_vertices.push_back(CGrPoint(a[0], a[1], a[2])); m_vertices.push_back(CGrPoint(b[0], b[1], b[2])); m_vertices.push_back(CGrPoint(c[0], c[1], c[2])); if(d) m_vertices.push_back(CGrPoint(d[0], d[1], d[2])); } void CGrPolygon::glRender() { glBegin(GL_POLYGON); for(list<CGrPoint>::iterator i=m_vertices.begin(); i!=m_vertices.end(); i++) i->glVertex(); glEnd(); } std::list<CGrPoint> m_vertices;
A Composite Class class CGrComposite : public CGrObject { public: CGrComposite() {} ~CGrComposite(); virtual void glRender(); void Child(CGrObject *p_child) {m_children.push_back(p_child);} private: std::list<CGrPtr<CGrObject> > m_children; }; void CGrComposite::glRender() { for(list<CGrPtr<CGrObject> >::iterator i=m_children.begin(); i != m_children.end(); i++) (*i)->glRender(); }
Creating the Tetrahedron // The composite node that will contain everything CGrPtr<CGrComposite> composite = new CGrComposite(); CGrPtr<CGrObject> obj = composite; // Non-equilateral tetrahedron points … CGrPtr<CGrPolygon> poly; // Polygon 1 poly = new CGrPolygon(); poly->AddVertex3dv(a); poly->AddVertex3dv(b); poly->AddVertex3dv(c); // Add to composite composite->Child(poly); // Polygon 2 poly = new CGrPolygon(); poly->AddVertices(d, b, a); composite->Child(poly); // Polygon 3 poly = new CGrPolygon(d, c, b); composite->Child(poly); // Polygon 4 composite->Child(new CGrPolygon(d, a, c));
What we get… CGrComposite CGrPolygon CGrPolygon CGrPolygon CGrPolygon What happens when I call render on the CGrComposite object?
CGrColor class CGrColor : public CGrObject { public: CGrColor() {c[0]=c[1]=c[2] = 0.; c[3] = 1.;} CGrColor(double r, double g, double b) {c[0]=r; c[1]=g; c[2]=b; c[3] = 1.;} CGrColor(double r, double g, double b, CGrObject *p_child) {c[0]=r; c[1]=g; c[2]=b; c[3] = 1.; m_child=p_child;} virtual ~CGrColor(); virtual void glRender(); void Child(CGrObject *p_child) {m_child = p_child;} private: double c[4]; CGrPtr<CGrObject> m_child; }; void CGrColor::glRender() { glColor4dv(c); if(m_child) m_child->glRender(); }
Adding Color to Tetra Model CGrPtr<CGrColor> modelwcolor = new CGrColor(0., 0., 1., composite);
After adding the CGrColor node CGrColor CGrComposite CGrPolygon CGrPolygon CGrPolygon CGrPolygon
A Translation Class class CGrTranslate : public CGrObject { public: CGrTranslate() {m_x=m_y=m_z = 0.;} CGrTranslate(double x, double y, double z) {m_x=x; m_y=y; m_z=z;} CGrTranslate(double x, double y, double z, CGrObject *p_child) {m_x=x; m_y=y; m_z=z; m_child=p_child;} ~CGrTranslate(); virtual void glRender(); void Child(CGrObject *p_child) {m_child = p_child;} private: CGrPtr<CGrObject> m_child; double m_x, m_y, m_z; };
Translation Class Implementation Alternatives void CGrTranslate::glRender() { if(m_child) { glPushMatrix(); glTranslated(m_x, m_y, m_z); m_child->glRender(); glPopMatrix(); } } OR void CGrTranslate::glRender() { if(m_child) { glTranslated(m_x, m_y, m_z); m_child->glRender(); } }
Translate in Barbell Composite Translate Translate Translate BarbellBar BarbellEnds Color Color Composite Composite … … Polygon Polygon Polygon Polygon
Very common… Translate Rotate Translate Object
Means: Go ahead and mess with the transformation matrix, I’m isolating my children! Separator Nodes Composite Separator Separator Separator Translate Translate Translate BarbellBar BarbellEnds Color Color Composite Composite … … Polygon Polygon Polygon Polygon
CGrSeparator class CGrSeparator : public CGrObject { public: CGrSeparator() {} CGrSeparator(CGrObject *p_child) {m_child=p_child;} ~CGrSeparator(); virtual void glRender(); void Child(CGrObject *p_child) {m_child = p_child;} private: CGrPtr<CGrObject> m_child; }; void CGrSeparator::glRender() { if(m_child) { glPushMatrix(); m_child->glRender(); glPopMatrix(); } }