It is currently Fri Nov 24, 2017 5:53 am

All times are UTC - 5 hours




 Page 1 of 1 [ 25 posts ] 
Author Message
 Post subject: GameDev VMK 29 - Cylinder Geometry
PostPosted: Mon Apr 16, 2007 5:43 pm 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
The Cylinder class is developed in VMK29A & 29B, and a visual explanation of the different parameters within the class is shown.

VMK29 A & B has been split into two parts so that the download file size is a little bit easier to work with. Because of this, VMK29A will only play up to the beginning of 25min. The rest of the video is stored in

VMK29B and it will play from 25min to the end. After you download both parts, you can extract all VMK files (from 29A and 29B) into one directory to allow you to watch the entire VMK in one go.

VMK 29C shows you how to add smooth shading to the cylinder class and VMK 29D adds texture coordinates so that you can apply a texture overtop of the geomerty.

VMK 29E shows you how to make a cylinder roll on a flat surface. A challenge is also presented to you in this video. The last part of the VMK shows you how to fix a problem with GL_BLEND.


Last edited by Marek on Sun Feb 03, 2008 12:13 pm, edited 1 time in total.

Offline
 Profile  
 
 Post subject: Re: GameDev VMK 29 - Cylinder Geometry
PostPosted: Tue Apr 17, 2007 6:21 am 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
I made a short math VMK for anyone who would like to see a little more of an explanation on how the unit circle can be used to get coordinates located in a circle. You can download the video from: http://www.marekknows.com/downloadSection.php?Topic=Math&pg=1#Math5


Offline
 Profile  
 
 Post subject:
PostPosted: Sat Feb 02, 2008 1:55 am 

Joined: Sat Jun 23, 2007 7:56 pm
Posts: 145
Hi,
I have just implemented texturing for my cylinders. However, I use quad strips when rendering my cylinders.

I generated my texture coords for the column part of the cylinder by chopping the bottom half of the texture (0,0) to (1,0) into the number of sections for the cylinder.


   //Texture coords for the side of the cylinder
   //they are in the bottom 2 quadrants from (0,0) to (1,0)
   //the height is 0.5
   float inc = 1.0f / m_horizontalSections;

   //put in the bottom m_horizontalSections coordinates
   for(int i = 0; i < m_horizontalSections; i++)
   {
      coord.m_x = i * inc;
      coord.m_y = 0;

      m_textCoords.push_back(coord);
   }

   //put in the top m_horizontalSections coordinates
   for(int i = 0; i < m_horizontalSections; i++)
   {
      coord.m_x = i * inc;
      coord.m_y = 0.5f;

      m_textCoords.push_back(coord);
   }


While rendering the cylinder as quad strips, if I use the texture coords as calculated, the image is backwards
Image

However, If I calculate the x value as a negative (coord.m_x = -i * inc;) I get the right result.

Does anybody have an idea why this is the case?

Thanks
Codeslasher


Offline
 Profile  
 
 Post subject:
PostPosted: Sat Feb 02, 2008 7:41 am 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
It sounds like your texture coordinates are being placed onto your geometry in a clockwise fashion. That is why it is fixed by swapping your angle from positive to negative.

Have a look at your render code to see which texture coordinates you are grabing for each vertex that you render. You'll probably see that you are going around the geometry one way, but your texture coordinates are going around it the opposite way.


Offline
 Profile  
 
 Post subject:
PostPosted: Sat Feb 02, 2008 2:25 pm 

Joined: Sat Jun 23, 2007 7:56 pm
Posts: 145
Ok,
I now start putting in text coords from point (1,0) to (0,0) , using this texture coordinate generation code (the reverse of the one above)
   float inc = 1.0f / m_horizontalSections;

   //put in the bottom m_horizontalSections coordinates
   for(int i = m_horizontalSections; i > 0; i--)
   {
      coord.m_x = i * inc;
      coord.m_y = 0;

      m_textCoords.push_back(coord);
   }


And evrything works as expected. What I don't understand is why the texture coord for the first vertex of my cylinder column is (1,0) and not (0,0) and the one directly above it is (1,0.5) and not (0, 0.5)?

Any ideas? (also I am not using angles when making the texture coordinates for the column part)


Offline
 Profile  
 
 Post subject:
PostPosted: Sat Feb 02, 2008 4:19 pm 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
I'd have to see your render code to see how you are using your texture coordinates to figure out why the texture is backwards.


Offline
 Profile  
 
 Post subject:
PostPosted: Sun Feb 03, 2008 8:39 am 

Joined: Sat Jun 23, 2007 7:56 pm
Posts: 145
Here is the complete Cylinder class.

http://www.freewebs.com/fuzionstudio/Cylinder.cpp
http://www.freewebs.com/fuzionstudio/Cylinder.h


Offline
 Profile  
 
 Post subject:
PostPosted: Sun Feb 03, 2008 9:51 am 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
Looking at your code confirmed my earlier suspicion that you are wrapping your texture in clockwise winding order. Have a look at the image below.

Image

As you are going around clockwise you are grabing texture coordinates from your image. But notice that a clockwise rotation will cause your texture to lay inverted on the cylinder. You can either define your texture coordinates backwards as you suggested, or use the original texture coordinates but grab them in reverse order (CCW) rather than CW when you go around your geometry.


Last edited by Marek on Sat Dec 11, 2010 6:33 am, edited 1 time in total.

Offline
 Profile  
 
 Post subject:
PostPosted: Sun Feb 03, 2008 10:32 am 

Joined: Sat Jun 23, 2007 7:56 pm
Posts: 145
Hi,
Thanks for the reply.
I didn't realise I was going around clockwise. I thought that while generating the vertices of the cylinder, sin(angle) and cos(angle) were already giving me a counter-clockwise rotation.

Could you please point out where(using line numbers if possible) and if possible, how you determined that I was going around clockwise?

Thanks once again.


Offline
 Profile  
 
 Post subject:
PostPosted: Sun Feb 03, 2008 11:31 am 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
Your clockwise winding is the result of using the following equations
vert.m_x = m_radius * cos(radAngle);
vert.m_z = m_radius * sin(radAngle);


The x axis goes to the right, the Z axis comes out of the screen in OpenGL.

If you set your angle to 0 you see you have a vector pointing in the X direction (1,0,0).

Now if you increase the angle your X value decreases and your Z value increases (according to the cos and sin relationship). So when you get to 90 degrees your vector now points at (0,0,1). Continue on ward to 180 degrees you get (-1,0,0) and at 270 degrees you're pointing at (0,0,-1).


Offline
 Profile  
 
 Post subject:
PostPosted: Sun Feb 03, 2008 11:38 am 

Joined: Sat Jun 23, 2007 7:56 pm
Posts: 145
Thanks, I really appreciate this.

So to get a counter-clockwise rotation using that formula, I should flip the Z value , right?

Like this
vert.m_x = m_radius * cos(radAngle);
vert.m_z = -m_radius * sin(radAngle);


or should I use the negaive radAngle?

Thanks


Offline
 Profile  
 
 Post subject:
PostPosted: Sun Feb 03, 2008 12:09 pm 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
sin(-angle) = -sin(angle)


therefore it doesn't matter which one you choose. They will give you the same result.

(side note) Careful when trying to apply this logic to the cosine through
cos(-angle) != -cos(angle)

For your example you don't have to worry about the cos component though. Just wanted to add this side note though.


Offline
 Profile  
 
 Post subject: Normal improvement
PostPosted: Thu Nov 27, 2008 10:49 pm 

Joined: Wed Aug 06, 2008 7:53 pm
Posts: 182
Location: Russia
The way the normals for cylindrical geometry are calculated in this VMK is a little bit overengineered. Let's employ the fact that all normals are radius-vectors of unit circumference. The angles are also known. Hence, to calculate normals for both, smooth and faceted faces one loop is enough, i.e.
    const float astep = (-2.0f * PI) / m_numSides;
    const float bias = m_smooth ? 0.0f : (astep * 0.5f);

    for ( t = 0, angle = bias; t < m_numSides; ++t, angle += astep )
    {
        m_N[ t ] = Vertex3( cos( angle ), 0.0f, sin( angle ) );
    }



As a result, my GeometryCylinder ctor code is pretty concise:
ShapeCylinder::ShapeCylinder( size_t numSides, float radius, float height, bool smooth )
:   m_n( NULL )
,   m_v( NULL )
,   m_t( NULL )
,   m_smooth( smooth )   
{
    m_numSides = get_in_range( 3u, numSides, 32u );
    m_radius = radius <= FLOAT_EPSILON ? 1.0f : radius;
    m_height = height <= FLOAT_EPSILON ? 1.0f : height;

    m_v = New Vector3[ m_numSides ];
    m_n = New Vector3[ m_numSides ];
    m_t = New Vertex2[ m_numSides * 2 ];
    _ASSERTE( m_v && m_n && m_t );

    size_t t;
    float a, n, x, y;
    const float astep = (-2.0f * PI_FLT) / m_numSides;
    const float tstep = 1.0f / m_numSides;
    const float bias = m_smooth ? 0.0f : (astep * 0.5f);

    for ( t = 0, a = 0.0f, n = bias; t < m_numSides; ++t, a += astep, n += astep )
    {
        x = cos( a ), y = sin( a );
        Vertex( t ) = Vertex3( m_radius * x, 0.0f, m_radius * y );      // vertices
        TexCol( t ) = Vertex2( tstep * t, 0.0f );                       // tex of columns
        TexCap( t ) = Vertex2( 0.25f * x + 0.25f, -0.25 * y + 0.75f );  // tex of cap
        Normal( t ) = Vertex3( cos( n ), 0.0f, sin( n ) );              // normals
    }
}

(I am using another memory arrangement for vertices, texture co-ordinates and normals, but that is not a big deal). New is defined as
#define New new ( std::nothrow )
in the library, because operator new does not return NULL if it failed to allocate memory, it throws an exception instead. So I use nothrow version of new.
Additionally, my rendering code uses two display lists:
void ShapeCylinderGL::Render( bool textured )
{
    glCallList( m_list + (textured ? TEXURING_ON : TEXURING_OFF) );
}

The only thing I did not manage to do is to use GL_QUAD_STRIP in place of GL_QUADS, as codeslasher proposed, since I suspect that the strips are not compatible with faceted (non-smoothed) faces, e.g. if one chose to use GL_QUAD_STRIP then there is no way to make the edges looks faceted (assuming each face has its own normal). I would be very grateful if somebody confirm or refute this supposition.


Offline
 Profile  
 
 Post subject: the sin_cos( ) promotion
PostPosted: Sat Dec 06, 2008 3:15 am 

Joined: Wed Aug 06, 2008 7:53 pm
Posts: 182
Location: Russia
To make elliptical calculations ( e.g. sin( alpa ), cos( alpha ) ) a little bit faster, I added sin_cos( angle, sin_, cos_ ) function to our math library.

http://www.marek-knows.com/phpBB3/viewtopic.php?t=313



_________________
«Computer scientists deal with algorithms that you may call practical in theory but unpractical in practice.» © Timothy Gowers
Offline
 Profile  
 
 Post subject: VMK29 - enigma is solved
PostPosted: Wed Dec 10, 2008 10:53 am 

Joined: Wed Aug 06, 2008 7:53 pm
Posts: 182
Location: Russia
VMK29 - enigma is solved.
Please have a look: http://www.marek-knows.com/phpBB3/viewt ... =1332#1332

8)


Offline
 Profile  
 
 Post subject: Rolling Cylinder
PostPosted: Fri Jan 09, 2009 10:49 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 450
I am working on The Rolling Cylinder and I have no problems with the code the program runs fine. I was trying out the algorithm you gave to us as a challenge. I liked the challenge. It took some time and thought.

Inside the Scene::Update() where we implement the "tumbling" effect.
This is what I came up with:

  pNode = m_vpNodes[0]->FindNode("tumble");
   if ( pNode )
   {
      NodeTransform* pT = (NodeTransform*)pNode;
      pT->m_v3Translate.m_fZ = -0.65f;
      pT->m_v3Translate.m_fX += fMoved;
      if ( ((pT->m_v3Centre.m_fX > 5.0f ) && (pT->m_v3Translate.m_fX > 5.0f)) ||
          ((pT->m_v3Centre.m_fX < -5.0f ) && (pT->m_v3Translate.m_fX < -5.0f)) )
      {
         fDir *= -1.0f;
      }
      
      pT->m_fRotateAngle -=  (fMoved/0.75f)*PI_INVx180;
   }



I was able to raise the height of the cylinder, create the boundaries and rotate the object, but when one of the vertices hit the ground, it hops in the air along an arc. The cylinders side does not lay flat on the ground at any time. What am I missing. I would really like to implement this.
BTW Barrel Rolling Is Fun!


Offline
 Profile  
 
 Post subject: Think harder ;)
PostPosted: Sat Jan 10, 2009 4:24 am 

Joined: Wed Aug 06, 2008 7:53 pm
Posts: 182
Location: Russia
Think harder, I know you can! ;)

Meanwhile, my version of The Rolling Cylinders (a remainder): http://www.marek-knows.com/phpBB3/viewt ... =1332#1332

Image Image


Full Image 1
Full Image 2


8)



_________________
«Computer scientists deal with algorithms that you may call practical in theory but unpractical in practice.» © Timothy Gowers
Offline
 Profile  
 
 Post subject: Re: Rolling Cylinder
PostPosted: Sat Jan 10, 2009 6:38 am 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
skilz80 wrote:
I was able to raise the height of the cylinder, create the boundaries and rotate the object, but when one of the vertices hit the ground, it hops in the air along an arc. The cylinders side does not lay flat on the ground at any time. What am I missing. I would really like to implement this.


Start with a cylinder made up of 3 sides (extruded triangle).

Draw what it would look like on a piece of paper looking at it from the side. Draw the ground plane and draw the cylinder rolling along the ground. Also mark the centre of the cylinder in each of your drawings. Now connect the centres as the cylinder is rolling to see the curve that it creates.

Your objective is to figure out how to define this curve mathematically with an equation.


Offline
 Profile  
 
 Post subject: How Many Sides Is Enough!
PostPosted: Wed Dec 09, 2009 9:21 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 450
When I first started to work with these tutorials from this website, I had a Pentium Core2 Duo 1.6GHZ with 2GB DDR2 ram and an ATI 256MB video card. Now my current pc is a Pentium Core2 Quad Extreme 3.0GHZ with 4GB DDR3 ram and an ATI 512MB video card ( both video cards are PCI-Express ) eventually I will get atleast a 1GB video card :)

For those of you who are interested. If you have high end graphics cards and are programming for your-self or the new wave of video cards out there for the Quad Core or I7 with (direct-x 10 / 11) or OpenGL equivalent up-to-date. I did some testing and found that the max number of sides that you will ever need for the Cylinder is 360.

Why did I come up with this number?

My first thought was well 20 is nice for a can or barrel, but what if i wanted a platform that was big inside of a room, or wanted to make an Oil Tank that you see in a refinery and I wanted it to be as close to a circle as possible. Well with some testing 20 sides wasn't cutting it (LOL),
but 360 was perfect. and my reasoning for this is that there are 360 degrees in a cirlce.

Yes that is a lot of polygons for to render for one shape/object. So how do we regulate this.

In the constructor what we can do is take the range of the radius
from [a,b] and set max number to 20 for small cylinders, then
from [b,c] to say 50-100 your preference and finally
from [c, >c] to 360.

I can not give you the demensions in this demonstration for these ranges. It will depend on your coordinate system and the relative world size.

For a soda can, pillar or barrel you could use 20 sides with the radius between [a,b]

For something like a swimming pool you could use between 50 - 100 sides with the radius between [b,c]

For a platform on the ground ( an elevated part of the floor, like a lobby in a building you could use 100 - 360 sides with a radius from [c, >c].

I hope This Helps! Please Post some feed back on this!


Offline
 Profile  
 
 Post subject: Question About The Radius?
PostPosted: Wed Dec 09, 2009 9:36 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 450
In the constructor you originally have

if ( fRadius <= 0.0f )
{
fRadius = 1.0f;
}
m_fRadius = 1.0f;

My question is:

with in the constructor 1.0f is the minimal size for the radius

but when we implement the constructor in Scene::Initialize()
we are using sizes from .1 - 1.0f

what is the ratio between the two. This will help me set the ranges for the max number of sides depending on the length or r.


Offline
 Profile  
 
 Post subject: My Second Attempt!
PostPosted: Thu Oct 14, 2010 2:15 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 450
I am redoing the VMK's again for some practice! I have noticed something that makes this class's code a little nicer :)

but before I show you my version of the code. You will need to have within your Vector3 class the union structure .m_f for this to work!
At this point I have not done the texture coordinates yet, but I will post them afterwards.

If you look in the Constructor where we call the plane's constructor Marek is calling 3 Vector3 constructors and using the member variables that are vertexes and setting the x,y,z coords. To simplify the code, within the .h file instead of declaring m_V as a Veretex, you can declare it as a Vector3 it will do the same thing. Then whe you call the plane's constructor
you can just pass in m_V[with condition], since the condition doesn't change between the x,y or z value... Just refer to where I have the plane = Plane( .... ) vs. the commented code right below it. The code compiles and the cylinders render with the correct normals to work with the lighting in the scene. The reason for this is m_V is already a Vector3 so we don't need to call the Vector3's constructor for each point.
The less code typed to do the same task is usually better.

Now as in the RenderOGL function, I have one call for the
glNormal3fv(...); and commented out the glNormal3f( .., .., .. );
they do the same thing, but as I said up above within your Vector3.h you will need to have your m_fX, m_fY and m_fZ setup like this
class SomeClass
{
public:
     SomeClass();
     ~SomeClass();

     union
     {
          float m_f[3];
          struct
          {
               float m_fX;
               float m_fY;
               float m_fZ;
          };
     };
};



Then you can use glNormal3fv( your vector3 ) glVertex3fv( your vector3 )
and glTexCoord2fv( your vector2 ) and make life a lot easier.

This is really meant for any new members that are just now reaching this point in the GameEngine.

As far as I can tell there should be no bugs in this code, but if anyone can see any place where the code breaks down please let me know.

Oh, one last thing within the Plane's Constructor where we use m_V[...]
you might be tempted to do m_V[...].m_f like i was using in the glNormal3fv() calls, but our constructor for the plane doesn't know how to handle that, but since m_V[...] is a Vector3 you don't need the .m_f after it.


Last edited by skilz80 on Fri Oct 15, 2010 1:24 pm, edited 1 time in total.

Offline
 Profile  
 
 Post subject: This Is Something Extra
PostPosted: Thu Oct 14, 2010 5:23 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 450
Ok I took the idea of the cylinder class, and I am trying to implement a Pyramid class. So far the .h file is the same as the Cylinder class, only the .cpp file differs.

I want the class to work where you have number of sides with radius r this defines the base, then what ever height is given creates a single vertex at that height. As an additional 4th parameter I added a cutoff value that will define a new height, the default is set to 0 rendering the pyramid with a vertex point at the top, but if this parameter is greater then 0 or less then the height the difference is taken and this becomes the new hieght. At this new height the top portion of the pyramid is cutoff and the top has the same polygonal shape as the base but with a new radius! Please refer to the next post for more details and the code.


Last edited by skilz80 on Fri Oct 15, 2010 1:28 pm, edited 1 time in total.

Offline
 Profile  
 
 Post subject: I Have A New Object Class For You All To Enjoy!!!
PostPosted: Thu Oct 14, 2010 9:07 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 450
Ok here is the scoop! I have a GeometryPyramid Class!!!
When you create the constructor in the Scene for this new class that I have implemented. It takes the same 3 parameters as the GeometryCylinder class GeometryPyramid( int iNumSides, float fRadius, float fHeight ) but there is a 4th different parameter... I called this the Cutoff and it is a float value... What This means is by default it is set to 0
and if you call the constructor without the 4th parameter or enter in a number <= 0 it is clamped to 0 and the Pyramid draws the base polygon based on the number of sides the user inputs and the sides converge to a single vertex.
Now if the user specifies a number greater then 0 and less then the height passed in, that value will be used as the cutoff value and the difference from the height and the cutoff value is the new height, except here the same pyramid is drawn except the top is rendered as a n-polygon same as the base.

Here is the complete code for you to enjoy!!!

In the header file there are some includes that you won't see such as Vector3.h, GeneralMath.h ( I am not using any Vertex Classes ) I am using Vector3 and Vector2 classes every where and so forth. these missing header files are in my core.h since they are used in most files.

The Header File
#ifndef GEOMETRYPYRAMID_H
#define GEOMETRYPYRAMID_H

// ============================================================================================== //
// FileName: GeometryPyramid.h
// Version: 1.0
// Copyright (c) 2010 by Francis R. Cugler Jr.
// ============================================================================================== //

// Includes
#include "Core.h"
#include "Plane.h"
#include "Geometry.h"

class GeometryPyramid : public Geometry
{
public:
   // Default Constructor And Destructor
   GeometryPyramid( int iNumSides, float fRadius, float fHeight, float fCutOff = 0.0f );
   ~GeometryPyramid();

   // Public Member Functions
   void   Update();
   void   RenderOGL( bool bTextured );

private:
   int      m_iNumSides;
   float   m_fRadius;
   float   m_fHeight;
   float   m_fCutOff;
   float   m_fCutOffRadius;

   Vector3 *m_N; // Normals
   Vector3 *m_V; // Vertex Coords

}; // GeometryPyramid

#endif // GEOMETRYPYRAMID_H


The Cpp File
// ============================================================================================== //
// FileName: GeometryPyramid.cpp
// Version: 1.0
// Copyright (c) 2010 by Francis R. Cugler Jr.
// ============================================================================================== //

// Includes
#include "stdafx.h"
#include "GeometryPyramid.h"

// ---------------------------------------------------------------------------------------------- //
// Name: GeometryPyramid()
// Desc: Default Constructor
// ---------------------------------------------------------------------------------------------- //
GeometryPyramid::GeometryPyramid( int iNumSides, float fRadius, float fHeight, float fCutOff )
{
   // Save And Correct All Parameters
   if ( iNumSides < 3 )
   {
      iNumSides = 3;
   }
   else if ( iNumSides > 20 )
   {
      iNumSides = 20;
   }
   m_iNumSides = iNumSides;

   if ( fRadius <= 0 )
   {
      fRadius = 1.0f;
   }
   m_fRadius = fRadius;

   if ( fHeight <= 0 )
   {
      fHeight = 1.0f;
   }
   m_fHeight = fHeight;

   if ( fCutOff <= 0 )
   {
      fCutOff = 0.0f;
      m_fCutOff = fCutOff;
   }
   else if ( fCutOff >= m_fHeight )
   {
      fCutOff = fHeight-0.08f;
      m_fCutOff = fCutOff;
   }
   else if ( (fCutOff > 0) || (fCutOff < fHeight)  )
   {
      m_fCutOff = fCutOff;
   }

   m_N = NULL;
   m_V = NULL;
   
   // Define The Up or Peak Normal This Doesn't Change
   // With Regard To The CutOff Value
   
   if ( fCutOff == 0 )
   {   
      m_N = new Vector3[iNumSides+1];
      m_V = new Vector3[iNumSides+1];
      // Peak Vertex
      m_N[iNumSides] = Vector3( 0.0f, 1.0f, 0.0f );
      m_V[iNumSides] = Vector3( 0.0f, m_fHeight, 0.0f );
   }
   else if ( fCutOff != 0 )
   {
      m_N = new Vector3[iNumSides];
      m_V = new Vector3[iNumSides*2];
   }

   // Vertex And Normals For The Sides
   if ( m_V && m_N )
   {
      // Memory Allocation Is Okay
      float fXVal, fZVal;
      for ( int i = 0; i < iNumSides; i++ )
      {
         if ( fCutOff == 0 )
         {
            fXVal = float( fRadius*cos(-i*2*PI/iNumSides) );
            fZVal = float( fRadius*sin(-i*2*PI/iNumSides) );
            
            m_V[i] = Vector3( fXVal, 0.0f, fZVal );
         }
         else if ( fCutOff != 0 )
         {
            fXVal = float( fRadius*cos(-i*2*PI/iNumSides) );
            fZVal = float( fRadius*sin(-i*2*PI/iNumSides) );
            
            m_V[i] = Vector3( fXVal, 0.0f, fZVal );
            
            float fAngle = (float)(180*(atan(fHeight/fRadius)/PI)); // In Rad
            // Convert fAnlge From Degrees To Radians
            fAngle = ((float)PI*fAngle/180.0f);
            m_fCutOffRadius = fCutOff/(float)tan(fAngle);
      
            float fNewHeight = fHeight - fCutOff;      
            fXVal = float( m_fCutOffRadius*cos(-i*2*PI/iNumSides) );
            fZVal = float( m_fCutOffRadius*sin(-i*2*PI/iNumSides) );
            m_V[i+iNumSides] = Vector3( fXVal, fNewHeight, fZVal );         
         }
      }

      Plane plane;
      // Calculate Normals For Each Side Of The Pyramid
      for ( int n = 0; n < iNumSides; n++ )
      {
         if ( fCutOff == 0 )
         {
            if ( n == (iNumSides-1) )
            {
               plane = Plane( m_V[iNumSides], m_V[n], m_V[0] );
            }
            else
            {
               plane = Plane( m_V[iNumSides], m_V[n], m_V[n+1] );
            }
         }
         else if ( fCutOff != 0 )
         {
            if ( n == (iNumSides-1) )
            {
               plane = Plane( m_V[n+iNumSides], m_V[n], m_V[0] );
            }
            else
            {
               plane = Plane( m_V[n+iNumSides], m_V[n], m_V[n+1] );
            }
         }
         m_N[n] = plane.GetNormal();
      }      
   }
   else
   {
      // Not Enough Memory
      SAFE_DELETE_ARRAY( m_N );
      SAFE_DELETE_ARRAY( m_V );
   }
         
} // GeometryPyramid

// ---------------------------------------------------------------------------------------------- //
// Name: ~GeometryPyramid()
// Desc: Default Destructor
// ---------------------------------------------------------------------------------------------- //
GeometryPyramid::~GeometryPyramid()
{
   SAFE_DELETE_ARRAY( m_N );
   SAFE_DELETE_ARRAY( m_V );

} // ~GeometryPyramid

// ---------------------------------------------------------------------------------------------- //
// Name: RenderOGL()
// Desc:
// ---------------------------------------------------------------------------------------------- //
void GeometryPyramid::RenderOGL( bool bTextured )
{
   // Render The Pyramid Using Coordinates
   if ( bTextured )
   {

   }
   else
   {
      // Not Using Texture Coordinates

      // Render Sides
      for ( int v = 0; v < m_iNumSides; v++ )
      {
         // Render Pyramid With Vertex Peak
         if ( m_fCutOff == 0 )
         {
            glBegin( GL_TRIANGLES );
            glNormal3fv( m_N[v].m_f );
            // Check For Last Side First
            if ( v == m_iNumSides - 1 )
            {
               glVertex3fv( m_V[m_iNumSides-1].m_f );
               glVertex3fv( m_V[0].m_f );
               glVertex3fv( m_V[m_iNumSides].m_f );
            }
            else
            {
               glVertex3fv( m_V[v].m_f );
               glVertex3fv( m_V[v+1].m_f );
               glVertex3fv( m_V[m_iNumSides].m_f );
            }
            glEnd();
         }
         else if ( m_fCutOff != 0 ) // Render Pyramid With Top Cap CutOff
         {
            glBegin( GL_QUADS );
            
            glNormal3fv( m_N[v].m_f );
            if ( v == m_iNumSides - 1 )
            {
               // Adjust Coordinates At The Seam To Wrap Around
               glVertex3fv( m_V[0].m_f );
               glVertex3fv( m_V[m_iNumSides].m_f );
            }
            else
            {
               glVertex3fv( m_V[v+1].m_f );
               glVertex3fv( m_V[v+1+m_iNumSides].m_f );
            }
            glVertex3fv( m_V[v+m_iNumSides].m_f );
            glVertex3fv( m_V[v].m_f );

            glEnd();
         }
      }

      // Render Top Cap
      if ( m_fCutOff != 0 )
      {
         // Render Top Cap
         glBegin( GL_POLYGON );
         glNormal3f( 0.0f, 1.0f, 0.0f );
         for ( int v = 0; v < m_iNumSides; v++ )
         {
            glVertex3fv( m_V[v+m_iNumSides].m_f );
         }
         glEnd();
      }
      
      // Render The Base This Does Not Change
      glBegin( GL_POLYGON );
      glNormal3f( 0.0f, -1.0f, 0.0f );
      for ( int v = m_iNumSides-1; v >= 0; v-- )
      {
         // Render Base
         glVertex3fv( m_V[v].m_f );
      }
      glEnd();
   }
} // RenderOGL

// ---------------------------------------------------------------------------------------------- //
// Name: Update()
// Desc:
// ---------------------------------------------------------------------------------------------- //
void GeometryPyramid::Update()
{
} // Update


As far as I can tell there are no bugs in this code :)
And as a note I did not try to implement the smooth normals in this class,
that is not the goal here... for that I will eventually make a cone class and post it here.


Offline
 Profile  
 
 Post subject: Follow Up on Pyramid Class
PostPosted: Thu Oct 14, 2010 10:17 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 450
After using the class a bit, i worked with the default numbers in the constructor for iNumSides and found out that if i use 360 as a max number here, it renders a very near perfect cone

So I decided not to implement a cone class for now. I may go back and do it later but, i will have to dive into OpenGL and see how it works with rendering circles.

I will however implent the class if I find that the computation is much less expensive, but so far it runs smooth on my PC with both the cylinder and pyramid class with 360 sides;


Offline
 Profile  
 
 Post subject: Texture Coords Have Been Added To The Pyramid Class
PostPosted: Sun Oct 17, 2010 12:53 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 450
Here is the new code!
#ifndef GEOMETRYPYRAMID_H
#define GEOMETRYPYRAMID_H

// ============================================================================================== //
// FileName: GeometryPyramid.h
// Version: 1.0
// Copyright (c) 2010 by Francis R. Cugler Jr.
// ============================================================================================== //

// Includes
#include "Core.h"
#include "Plane.h"
#include "Geometry.h"

class GeometryPyramid : public Geometry
{
public:
   // Default Constructor And Destructor
   GeometryPyramid( int iNumSides, float fRadius, float fHeight, float fCutOff = 0.0f );
   ~GeometryPyramid();

   // Public Member Functions
   void   Update();
   void   RenderOGL( bool bTextured );

private:
   int      m_iNumSides;
   float   m_fRadius;
   float   m_fHeight;
   float   m_fCutOff;
   float   m_fCutOffRadius;
   float   m_fNewHeight;

   Vector3 *m_N; // Normals
   Vector3 *m_V; // Vertex Coords
   Vector2 *m_T; // Texture Coords

}; // GeometryPyramid

#endif // GEOMETRYPYRAMID_H


// ============================================================================================== //
// FileName: GeometryPyramid.cpp
// Version: 1.0
// Copyright (c) 2010 by Francis R. Cugler Jr.
// ============================================================================================== //

// Includes
#include "stdafx.h"
#include "GeometryPyramid.h"

// ---------------------------------------------------------------------------------------------- //
// Name: GeometryPyramid()
// Desc: Default Constructor
// ---------------------------------------------------------------------------------------------- //
GeometryPyramid::GeometryPyramid( int iNumSides, float fRadius, float fHeight, float fCutOff )
{
   // Save And Correct All Parameters
   if ( iNumSides < 3 )
   {
      iNumSides = 3;
   }
   else if ( iNumSides > 360 )
   {
      iNumSides = 360;
   }
   m_iNumSides = iNumSides;

   if ( fRadius <= 0 )
   {
      fRadius = 1.0f;
   }
   m_fRadius = fRadius;

   if ( fHeight <= 0 )
   {
      fHeight = 1.0f;
   }
   m_fHeight = fHeight;

   if ( fCutOff <= 0 )
   {
      fCutOff = 0.0f;
      m_fCutOff = fCutOff;
   }
   else if ( fCutOff >= m_fHeight )
   {
      fCutOff = fHeight-0.08f;
      m_fCutOff = fCutOff;
   }
   else if ( (fCutOff > 0) || (fCutOff < fHeight)  )
   {
      m_fCutOff = fCutOff;
   }

   m_N = NULL;
   m_V = NULL;
   m_T = NULL;
   
   // Define The Up or Peak Normal This Doesn't Change
   // With Regard To The CutOff Value
   
   if ( fCutOff == 0 )
   {   
      m_N = new Vector3[iNumSides+1];
      m_V = new Vector3[iNumSides+1];
      m_T = new Vector2[iNumSides*2+2];
      
      // Peak Vertex
      m_N[iNumSides] = Vector3( 0.0f, 1.0f, 0.0f );
      m_V[iNumSides] = Vector3( 0.0f, m_fHeight, 0.0f );
      m_T[iNumSides] = Vector2( 0.25f, 0.5f );
   }
   else if ( fCutOff != 0 )
   {
      m_N = new Vector3[iNumSides];
      m_V = new Vector3[iNumSides*2];
      m_T = new Vector2[(iNumSides+1)*2 + iNumSides];
   }
   
   // Vertex And Normals For The Sides
   if ( m_V && m_N && m_T )
   {
      // Memory Allocation Is Okay
                   
      // Assign Texture Along Seem Of Column
      m_T[0]          = Vector2( 0.0f, 0.0f );
      m_T[iNumSides+1] = Vector2( 0.0f, 0.5f );
      
      float fXVal, fZVal;
      for ( int i = 0; i < iNumSides; i++ )
      {
         if ( fCutOff == 0 )
         {
            fXVal = float( fRadius*cos(-i*2*PI/iNumSides) );
            fZVal = float( fRadius*sin(-i*2*PI/iNumSides) );
            
            m_V[i] = Vector3( fXVal, 0, fZVal );
            
            m_T[0]    = Vector2( 0.0f,  0.0f );
            m_T[1]    = Vector2( 0.5f,  0.0f );
            m_T[i+1] = Vector2( 0.25f, 0.5f );

            // Assign Texture Coordinates For Base Of Pyramid
            fXVal = float(0.25*cos(-i*2*PI/iNumSides) + 0.25f );
            fZVal = float(0.25*sin(-i*2*PI/iNumSides) + 0.75f );
            m_T[iNumSides+2+i] = Vector2( fXVal, fZVal );
            
         }
         else if ( fCutOff != 0 )
         {
            // Define Vertexes And Adjust For New Radius
            fXVal = float( fRadius*cos(-i*2*PI/iNumSides) );
            fZVal = float( fRadius*sin(-i*2*PI/iNumSides) );
            m_V[i] = Vector3( fXVal, 0.0f, fZVal );

            
            // Calculate The Angle At Any One Vertex At Base
            float fAngle = (float)(180*(atan(fHeight/fRadius)/PI)); // In Rad
            // Convert fAnlge From Degrees To Radians
            fAngle = ((float)PI*fAngle/180.0f);
            m_fCutOffRadius = fCutOff/(float)tan(fAngle);
            
            // Use The Angle Found To Find The New Height
            float fNewHeight = fHeight - fCutOff;
            m_fNewHeight = fNewHeight;
            fXVal = float( m_fCutOffRadius*cos(-i*2*PI/iNumSides) );
            fZVal = float( m_fCutOffRadius*sin(-i*2*PI/iNumSides) );
            m_V[i+iNumSides] = Vector3( fXVal, m_fNewHeight, fZVal );         
            
            // Assign Texture Coordinates For Top
            m_T[1+i]         = Vector2( float(i+1)/float(iNumSides), 0.0f );
            m_T[iNumSides+2+i] = Vector2( float(i+1)/float(iNumSides), 0.5f - (m_fHeight)/100 );                                 
            
            // Assign Texture Coordinates For Base Of Pyramid
            fXVal = float(0.25*cos(i*2*PI/iNumSides) + 0.25f );
            fZVal = float(0.25*sin(i*2*PI/iNumSides) + 0.75f );
            m_T[(2*iNumSides+2)+i] = Vector2( fXVal, fZVal );
            
         }
      }

      Plane plane;
      // Calculate Normals For Each Side Of The Pyramid
      for ( int n = 0; n < iNumSides; n++ )
      {
         if ( fCutOff == 0 )
         {
            if ( n == (iNumSides-1) )
            {
               plane = Plane( m_V[iNumSides], m_V[n], m_V[0] );
            }
            else
            {
               plane = Plane( m_V[iNumSides], m_V[n], m_V[n+1] );
            }
         }
         else if ( fCutOff != 0 )
         {
            if ( n == (iNumSides-1) )
            {
               plane = Plane( m_V[n+iNumSides], m_V[n], m_V[0] );
            }
            else
            {
               plane = Plane( m_V[n+iNumSides], m_V[n], m_V[n+1] );
            }
         }
         m_N[n] = plane.GetNormal();
      }      
   }
   else
   {
      // Not Enough Memory
      SAFE_DELETE_ARRAY( m_N );
      SAFE_DELETE_ARRAY( m_V );
      SAFE_DELETE_ARRAY( m_T );
   }
         
} // GeometryPyramid

// ---------------------------------------------------------------------------------------------- //
// Name: ~GeometryPyramid()
// Desc: Default Destructor
// ---------------------------------------------------------------------------------------------- //
GeometryPyramid::~GeometryPyramid()
{
   SAFE_DELETE_ARRAY( m_N );
   SAFE_DELETE_ARRAY( m_V );
   SAFE_DELETE_ARRAY( m_T );

} // ~GeometryPyramid

// ---------------------------------------------------------------------------------------------- //
// Name: RenderOGL()
// Desc:
// ---------------------------------------------------------------------------------------------- //
void GeometryPyramid::RenderOGL( bool bTextured )
{
   // Render The Pyramid Using Coordinates
   if ( bTextured )
   {
      // Render Sides
      for ( int v = 0; v < m_iNumSides; v++ )
      {
         // Render Pyramid With Vertex Peak
         if ( m_fCutOff == 0 )
         {
            glBegin( GL_TRIANGLES );
            glNormal3fv( m_N[v].m_f );
            // Check For Last Side First
            if ( v == m_iNumSides - 1 )
            {
               glTexCoord2fv( m_T[0].m_f );
               glVertex3fv( m_V[m_iNumSides-1].m_f );
               glTexCoord2fv( m_T[1].m_f );
               glVertex3fv( m_V[0].m_f );
               glTexCoord2fv( m_T[m_iNumSides].m_f );
               glVertex3fv( m_V[m_iNumSides].m_f );
            }
            else
            {
               glTexCoord2fv( m_T[0].m_f );
               glVertex3fv( m_V[v].m_f );
               glTexCoord2fv( m_T[1].m_f );
               glVertex3fv( m_V[v+1].m_f );
               glTexCoord2fv( m_T[m_iNumSides].m_f );
               glVertex3fv( m_V[m_iNumSides].m_f );
            }
            glEnd();
         }
         else if ( m_fCutOff != 0 ) // Render Pyramid With Top Cap CutOff
         {
            glBegin( GL_QUADS );
            
            glNormal3fv( m_N[v].m_f );
            if ( v == m_iNumSides - 1 )
            {
               
               glTexCoord2fv( m_T[m_iNumSides].m_f );
               glVertex3fv( m_V[0].m_f );
               
               glTexCoord2fv( m_T[2*m_iNumSides+1].m_f );
               glVertex3fv( m_V[m_iNumSides].m_f );
            }
            else
            {
               glTexCoord2fv( m_T[v+1].m_f );
               glVertex3fv( m_V[v+1].m_f );

               glTexCoord2fv( m_T[v+2+m_iNumSides].m_f );
               glVertex3fv( m_V[v+1+m_iNumSides].m_f );
            }
            glTexCoord2fv( m_T[v+m_iNumSides+1].m_f );
            glVertex3fv( m_V[v+m_iNumSides].m_f );

            glTexCoord2fv( m_T[v].m_f );
            glVertex3fv( m_V[v].m_f );

            glEnd();
         }
      }

      // Render Top Cap
      if ( m_fCutOff != 0 )
      {
         // Render Top Cap
         glBegin( GL_POLYGON );
         glNormal3f( 0.0f, 1.0f, 0.0f );
         for ( int v = 0; v < m_iNumSides; v++ )
         {
            glTexCoord2fv( m_T[(2*m_iNumSides+2)+v].m_f );
            glVertex3fv( m_V[v+m_iNumSides].m_f );
         }
         glEnd();
      }
      
      // Render The Base This Does Not Change
      glBegin( GL_POLYGON );
      glNormal3f( 0.0f, -1.0f, 0.0f );
      for ( int v = m_iNumSides-1; v >= 0; v-- )
      {
         if ( m_fCutOff != 0 )
         {
            // Render Base
            glTexCoord2fv( m_T[(3*m_iNumSides+1)-v].m_f );
            glVertex3fv( m_V[v].m_f );
         }
         else if ( m_fCutOff == 0 )
         {
            glTexCoord2fv( m_T[v+m_iNumSides+2].m_f );
            glVertex3fv( m_V[v].m_f );
         }

      }
      glEnd();
   }
   else
   {
      // Not Using Texture Coordinates

      // Render Sides
      for ( int v = 0; v < m_iNumSides; v++ )
      {
         // Render Pyramid With Vertex Peak
         if ( m_fCutOff == 0 )
         {
            glBegin( GL_TRIANGLES );
            glNormal3fv( m_N[v].m_f );
            // Check For Last Side First
            if ( v == m_iNumSides - 1 )
            {
               glVertex3fv( m_V[m_iNumSides-1].m_f );
               glVertex3fv( m_V[0].m_f );
               glVertex3fv( m_V[m_iNumSides].m_f );
            }
            else
            {
               glVertex3fv( m_V[v].m_f );
               glVertex3fv( m_V[v+1].m_f );
               glVertex3fv( m_V[m_iNumSides].m_f );
            }
            glEnd();
         }
         else if ( m_fCutOff != 0 ) // Render Pyramid With Top Cap CutOff
         {
            glBegin( GL_QUADS );
            
            glNormal3fv( m_N[v].m_f );
            if ( v == m_iNumSides - 1 )
            {
               // Adjust Coordinates At The Seam To Wrap Around
               glVertex3fv( m_V[0].m_f );
               glVertex3fv( m_V[m_iNumSides].m_f );
            }
            else
            {
               glVertex3fv( m_V[v+1].m_f );
               glVertex3fv( m_V[v+1+m_iNumSides].m_f );
            }
            glVertex3fv( m_V[v+m_iNumSides].m_f );
            glVertex3fv( m_V[v].m_f );

            glEnd();
         }
      }

      // Render Top Cap
      if ( m_fCutOff != 0 )
      {
         // Render Top Cap
         glBegin( GL_POLYGON );
         glNormal3f( 0.0f, 1.0f, 0.0f );
         for ( int v = 0; v < m_iNumSides; v++ )
         {
            glVertex3fv( m_V[v+m_iNumSides].m_f );
         }
         glEnd();
      }
      
      // Render The Base This Does Not Change
      glBegin( GL_POLYGON );
      glNormal3f( 0.0f, -1.0f, 0.0f );
      for ( int v = m_iNumSides-1; v >= 0; v-- )
      {
         // Render Base
         glVertex3fv( m_V[v].m_f );
      }
      glEnd();
   }
} // RenderOGL

// ---------------------------------------------------------------------------------------------- //
// Name: Update()
// Desc:
// ---------------------------------------------------------------------------------------------- //
void GeometryPyramid::Update()
{
} // Update


It took me some time to get this working right, only thing is if you endup rotating this object about the X,Z axis and look at the base, It does texture right, but the look of it may not be perfect.

If you want the texture that I was using to test this class send me an email at either skilz80@yahoo.com or skilz8099@hotmail.com. The texture I am using I made it myself :)!!! I hope you enjoy the new code!!!


Offline
 Profile  
 
Display posts from previous:  Sort by  
 Page 1 of 1 [ 25 posts ] 

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Jump to:  

cron