It is currently Fri Apr 28, 2017 8:39 pm

All times are UTC - 5 hours




 Page 1 of 1 [ 15 posts ] 
Author Message
 Post subject: Shader VMK 35 - Create Surface
PostPosted: Fri Nov 01, 2013 10:37 pm 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1094
Location: Ontario Canada
In this video I demonstrate how to use Photoshop to generate 3D surfaces for rendering in the engine. Near the end of the video I also present the second challenge.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Tue Jan 28, 2014 11:05 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 447
I am using different height values coming in from our original vertex shader and checking to see if they are in a specified range if so I am either adding or subtracting a predefined color value with transparency to the original color coming in to our vertex shader. I am using the existing fragment shader.

This is The New Shader Program In the Game's Constructor

// ----------------------------------------------------------------------------
// Game()
Game::Game() :
Engine( glm::uvec2( 3, 3 ) ),
_backgroundColor( COLOR_BLACK ),
_m4Projection( 1.0f ) {

   // Set Background Color
   glClearColor( _backgroundColor.r,
              _backgroundColor.g,
              _backgroundColor.b,
              _backgroundColor.a );

   const glm::uvec2 gamePixelSize = _pSettings->getGameSize();
   float fAspectRatio = gamePixelSize.x / static_cast<float>( gamePixelSize.y );
   _m4Projection = glm::perspective( 45.0f, fAspectRatio, 0.1f, 100.0f );

   // Setup Shader Manager
   ShaderProgramSettings shaderProgramSettings( P_TEST, "Shaders/basic.vert", "Shaders/basic.frag" );   
   shaderProgramSettings.addVariable( ShaderAttribute( A_POSITION, AT_FLOAT_VEC3 ), "inPosition" );
   shaderProgramSettings.addVariable( ShaderAttribute( A_COLOR,    AT_FLOAT_VEC4 ), "inColor" );
   shaderProgramSettings.addVariable( ShaderUniform( U_MVP_MATRIX, UT_FLOAT_MAT4 ), "modelViewProjectionMatrix" );
   _pShaderManager->create( shaderProgramSettings );

   _pShaderManager->enable( P_TEST );


   ShaderProgramSettings colorHeightShader( P_COLOR_HEIGHT, "Shaders/colorHeight.vert", "Shaders/basic.frag" );
   colorHeightShader.addVariable( ShaderAttribute( A_POSITION, AT_FLOAT_VEC3 ), "inPosition" );
   colorHeightShader.addVariable( ShaderAttribute( A_COLOR,    AT_FLOAT_VEC4 ), "inColor" );
   colorHeightShader.addVariable( ShaderUniform( U_MVP_MATRIX, UT_FLOAT_MAT4 ), "modelViewProjectionMatrix" );
   _pShaderManager->create( colorHeightShader );


   MkoFileReader fileRaw( "Assets/surface1.mko" );
   _pSurface3d.reset( fileRaw.getMko<Surface3d>() );

} // Game


In my render function I use the existing model view matrix and apply a slight translation in the positive y direction after the original render call so that the second render call is not exactly in the same place. I then use blending and enable my shader and set the model view matrix to the new shader

// ----------------------------------------------------------------------------
// render()
void Game::render() {
   glm::mat4 m4View = glm::lookAt( glm::vec3( 0.0f, 7.0f, 13.0f ), glm::vec3( 0.0f, 0.0f, 0.0f ), glm::vec3( 0.0f, 1.0f, 0.0f ) );

   float fAngle = 70.0f * sin( _fCurrentTimeInSeconds * 0.4f ) - 70.0f;

   glm::mat4 m4Model = glm::mat4(); // Identity
   m4Model = glm::rotate( m4Model, fAngle, glm::vec3( 0.0f, 1.0f, 0.0f ) );
   m4Model = glm::translate( m4Model, glm::vec3( -3.0f, 0, -2.0f ) );

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


   // Render Code Goes Here
   _pSurface3d->render();

   m4Model = glm::translate( m4Model, glm::vec3( 0.0f, 0.025f, 0.0f ) );
   m4Result = _m4Projection * m4View * m4Model;

   glEnable( GL_BLEND );
   _pShaderManager->enable( P_COLOR_HEIGHT );
   _pShaderManager->setUniform( U_MVP_MATRIX, m4Result );
   _pSurface3d->render();
   glDisable( GL_BLEND );


} // render


Here is my new vertex shader
#version 330

layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec4 inColor;

out vec4 exColor;


uniform mat4  modelViewProjectionMatrix;

// ----------------------------------------------------------------------------
// main()
void main() {
   vec3 position = inPosition;
   vec4 color = inColor;

   if ( position.y >= 0.0f && position.y < 0.1f ) {
      color += vec4( 0.0f, 0.0f, 0.0f, 0.5f );      // Black
   }
   if ( position.y >= 0.1f && position.y < 0.2f ) {
      color += vec4( 7.0f, 0.0f, 0.0f, 0.5f );      // Red
   }
   if ( position.y >= 0.2f && position.y < 0.3f ) {
      color += vec4( 7.0f, 0.3f, 0.1f, 0.5f );      // Orange
   }
   if ( position.y >= 0.3f && position.y < 0.4f ) {
      color -= vec4( 7.0f, 7.0f, 0.0f, 0.5f );      // Yellow
   }
   if ( position.y >= 0.4f && position.y < 0.5f ) {
       color -= vec4( 0.0f, 7.0f, 0.0f, 0.5f );      // Green
   }
   if ( position.y >= 0.5f && position.y < 0.6f ) {
      color += vec4( 0.0f, 0.0f, 7.0f, 0.5f );      // Blue
   }
   if ( position.y >= 0.6f && position.y < 0.7f ) {
      color -= vec4( 7.0f, 0.0f, 7.0f, 0.5f );      // Violet
   }
   if ( position.y >= 0.7f && position.y < 0.8f ) {
       color -= vec4( 0.65f, 0.65f, 0.65f, 5.0f );      // Gray
   }
   if ( position.y >= 0.8f && position.y < 0.9f ) {
      color -= vec4( 1.0f, 1.0f, 1.0f, 5.0f );      // White
   }
   if ( position.y >= 0.9f && position.y <= 1.0f ) {
      color = inColor;                        // Color Passed In
   }
      
   gl_Position = modelViewProjectionMatrix * vec4( position, 1.0 );
   exColor = color;
} // main


I am sure there are other ways to do this and probably more efficient and cleaner code, but this is what I was able to come up with so far since my knowledge in OpenGL Shading language is limited. Please feel free to comment for suggestions where I could of improved this.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Wed Jan 29, 2014 8:46 am 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1094
Location: Ontario Canada
This is a good start. You have the right idea to look at the Y value to determine the color to use. Could you post a screen shot showing what your surface looks like when trying to render the surface shown in the VMK.

One easy optimization that you can add to your shader is to include "else" statements with all your "if". The way that you have written your code right now forces the vertex shader to always do 10 if statement checks even if only the first one is true. By using an "else" you can skip all the checks once you find a condition that matches your check.

In the C++ code I see that you I rendering the surface 2 times, once at the original location, and the second time slightly higher (0.025f units above the first). The correct solution can be done all in one render pass.

Here is a hint on how to solve the challenge. When you are rendering the surface, look at the height. Now adjust the current pixel color to be lighter or darker depending on the value of the height.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Wed Jan 29, 2014 2:25 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 447
Okay thank you for the tips. I will make the adjustments. Here is an image to see my outcome.

Image


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Wed Jan 29, 2014 3:12 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 447
I made the appropriate changes to my source code and my shader. Here is the new code.
The Game's Constructor has stayed the same the differences are in the render() call and in the vertex shader.
I also removed the translation, second render call and blending factors.

// ----------------------------------------------------------------------------
// render()
void Game::render() {
   glm::mat4 m4View = glm::lookAt( glm::vec3( 0.0f, 7.0f, 13.0f ), glm::vec3( 0.0f, 0.0f, 0.0f ), glm::vec3( 0.0f, 1.0f, 0.0f ) );

   float fAngle = 70.0f * sin( _fCurrentTimeInSeconds * 0.4f ) - 70.0f;

   glm::mat4 m4Model = glm::mat4(); // Identity
   m4Model = glm::rotate( m4Model, fAngle, glm::vec3( 0.0f, 1.0f, 0.0f ) );
   m4Model = glm::translate( m4Model, glm::vec3( -3.0f, 0, -2.0f ) );

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

   _pShaderManager->enable( P_COLOR_HEIGHT );
   _pShaderManager->setUniform( U_MVP_MATRIX, m4Result );

   // Render Code Goes Here
   _pSurface3d->render();


} // render


I used the same check for the height values, only this time I took a percentage of each color component and subtracted it from the original color. The lower the height value the higher the percentage is subtracted the higher the height value the lower the percentage is subtracted. This gives the result as follows. The lower the height value the darker the color, the higher the height value the brighter the color. I also added the appropriate if else for improved efficiency.

Here is the new shader
#version 330

layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec4 inColor;

out vec4 exColor;


uniform mat4  modelViewProjectionMatrix;

// ----------------------------------------------------------------------------
// main()
void main() {
   vec3 position = inPosition;
   vec4 color = inColor;
   float red;
   float green;
   float blue;

   if ( position.y >= 0.0f && position.y < 0.1f ) {
      red   = color.r * 0.9f;
      green = color.g * 0.9f;
      blue  = color.b * 0.9f;
      color = vec4(  color.r - red,  color.g - green, color.b - blue, 1.0f );
   }
   else if ( position.y >= 0.1f && position.y < 0.2f ) {
      red   = color.r * 0.8f;
      green = color.g * 0.8f;
      blue  = color.b * 0.8f;
      color = vec4(  color.r - red, color.g - green, color.b - blue, 1.0f );
   }
   else if ( position.y >= 0.2f && position.y < 0.3f ) {
      red   = color.r * 0.7f;
      green = color.g * 0.7f;
      blue  = color.b * 0.7f;
      color = vec4(  color.r - red, color.g - green, color.b - blue, 1.0f );
   }
   else if ( position.y >= 0.3f && position.y < 0.4f ) {
      red   = color.r * 0.6f;
      green = color.g * 0.6f;
      blue  = color.b * 0.6f;
      color = vec4(  color.r - red, color.g - green, color.b - blue, 1.0f );
   }
   else if ( position.y >= 0.4f && position.y < 0.5f ) {
      red   = color.r * 0.5f;
      green = color.g * 0.5f;
      blue  = color.b * 0.5f;
      color = vec4(  color.r - red, color.g - green, color.b - blue, 1.0f );
   }
   else if ( position.y >= 0.5f && position.y < 0.6f ) {
      red   = color.r * 0.4f;
      green = color.g * 0.4f;
      blue  = color.b * 0.4f;
      color = vec4(  color.r - red, color.g - green, color.b - blue, 1.0f );
   }
   else if ( position.y >= 0.6f && position.y < 0.7f ) {
      red   = color.r * 0.3f;
      green = color.g * 0.3f;
      blue  = color.b * 0.3f;
      color = vec4(  color.r - red, color.g - green, color.b - blue, 1.0f );
   }
   else if ( position.y >= 0.7f && position.y < 0.8f ) {
       red   = color.r * 0.2f;
      green = color.g * 0.2f;
      blue  = color.b * 0.2f;
      color = vec4(  color.r - red, color.g - green, color.b - blue, 1.0f );
   }
   else if ( position.y >= 0.8f && position.y < 0.9f ) {
      red   = color.r * 0.1f;
      green = color.g * 0.1f;
      blue  = color.b * 0.1f;
      color = vec4(  color.r - red, color.g - green, color.b - blue, 1.0f );
   }
   else if ( position.y >= 0.9f && position.y <= 1.0f ) {
      
      color = inColor;
   }
      
   gl_Position = modelViewProjectionMatrix * vec4( position, 1.0 );
   exColor = color;
} // main


Here is a screen shot of my resulting application

Image


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Wed Jan 29, 2014 3:29 pm 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1094
Location: Ontario Canada
Looking better. You still have some code in the C++ that you can remove since it now doesn't do anything and the vertex shader can be simplified with a general equation rather than having all those if/else statements. But I won't worry about that for now.

If you move your color calculation from the vertex shader to the fragment shader how does this affect your output? Post a screen shot of the result!

Also why is your surface rendered incorrectly? It seems like your values are shifted over by a bit since the tall part of the surface is not at the very end, but rather a few unit moved forward.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Wed Jan 29, 2014 7:06 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 447
I commented out these calls in the render().
// ----------------------------------------------------------------------------
// render()
void Game::render() {
   glm::mat4 m4View = glm::lookAt( glm::vec3( 0.0f, 7.0f, 13.0f ), glm::vec3( 0.0f, 0.0f, 0.0f ), glm::vec3( 0.0f, 1.0f, 0.0f ) );

   float fAngle = 70.0f * sin( _fCurrentTimeInSeconds * 0.4f ) - 70.0f;

   glm::mat4 m4Model = glm::mat4(); // Identity
   m4Model = glm::rotate( m4Model, fAngle, glm::vec3( 0.0f, 1.0f, 0.0f ) );
   m4Model = glm::translate( m4Model, glm::vec3( -3.0f, 0, -2.0f ) );

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

   _pShaderManager->enable( P_COLOR_HEIGHT );
   _pShaderManager->setUniform( U_MVP_MATRIX, m4Result );

   // Render Code Goes Here
   _pSurface3d->render();


} // render


I modified my Shader and this is my improved algorithm.

#version 330

layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec4 inColor;

out vec4 exColor;

uniform mat4  modelViewProjectionMatrix;

// ----------------------------------------------------------------------------
// main()
void main() {
   vec3 position = inPosition;
   vec4 color = inColor;
   
   float intensity = 0.8f; // The Higher The Value The Brighter.
                     // If This Value = 0 The Original Color Is Returned
   float red;
   float green;
   float blue;

   red      = color.r * position.y * intensity;
   green   = color.g * position.y * intensity;
   blue   = color.b * position.y * intensity;
   color = vec4( color.r + red, color.g + green, color.b + blue, 1.0f );
         
   gl_Position = modelViewProjectionMatrix * vec4( position, 1.0 );
   exColor = color;
} // main


Here is my screen shot of the improved algorithm

Image

I have yet to try this in the fragment shader instead of the vertex shader. When I get a little more time, I will work on it.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Thu Jan 30, 2014 6:15 am 

Joined: Sun Jul 21, 2013 5:17 pm
Posts: 17
I still have some perplexity on shaders and how they work.
I'm sure you will explain it in the future but... how will shaders work with more assets like we had in the previus engine made in OpenGL 1.0?
Or, we enable the shader, the shaders enabled works only with the assets rendered after and not the others?
Am I missing something? :-(


For example in this challenge we can render it correctly with only one shader program, we don't need more:


Game constructor
   ShaderProgramSettings shaderColorHeight( P_COLOR_HEIGHT,"Shaders/colorHeight.vert","Shaders/basic.frag");
   shaderColorHeight.addVariable(ShaderAttribute(A_POSITION, AT_FLOAT_VEC3), "inPosition");
   shaderColorHeight.addVariable(ShaderAttribute(A_COLOR, AT_FLOAT_VEC4), "inColor");
   shaderColorHeight.addVariable(ShaderUniform(U_MVP_MATRIX, UT_FLOAT_MAT4), "modelViewProjectionMatrix");

   _pShaderManager->create(shaderColorHeight);
   _pShaderManager->enable(P_COLOR_HEIGHT);



Render()
   glm::mat4 m4View = glm::lookAt( glm::vec3( 0.0f, 7.0f, 13.0f ), glm::vec3( 0.0f, 0.0f, 0.0f ), glm::vec3( 0.0f, 1.0f, 0.0f ) );

   float fAngle = 70.0f * sin( _fCurrentTimeInSecnds * 0.4f ) - 70.0f;

   glm::mat4 m4Model = glm::mat4();
   m4Model = glm::rotate( m4Model, fAngle, glm::vec3( 0.0f, 1.0f, 0.0f ) );
   m4Model = glm::translate( m4Model, glm::vec3( -3.0f, 0, -2.0f ) );

   glm::mat4 m4Result = _m4Projection * m4View * m4Model;   

   
   
      
   _pShaderManager->enable(P_COLOR_HEIGHT);
   _pShaderManager->setUniform(U_MVP_MATRIX, m4Result);
   _pSurface3d->render();

   



ColorHeight.vert
#version 330

in vec3 inPosition;
in vec4 inColor;


out vec4 exColor;
out vec4 exPosition;

uniform mat4 modelViewProjectionMatrix;


void main(){   
   
   vec4 color = inColor;
   vec3 pos = inPosition;

   color.r = color.r*pos.y;
   color.g = color.g*pos.y;
   color.b = color.b*pos.y;

   exColor = color;
   exPosition  = modelViewProjectionMatrix * vec4(inPosition, 1.0);
   gl_Position = exPosition;
   
}



result
Image


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Thu Jan 30, 2014 8:36 am 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1094
Location: Ontario Canada
davidemo89 wrote:
I still have some perplexity on shaders and how they work.
I'm sure you will explain it in the future but... how will shaders work with more assets like we had in the previus engine made in OpenGL 1.0?
Or, we enable the shader, the shaders enabled works only with the assets rendered after and not the others?


Looking good! Think of shaders as little programs that run on your graphics card that decide what to do with data that your C++ program sends to them. The vertex shader executes once per vertex that it gets and is responsible for transforming the vertex into something that can be rasterized.

The fragment shader executes once per "pixel" that the rasterizer outputs and it is responsible for updating the framebuffer with colors and depth.

So for the game Ghost Toast, you can create one vertex and one fragment shader that replicates the default OpenGL fixed function pipeline and get the exact same results. The nice thing about shaders is that you can create more than one for your program so that you can render things in multiple passes to apply special effects that would normally be to expensive to do on the CPU.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Thu Jan 30, 2014 11:48 am 

Joined: Sun Jul 21, 2013 5:17 pm
Posts: 17
Thank you marek :-) another question.

With the code I have now if I add another assets like a sphere, the shader program I use now will automaticaly work on the vertex of the sphere too? So the same program will run on the sphere too?
How can I run two different progrm on different model? :-(

if you are asking it yourself... yes, I'm impatience =D


Last edited by davidemo89 on Thu Jan 30, 2014 12:12 pm, edited 1 time in total.

Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Thu Jan 30, 2014 11:58 am 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1094
Location: Ontario Canada
davidemo89 wrote:
So the same program will run on the sphere too?
How can I run two different progrm on different model?


That is correct, once you enable a shader, it will be applied to all geometry that is rendered afterwards. You will typically do something like this:

enable shader program 1:
render all geometry that user that shader

enable shader program 2:
render all geometry that user that shader

etc

So you need to batch your render calls otherwise you'll be switching shaders a lot which can be expensive. Batching is coming up in the Shader Engine series.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Thu Jan 30, 2014 12:24 pm 

Joined: Sun Jul 21, 2013 5:17 pm
Posts: 17
Yay! thank you =D


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Thu Jan 30, 2014 3:11 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 447
Marek wrote:
Looking better. You still have some code in the C++ that you can remove since it now doesn't do anything and the vertex shader can be simplified with a general equation rather than having all those if/else statements. But I won't worry about that for now.

If you move your color calculation from the vertex shader to the fragment shader how does this affect your output? Post a screen shot of the result!

Also why is your surface rendered incorrectly? It seems like your values are shifted over by a bit since the tall part of the surface is not at the very end, but rather a few unit moved forward.



From what little bit I know about shaders from working with Direct X's HLSL you can produce the same result in the fragment or pixel shader, however the fragment shader runs many more times then the vertex shader and can produce an overhead and cause a bottleneck in the application.

My surface is being rendered correctly from what I can see in my source code. After I removed the translation, the second render call and changed the shaders algorithm to a simple equation instead of a bunch of if else statements I am getting the result I am expecting. There is a big drop off towards the middle, I believe that is from how I used the brush in photo shop.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Thu Apr 09, 2015 1:58 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 447
While working on this video in VS2013, I am using the newest version of GLM which is version 9.6.3 When I started to run the code to see the surface rotate I was getting really weird behavior. I checked my code about 3 or 4 times and didn't see any apparent errors. I then was looking at the rotate function and was thinking: Did you calculate degrees or radians that you were passing into the glm::rotate function, so I tried converting it to degrees at first and that had really interesting output but wasn't right then I converted to radians ( multiply by PI ) then divide by 180, and viola! I was getting the appropriate rendering.

Due to this it dawned on me that I was using the newest version of GLM and these videos are using I think version 9.3.4 or something like that. So I went to their website and was reading their document's on changes, deprecations, removals, and bug fixes. Come to find out I think ever since their version 9.5.4 or 9.5.5 they started to change their functions to accept radians. They did have a define that you could use to Force Radians, but now with any newer version that flag is set automatically. So if you are using your engine and decide to upgrade to the newest version of GLM, any of your function calls you need to make sure you are calculating them in radians. If the equation you are doing is giving you degrees and you need radians, just pass the whole equation into glm::radians( your equation in degrees here ) and that should resolve any rendering or transformation issues.


Offline
 Profile  
 
 Post subject: Re: Shader VMK 35 - Create Surface
PostPosted: Tue Jan 26, 2016 8:02 am 

Joined: Wed Sep 30, 2015 3:10 am
Posts: 7
Post a screen shot of the result!
จีคลับ


Offline
 Profile  
 
Display posts from previous:  Sort by  
 Page 1 of 1 [ 15 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