It is currently Fri Oct 20, 2017 3:38 am

All times are UTC - 5 hours




 Page 1 of 1 [ 11 posts ] 
Author Message
 Post subject: Shader VMK 56 - Challenge 4
PostPosted: Sun Oct 19, 2014 6:48 pm 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
In this video I present Challenge #4 for you to try. Complete the challenge and post your solution to this forum. The first person that completes this challenge successfully will win 250 download credits.

Good luck to everyone!


Offline
 Profile  
 
 Post subject: Re: Shader VMK 56 - Challenge 4
PostPosted: Sun Oct 19, 2014 10:36 pm 

Joined: Mon Mar 24, 2014 2:25 pm
Posts: 69
Hello Everyone,

Here is my solution with photos at the bottom:

Game specific code (Ignore for loop on images, just there in case we wanted multiple images updated).
Game logic for detecting rotation could probably be more elegant, but it works perfectly.
   // Challenge 4 Code
   if (Chal4Position < 850)
   {
      ++Chal4Position;
      if (Chal4Position < 425)
              Chal4Scale += 0.002f;
      else
         Chal4Scale -= 0.002f;
   }
   else
   {
      Chal4Position = 10;
      Chal4Scale = 1.0f;
   }

   // 1.5708 radians = 90 degrees
   if (Chal4Rotation > -1.5708f && !Turn)
      Chal4Rotation -= 0.02f;
   else
        {
      Turn = true;
      Chal4Rotation += 0.02f;
      if (Chal4Rotation > 1.5708f)
         Turn = false;
   }
   
   if (Images.size() > 0)
   {
      for (uint32 u = 0; u < Images.size(); ++u)
      {
         Images.at(u)->SetTransform(glm::vec3(Chal4Position, 450.f, 0.0f), glm::vec3(Chal4Scale, Chal4Scale, 1.0f), glm::vec3(0.0f, 0.0f, 1.0f), Chal4Rotation);
         Images.at(u)->Render();
      }
   }


Updated TransformMatrix structure:
struct FTransformMatrix
   {
      glm::vec3 Translation;
      glm::vec3 Scale;
      glm::vec3 RotationAxis;      
      float     Rotation;

      uint8   HasTranslation : 1;
      uint8   HasScale : 1;
      uint8   HasRotation : 1;
      uint8   Update : 1;

      FTransformMatrix()
         : HasTranslation(false),
         HasScale(false),
         HasRotation(false),
         Update(true) // Force 1 time update on render
      {}

   } TransformMatrix;


Renamed SetPosition to SetTransform (declaration and definition below, Scale defaults to a 1.0f vector, Rotation defaults to 0 radians):
void SetTransform(const glm::vec3& InPosition, const glm::vec3& InScale = glm::vec3(1.0f, 1.0f, 1.0f), const glm::vec3& InRotationAxis = glm::vec3(), const float InRotation = 0.0f);

void FVisualONE::SetTransform(const glm::vec3& InPosition, const glm::vec3& InScale, const glm::vec3& InRotationAxis, const float InRotation)
{
   if (TransformMatrix.Translation != InPosition || TransformMatrix.Scale != InScale || TransformMatrix.RotationAxis != InRotationAxis || TransformMatrix.Rotation != InRotation)
   {
      TransformMatrix.Translation        = InPosition;
      TransformMatrix.Scale            = InScale;
      TransformMatrix.RotationAxis     = InRotationAxis;
      TransformMatrix.Rotation        = InRotation;
      TransformMatrix.HasTranslation     = (InPosition.x != 0 || InPosition.y != 0 || InPosition.z != 0);
      TransformMatrix.HasScale        = (InScale.x != 1.0f || InScale.y != 1.0f || InScale.z != 1.0f);
      TransformMatrix.HasRotation        = (InRotationAxis.x != 0 || InRotationAxis.y != 0 || InRotationAxis.z != 0 || InRotation != 0);
      TransformMatrix.Update = true;
   }
}


FImage2D Render Update (Default identity matrix for scale, update 0,0 and 1,1 values with x and y scale respectively & use glm::rotate for Rotation Matrix updates) :
      if (TransformMatrix.Update)
      {
         TransformMatrix.Update = false;

         glm::mat4 Translate;
         if (TransformMatrix.HasTranslation)
         {
            Translate[3][0] = TransformMatrix.Translation.x;
            Translate[3][1] = TransformMatrix.Translation.y;
         }
         glm::mat4 Scale(1.0f);
         if (TransformMatrix.HasScale)
         {
            Scale[0][0] = TransformMatrix.Scale.x;
            Scale[1][1] = TransformMatrix.Scale.y;
         }
         glm::mat4 Rotate(1.0f);
         if (TransformMatrix.HasRotation)
         {
            Rotate = glm::rotate(Rotate, TransformMatrix.Rotation, TransformMatrix.RotationAxis);
         }

         Vertices[0].Position = glm::vec2(Translate * Rotate * Scale * glm::vec4(0,      0, 0, 1.0f));
         Vertices[1].Position = glm::vec2(Translate * Rotate * Scale * glm::vec4(0, Size.y, 0, 1.0f));
         Vertices[2].Position = glm::vec2(Translate * Rotate * Scale * glm::vec4(Size.x, 0, 0, 1.0f));
         Vertices[3].Position = glm::vec2(Translate * Rotate * Scale * glm::vec4(Size.x, Size.y, 0, 1.0f));
      }

      BatchManager->Render(Vertices, Config, GetId());


Image

Image

Image


Offline
 Profile  
 
 Post subject: Re: Shader VMK 56 - Challenge 4
PostPosted: Mon Oct 20, 2014 8:09 pm 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
Great work Mebourne. There are a few things you can optimize in your code but overall it looks correct. I'll try to record and post my solution some time this week.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 56 - Challenge 4
PostPosted: Mon Oct 20, 2014 9:01 pm 

Joined: Mon Mar 24, 2014 2:25 pm
Posts: 69
Thanks Marek! Had fun working it last night after seeing your post late. Was groggy getting into work this morning, but had a blast answering the challenge!


Offline
 Profile  
 
 Post subject: Re: Shader VMK 56 - Challenge 4
PostPosted: Wed Oct 22, 2014 12:44 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 449
I've Been Working on this today and this is what I have so far.

This is my updated VisualMko.h
struct TransformMatrix {
   glm::vec3 translation;
   glm::vec3 scale;
   glm::vec3 rotationAxis;
   float rotation;

   unsigned char hasTranslation    : 1;
   unsigned char updateTranslation : 1;
   unsigned char hasScale          : 1;
   unsigned char updateScale       : 1;
   unsigned char hasRotation       : 1;
   unsigned char updateRotation    : 1;

   TransformMatrix() :
      // Translation
      hasTranslation( false ),
      updateTranslation( true ), // Force 1 Time Update On Render
      hasScale( false ),
      updateScale( false ),
      hasRotation( false ),
      updateRotation( false )
   {}
} _transformMatrix;


void   setPosition( const glm::vec3& position );
void   setScale( const glm::vec3& scale );
void   setRotation( const float& rotation, const glm::vec3& rotationAxis );



VisualMko.cpp
// ----------------------------------------------------------------------------
// setPosition()
void VisualMko::setPosition( const glm::vec3& position ) {
   if ( _transformMatrix.translation != position ) {
       _transformMatrix.translation      = position;
       _transformMatrix.hasTranslation   = ( position.x != 0 || position.y != 0 || position.z != 0 );
       _transformMatrix.updateTranslation = true;
   }
} // setPosition

// ----------------------------------------------------------------------------
// setScale()
void VisualMko::setScale( const glm::vec3& scale ) {
   if ( _transformMatrix.scale != scale ) {
       _transformMatrix.scale      = scale;
       _transformMatrix.hasScale   = ( scale.x != 1.0f || scale.y != 1.0f || scale.z != 1.0f );
       _transformMatrix.updateScale = true;
   }
} // setScale

// ----------------------------------------------------------------------------
// setRotation()
void VisualMko::setRotation( const float& rotation, const glm::vec3& rotationAxis ) {
   if ( _transformMatrix.rotation != rotation || _transformMatrix.rotationAxis != rotationAxis ) {
       _transformMatrix.rotation      = rotation;
       _transformMatrix.rotationAxis  = rotationAxis;
       _transformMatrix.hasRotation   = ( rotation != 0 || (rotationAxis.x != 0 || rotationAxis.y != 0 || rotationAxis.z != 0) );
       _transformMatrix.updateRotation = true;
   }
} // setRotation



Updated Image2d.cpp render()
// ----------------------------------------------------------------------------
// render()
void Image2d::render() {
   if ( 1 == _version ) {
      _pShaderManager->setTexture( 0, U_TEXTURE0_SAMPLER_2D, _textureInfo.uTextureId );

      glBindVertexArray( _vao );
      glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, nullptr );
      glBindVertexArray( 0 );
   } else {
      // Version 2.0
      // Update Vertices
      if ( _transformMatrix.updateTranslation || _transformMatrix.updateScale || _transformMatrix.updateRotation ) {
          _transformMatrix.updateTranslation = false;
          _transformMatrix.updateScale       = false;
          _transformMatrix.updateRotation    = false;

          glm::mat4 translate; // Identity
          if ( _transformMatrix.hasTranslation ) {
             translate[3][0] = _transformMatrix.translation.x;
             translate[3][1] = _transformMatrix.translation.y;
          }
         
          glm::mat4 scale(1.0f); // Identity
          if ( _transformMatrix.hasScale ) {
             scale[0][0] = _transformMatrix.scale.x;
             scale[1][1] = _transformMatrix.scale.y;
          }
          
          glm::mat4 rotate(1.0f); // Identity
          if ( _transformMatrix.hasRotation ) {
            rotate = glm::rotate( rotate, _transformMatrix.rotation, _transformMatrix.rotationAxis );
          }

         // One can replace the 3 matrices with this result matrix
         // const glm::mat4 result = translate * rotate * scale;

          // Apply Transformation To All 4 Vertices
         _vVertices[0].position = glm::vec2( translate * rotate * scale * glm::vec4(       0,       0, 0, 1.0f ) );
         _vVertices[1].position = glm::vec2( translate * rotate * scale * glm::vec4(       0, _size.y, 0, 1.0f ) );
         _vVertices[2].position = glm::vec2( translate * rotate * scale * glm::vec4( _size.x,       0, 0, 1.0f ) );
         _vVertices[3].position = glm::vec2( translate * rotate * scale * glm::vec4( _size.x, _size.y, 0, 1.0f ) );
      }
      renderBatch();
   }
} // render


and the Game.cpp render()
// ----------------------------------------------------------------------------
// render()
void Game::render() {
   
   glEnable( GL_BLEND );

   // Render Code Goes Here
   if ( _vImage2d.size() > 0 ) {
      for ( unsigned u = 0; u < _vImage2d.size(); ++u ) {
         glm::mat4 m4Model = glm::translate( glm::mat4(), glm::vec3( 0, 100, 0 ) );

         glm::mat4 m4Result = _m4Projection * m4Model;
         _pShaderManager->setUniform( U_MVP_MATRIX, m4Result );

         if ( u == 1 ) {
            // Translate
            static int iX = 0;
            ++iX;
            _vImage2d.at(u)->setPosition( glm::vec3( iX + 10, 50, 0.0f ) );
            
            // Scale
            static float scaleAmount = 1.0f;   
            if ( iX < 425 ) {
               // Scale Larger
               scaleAmount += 0.002f;
            } else {
               // Scale Larger
               scaleAmount -= 0.002f;
            }
            _vImage2d.at(u)->setScale( glm::vec3( scaleAmount, scaleAmount, 1.0f ) );            

            // Reset
            if ( iX == 850 ) {
               iX = 0;
               scaleAmount = 1.0f;
               _vImage2d.at(u)->setPosition( glm::vec3( iX + 10, 50, 0.0f ) );
               _vImage2d.at(u)->setScale( glm::vec3( scaleAmount, scaleAmount, 1.0f ) );
               //_vImage2d.at(u)->setRotation( rotationInRadians, glm::vec3( 0, 0, 1.0f ) );

            }   

            // Rotate
            // 90 Degrees = 1.570796f Radians
            const float  pi_halves = 1.5708f;
            float rotationSpeed = pi_halves/4;
            static float rotationInRadians = 0.0f;            

            // Start Rotation
            if ( rotationInRadians <= 0.0f ) {
               rotationInRadians -= rotationSpeed;

               // Switch Direction
               if ( rotationInRadians == pi_halves || rotationInRadians == 0.0f ) {
                  rotationSpeed *= (-1.0f);
               }
            }

            // Prevent Large Angles
            if ( rotationInRadians == (pi_halves*4) || rotationInRadians == (pi_halves*-4) ) {
               rotationInRadians = 0.0f;            
            }
            
            _vImage2d.at(u)->setRotation( rotationInRadians, glm::vec3( 0, 0, 1.0f ) );
         
         }
         _vImage2d.at( u )->render();
      }
   }

   _pBatchManager->emptyAll();

   glDisable( GL_BLEND );

} // render


At this point. I can translate to the specified point then reset its location. I can scale the image at the same time, I am able to rotate, however when I set the bounds for the angles of rotation I have having trouble with it switching directions. I've tried multiple things, using while & for loops, using switch statement, and even tried using a bool flag variable and for some reason I can not seem to get it to change direction of rotation.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 56 - Challenge 4
PostPosted: Wed Oct 22, 2014 8:15 pm 

Joined: Mon Mar 24, 2014 2:25 pm
Posts: 69
Hey Skilz80, looking good. For your rotation problem, here is what I see.

On each render pass you test if rotationInRadians <= 0.0f. If it is you substract some radians based on speed. Once you are equal to pi_halves you switch the rotation angle. The issues seems to be each time you run through your loop you set rotationSpeed back to a positive number. You need to change rotationSpeed to static so it doesn't reset itself each engine tick. On a side note that rotation is blazing fast at ~11.25 degrees or .3927 radians per tick. Is your GLM maybe still using degrees for it's rotate functions? If so that would make sense on being able to see it at 60 frames per second or more and you it thinks you are sending .3927 degrees per tick. If this is the case, just be aware degrees is depreciated for the latest GLM.

Here is my implementation from the challenge solution cleaned up a bit with a bool variable who's name actually makes sense...

static bool RotateCW = false;
if (Chal4Rotation > -1.5708f && !RotateCW)
   Chal4Rotation -= 0.02f;
else
{
   RotateCW = true;
   Chal4Rotation += 0.02f;
   if (Chal4Rotation > 1.5708f)
      RotateCW = false;
}


Offline
 Profile  
 
 Post subject: Re: Shader VMK 56 - Challenge 4
PostPosted: Thu Oct 23, 2014 1:23 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 449
No, I set the macro in stdafx.h #define GLM_FORCE_RADIANS before any glm includes. I over looked the fact of the rotationSpeed not being static. but my rotation increments should be at pi/8 by definition that would be 4 frames to make 90 degrees but I am not getting that. How can I tell if the GLM / OpenGL functions are working in radians vs degrees? I'll keep trying and thank you for suggestions and feedback. Also when I try to use your implementation on rotating, it does not rotate when I run the application.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 56 - Challenge 4
PostPosted: Thu Oct 23, 2014 3:39 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 449
After some time and some thinking, I used a different Approach and used a little bit of basic trig, geometry and algebra and this is what I came up with. My comments explains my logic and reasoning. It works but it is 100% perfect yet. As the object rotates in a +angle or Counter Clockwise on the Unit Circle it wants to over rotate a little more then 90% but as it comes back in the opposite direction it switches at the appropriate time. The Speed Factor Needs to Be Constant In This Situation. If you change the speed because of the for loop it will rotate much more then 90 degrees.

// ----------------------------------------------------------------------------
// render()
void Game::render() {
   
   glEnable( GL_BLEND );

   // Render Code Goes Here
   if ( _vImage2d.size() > 0 ) {
      for ( unsigned u = 0; u < _vImage2d.size(); ++u ) {
         glm::mat4 m4Model = glm::translate( glm::mat4(), glm::vec3( 0, 100, 0 ) );

         glm::mat4 m4Result = _m4Projection * m4Model;
         _pShaderManager->setUniform( U_MVP_MATRIX, m4Result );

         if ( u == 1 ) {
            // Translate
            static int iX = 0;
            ++iX;
            _vImage2d.at(u)->setPosition( glm::vec3( iX, 50, 0.0f ) );
            
            // Scale
            static float scaleAmount = 1.0f;   
            if ( iX < 425 ) {
               // Scale Larger
               //scaleAmount += 0.002f;
            } else {
               // Scale Larger
               //scaleAmount -= 0.002f;
            }
            _vImage2d.at(u)->setScale( glm::vec3( scaleAmount, scaleAmount, 1.0f ) );               

            // Rotate
            // 90 Degrees = 1.570796f Radians
            // Using Trig And Basic Geometry We Know That The Width Is 150 and We Are Starting At 10 In
            // The +x Direction. It Should Take 150 Ticks Or Frames To Make Our 90 Degrees or PI/2 Rotation. So The Vertex
            // We Are Rotating About That Started At Location (10,0) After This Turn Would Be At Location (160,0)
            // Our Second Vertex That Defines Our Width Of 150 Started At (160,0) Is Now Located At ( 160, 150 )
            // Then The Following Step Will Do The Same Except Rotate In The Opposite Direction.
            // This Should Give Us Our Step Size Needed. At 90 Degrees or PI/2 We Know That Sin = 1 & Cos = 0
            // So If It Should Take 150 Ticks To Make A 90 Degree Turn We Need To Divide PI/2 By 150

            const float   pi_halves = 1.5708f;
            const float   stepSize  = pi_halves/150;
            const float speed     = 0.5f;
            static float direction = -1.0f;
            static float rotation = 0.0f;            


            if ( iX % 150 == 0 ) {
               direction *= -1.0f;
            }

            for ( int i = 0; i < 150; ++i ) {
               // Start Rotation                
               rotation += (stepSize*direction)*speed;               
               _vImage2d.at(u)->setRotation( rotation, glm::vec3( 0.0f, 0.0f, 1.0f ) );               
            }
            
            // Reset
            if ( iX == 850 ) {
               iX = 0;
               scaleAmount = 1.0f;
               _vImage2d.at(u)->setPosition( glm::vec3( iX + 10, 50, 0.0f ) );
               _vImage2d.at(u)->setScale( glm::vec3( scaleAmount, scaleAmount, 1.0f ) );
               rotation = 0.0f;
               direction = -1.0f;
               //_vImage2d.at(u)->setRotation( rotationInRadians, glm::vec3( 0, 0, 1.0f ) );

            }         
         }
         _vImage2d.at( u )->render();
      }
   }

   _pBatchManager->emptyAll();

   glDisable( GL_BLEND );

} // render

} // namespace vmk


Offline
 Profile  
 
 Post subject: Re: Shader VMK 56 - Challenge 4
PostPosted: Thu Oct 23, 2014 11:45 am 

Joined: Mon Mar 24, 2014 2:25 pm
Posts: 69
Quote:
Also when I try to use your implementation on rotating, it does not rotate when I run the application.


Hey Skilz, not sure which part of my implementation you were using, if just the game render code updating the rotation the only thing I could think of is ensuring the right variable names were shipped to your Image2D->SetTransform. I initialized Chal4Rotation outside what I posted in the code block.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 56 - Challenge 4
PostPosted: Thu Oct 23, 2014 12:11 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 449
I see, but I changed my algorithm from doing a rotation based on time increments to using a summation of step sizes. The only thing with my implementation is that I did some pre-calculations before hand instead of using a variable for the width, which can easily be integrated into the
formula.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 56 - Challenge 4
PostPosted: Tue Nov 11, 2014 9:56 pm 

Joined: Mon Mar 24, 2014 2:25 pm
Posts: 69
So I've been working on the engine quite a bit lately. In my first iteration of the Batch3D process, I had followed the same translation effort as the Batch2D and did all the translations on the CPU. While still plenty over 60FPS (when I turn off Vsync with WGLSwapIntervalEXT for Windows), I figured I'd go ahead and update to do the transforms on the GPU in the vertex shader... WOW was that an improvement, no more iterating over the vectors. But what this also means is that I'm not using the Batch3D process anymore due to each unique model needing it's own ModelView matrix for transformation reasons. I'm sure there is a clever way to do it, but for now I let all the Font and 2D images go through the batch process and stream mesh objects each with their own DrawElements call.

Doing this also fixed a long time bug I had with doing the translation on the CPU where for some reason the y value kept ever increasing only on my Batch3D. It's hard to explain, but I had looked at it for a day and couldn't track down the bug. Glad to say it's gone with the GPU transformations.

Can't wait till the next VMK.

Got a simple terrain working via the heightmap process, optimized as much as possible utilizing degenerate triangle strips and all the proper scaling. Vertex normals are pre-computed using common algorithms you can google white papers on including averaging nearby triangle normals. As I want to be able to dynamically update the heightmap, the next step is to re-compute normals only local to where modifications have been made in the game along with learning more about physically based rendering and moving to the additional material maps it requires.

Image


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

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 0 guests


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