크리에이티브 커먼즈 라이선스
Creative Commons License

Source: 1. Advanced graphics programming using OpenGL (Morgan Kaufmann)            
            2. OpenGL porgramming guide (Addison-Wesley Professional)

We assume that triangle mesh is rendered and then, we can draw the corresponding wireframe objects with their hidden lines removed as follows.

1. Disable writing to the color buffer with glColorMask.
2. Set the depth function to GL_LEQUAL.
3. Enable depth testing with glEnable(GL_DEPTH_TEST).
4. Render the object as triangles.
5. Enable writing to the color buffer.
6. Render the object as edges using such as GL_LINES, GL_LINE_LOOP, GL_LINE_STRIP, or method using glBegin(GL_POLYGON) and glPolygonMode(GL_FRONT_AND_BACK, GL_LINE).

The above algorithm works for the almost cases. However, depth rasterization artifacts from quantization errors may happen since the pixels at the edges of triangles rendered as polygon and the pixels from the edges rendered as line have depth values that are numerically close. To handel this problem, we may use the glPolygonOffset command which move the lines and polygons relative to each other.

- glEnable(GL_POLYGON_OFFSET_LINE): to offset the lines in front of the polygons
- glEnable(GL_POLYGON_OFFSET_FILL): to move polygon surfaces behind the lines

Example code fragments using glEnable(GL_POLYGON_OFFSET_FILL) are as follows.

 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 glDepthFunc(GL_LEQUAL);
 glEnable(GL_DEPTH_TEST);
 glEnable(GL_POLYGON_OFFSET_FILL);
 glPolygonOffset(1.0, 1.0);
// Draw triangles
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Draw edges

Otherwise, we may accomplish the same effect by drawing line segments for edges and drawing filled triangles as follows.

glDisable(GL_LIGHTING);
glEnable (GL_DEPTH_TEST);
glPolygonMode(GL_FRONT, GL_LINE); 
glColor3f(FOREGROUND_COLOR);

// Draw triangle edges
glLineWidth(PRE_DEFINED_LINE_WIDTH);
glBegin(GL_LINES);
// ...
glEnd();
////////////////////////

glPolygonMode(GL_FRONT, GL_FILL);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0, 1.0);
glColor3f(BACKGROUND_COLOR);

// Draw filled triangles
glBegin(GL_TRIANGLES);
// ...
glEnd();
////////////////////////
glDisable(GL_POLYGON_OFFSET_FILL);

신고

'OpenGL' 카테고리의 다른 글

Wireframe rendering with hidden line removal  (0) 2008.10.14
Posted by simon_ryu

Friend functions and classes

IT 2008.09.03 10:24
크리에이티브 커먼즈 라이선스
Creative Commons License

socure: C++ for dummies by Stephen Randy Davis

Occasionally, you want a non-member function to have access to the protected
members of a class. You do so by declaring the function to be a friend of the class by using the keyword friend. Sometimes, an external function can use direct access to a data member. I know this appears to break the strictly defined, well-sealed-off class interface position that I’ve been advocating, but just consider the following. First,
including a friend function is, in effect, adding that function to the interface (that’s why a class shouldn’t have too many friends). You’re okay as long as you attempt to treat this function as a normal function that, oh yeah, happens to have direct access. Second, providing a public access method that acts as a thin veil over a data member doesn’t do anything to abstract away class details. Such a thin veneer function fulfills the letter of the law, but not the spirit.

The friend declaration appears in the class that contains the protected member. The friend declaration is like a prototype declaration in that it includes the extended name and the return type. In the following example, the function initialize() can now access anything it wants in Student:

class Student
{
friend void initialize(Student*);
public:
// same public members as before...
protected:
int semesterHours; // hours earned toward graduation
float gpa;
};
// the following function is a friend of Student
// so it can access the protected members
void initialize(Student *pS)
{
pS->gpa = 0; // this is now legal...
pS->semesterHours = 0; // ...when it wasn’t before
}

A single function can be declared a friend of two classes at the same time. Although this can be convenient, it tends to bind the two classes together. This binding of classes is normally considered bad because it makes one class dependent on the other. If the two classes naturally belong together, however, it’s not all bad, as shown here:

class Student; // forward declaration
class Teacher
{
friend void registration(Teacher& t, Student& s);
public:
void assignGrades();
protected:
int noStudents;
Student *pList[100];
};
class Student
{
friend void registration(Teacher& t, Student& s);
public:
// same public members as before...
protected:
Teacher *pT;
int semesterHours; // hours earned toward graduation
float gpa;
};

void registration(Teacher& t, Student& s)
{
// initialize the Student object
s.semesterHours = 0;
s.gpa = 0;
// if there’s room...
if (t.noStudents < 100)
{
// ...add it onto the end of the list
t.pList[t.noStudents] = &s;
t.noStudents++;
}
}

In this example, the registration() function can reach into both the Student and Teacher classes to tie them together at registration time, without being a member function of either one. The first line in the example declares the class Student, but none of its members. This is called a forward declaration and just defines the name of the
class so that other classes, such as Teacher, can define a pointer to it. Forward references are necessary when two classes refer to each other. A member function of one class may be declared a friend of another class, as shown here:

class Teacher
{
// ...other members as well...
public:
void assignGrades();
};
class Student
{
friend void Teacher::assignGrades();
public:
// same public members as before...
protected:
int semesterHours; // hours earned toward graduation
float gpa;
};
void Teacher::assignGrades()
{
// can access protected members of Teacher from here
}
Unlike in the non-member example, the member function assignGrades()
must be declared before the class Student can declare it to be a friend.

An entire class can be named a friend of another. This has the effect of
making every member function of the class a friend
:

class Student; // forward declaration
class Teacher
{
protected:
int noStudents;
Student *pList[100];
public:
void assignGrades();
};
class Student
{
friend class Teacher; // make entire class a friend
public:
// same public members as before...
protected:
int semesterHours; // hours earned toward graduation
float gpa;
};
Now, any member function of Teacher has access to the protected members
of Student. Declaring one class a friend of the other inseparably binds the
two classes together.

신고
Posted by simon_ryu
TAG C++
크리에이티브 커먼즈 라이선스
Creative Commons License
(source: Effective C++, 2E | Item 50 by Scott Meyers)

class Base {
public:
virtual void f(int x);
};
class Derived: public Base {
public:
virtual void f(double *pd);
};
Derived *pd = new Derived;
pd->f(10); // error!

The problem is that Derived::f hides Base::f, even though they take different
parameter types
, so compilers demand that the call to f take a double*, which the literal 10 most certainly is not.

Suppose that when you called f, you really did want to call the version in Derived, but you accidentally used the wrong parameter type. Further suppose that Derived is way down in an inheritance hierarchy and that you were unaware that Derived indirectly inherits from some base class BaseClass, and that BaseClass declares a virtual function f that takes an int. In that case, you would have inadvertently called BaseClass::f, a function you didn't even know existed! This kind of error could occur frequently where large class hierarchies are used, so Stroustrup decided to nip it in the bud by having derived class members hide base class members on a per-name basis.

Note that if not declared with the same agruments in the derived classes, the member functions are not overridden polymorphically, whether or not they are declared virtual.

Note, by the way, that if the writer of Derived wants to allow clients to access Base::f,
this is easily accomplished via a simple using declaration:

class Derived: public Base {
public:
using Base::f; // import Base::f into
                         // Derived's scope
virtual void f(double *pd);
};
Derived *pd = new Derived;
pd->f(10); // fine, calls Base::f

For compilers not yet supporting using declarations, an alternative is to employ an
inline function
:

class Derived: public Base {
public:
virtual void f(int x) { Base::f(x); }
virtual void f(double *pd);
};
Derived *pd = new Derived;
pd->f(10); // fine, calls Derived::f(int),
                  // which calls Base::f(int)
신고
Posted by simon_ryu
TAG C++
크리에이티브 커먼즈 라이선스
Creative Commons License

(source: Effective C++, 2E | Item 16 by Scott Meyers)

class Derived: public Base {
public:
Derived(int initialValue)
: Base(initialValue), y(initialValue) {}
Derived(const Derived& rhs) // erroneous copy
: y(rhs.y) {} // constructor
private:
int y;
};

// correct copy constructor
class Derived: public Base {
public:
Derived(const Derived& rhs): Base(rhs), y(rhs.y) {}
...
};

// erroneous assignment operator
Derived& Derived::operator=(const Derived& rhs)
{
if (this == &rhs) return *this;

this->m_member = rhs.m_member; // assign to Derived's
// lone data member
return *this;
}

// correct assignment operator (type 1)
// erroneous assignment operator
Derived& Derived::operator=(const Derived& rhs)
{
if (this == &rhs) return *this;

Base::operator=(rhs); // call this->Base::operator=
this->m_member = rhs.m_member;
return *this;
}

// correct assignment operator (type 2)
// erroneous assignment operator
Derived& Derived::operator=(const Derived& rhs)
{
if (this == &rhs) return *this;

static_cast<Base&>(*this) = rhs; // some complier allows only this one
this->m_member = rhs.m_member;
return *this;
}

신고
Posted by simon_ryu
TAG C++


티스토리 툴바