Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 5 of 5

Thread: Trying to draw multiple objects with different shaders

  1. #1
    Newbie Newbie
    Join Date
    Jun 2017
    Posts
    3

    Problem using multiple shaders while rendering

    Hello, I have a basic scene of a player (triangle) and a skybox. The skybox has its own shader program. Here is how I am attempting to draw both entities:

    Code :
    void Game::Render()
    {
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
    	Shader.UpdateCameraPos(Camera.GetCameraPosition());
     
    	RenderSkybox();
    	RenderPlayer();
            SDL_GL_SwapWindow(MainWindow);
    }
    void Game::RenderSkybox()
    {
    	SkyboxShader.UpdateSkyboxTexture(m_SkyboxTextureID);
    	SkyboxShader.UpdateTransform(m_SkyboxTransform, m_Camera);
    	SkyboxShader.UseProgram();
    	Skybox.Draw();
    }
    void Game::RenderPlayer()
    {
    	Shader.UseProgram();
            Shader.UpdateTransform(m_Transformation, m_Camera);
    	Texture.BindTexture(0);
    	Player.Draw();
    }

    However, what's currently happening, the player is being drawn but the skybox is not. If I swap RenderSkybox() with RenderPlayer() like so:

    void Game::Render()
    {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    Shader.UpdateCameraPos(Camera.GetCameraPosition()) ;

    RenderPlayer();
    RenderSkybox();

    SDL_GL_SwapWindow(m_MainWindow);
    }

    Then nothing gets rendered to the screen (the result is a black screen). Why does this happen?

    Thanks for reading my thread.

  2. #2
    Newbie Newbie
    Join Date
    Jun 2017
    Posts
    3

    Trying to draw multiple objects with different shaders

    Hello, I am trying to draw two objects with different shaders, a skybox and a player (triangle). But for some reason, one of the shaders sort of override each other and I don't know why...

    Here is how I am rendering things:

    Code :
    void Game::RenderSkybox()
    {
    	SkyboxShader.UpdateSkyboxTexture(SkyboxTextureID);
    	SkyboxShader.UpdateTransform(SkyboxTransform, Camera);
    	SkyboxShader.UseProgram();
    	Skybox.Draw();
    }
    void Game::RenderPlayer()
    {
    	SimpleShader.UpdateTransform(Transformation, Camera);
    	SimpleShader.UseProgram();
    	Texture.BindTexture(0);
    	Player.Draw();
    }
     
    void Game::Render()
    {
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
    	SimpleShader.UpdateCameraPos(Camera.GetCameraPosition());
     
    	RenderSkybox();
    	RenderPlayer();
     
            SDL_GL_SwapWindow(MainWindow);
    }

    EDIT: So if I render in that order, I could see the skybox but the player is rendered in an incorrect manner (I think it is taking the scale from the skybox shader and applying it to the player...) and if I render the player before the skybox, then the player doesn't get rendered... What is causing this behavior to occur?

    Thank you for reading my thread.
    Last edited by ErickHawking; 06-18-2017 at 06:49 AM.

  3. #3
    Junior Member Newbie
    Join Date
    Mar 2017
    Posts
    20
    Hello Erick, I think I know what's going on with your program. The glUniform calls change the currently bound program's uniform state. So, for example, when you do this:

    Code :
    void Game::RenderSkybox()
    {
    	SkyboxShader.UpdateSkyboxTexture(SkyboxTextureID);
    	SkyboxShader.UpdateTransform(SkyboxTransform, Camera);
    	SkyboxShader.UseProgram();
    	Skybox.Draw();
    }
    void Game::RenderPlayer()
    {
    	SimpleShader.UpdateTransform(Transformation, Camera);
    	SimpleShader.UseProgram();
    	Texture.BindTexture(0);
    	Player.Draw();
    }

    When you're rendering the player, the transform will only affect the currently bound shader which is your skybox shader and not your simple shader. So whatever program passed to glUseProgram most recently. To fix this, you must switch shader programs before modifying any uniforms. Try this:

    Code :
    void Game::RenderSkybox()
    {
            SkyboxShader.UseProgram();
    	SkyboxShader.UpdateSkyboxTexture(SkyboxTextureID);
    	SkyboxShader.UpdateTransform(SkyboxTransform, Camera);	
    	Skybox.Draw();
    }
    void Game::RenderPlayer()
    {
            SimpleShader.UseProgram();
    	SimpleShader.UpdateTransform(Transformation, Camera);	
    	Texture.BindTexture(0);
    	Player.Draw();
    }

    Hope this helped.

  4. #4
    Newbie Newbie
    Join Date
    Jun 2017
    Posts
    3
    Quote Originally Posted by TheFearlessHobbit View Post
    Hello Erick, I think I know what's going on with your program. The glUniform calls change the currently bound program's uniform state. So, for example, when you do this:

    Code :
    void Game::RenderSkybox()
    {
    	SkyboxShader.UpdateSkyboxTexture(SkyboxTextureID);
    	SkyboxShader.UpdateTransform(SkyboxTransform, Camera);
    	SkyboxShader.UseProgram();
    	Skybox.Draw();
    }
    void Game::RenderPlayer()
    {
    	SimpleShader.UpdateTransform(Transformation, Camera);
    	SimpleShader.UseProgram();
    	Texture.BindTexture(0);
    	Player.Draw();
    }

    When you're rendering the player, the transform will only affect the currently bound shader which is your skybox shader and not your simple shader. So whatever program passed to glUseProgram most recently. To fix this, you must switch shader programs before modifying any uniforms. Try this:

    Code :
    void Game::RenderSkybox()
    {
            SkyboxShader.UseProgram();
    	SkyboxShader.UpdateSkyboxTexture(SkyboxTextureID);
    	SkyboxShader.UpdateTransform(SkyboxTransform, Camera);	
    	Skybox.Draw();
    }
    void Game::RenderPlayer()
    {
            SimpleShader.UseProgram();
    	SimpleShader.UpdateTransform(Transformation, Camera);	
    	Texture.BindTexture(0);
    	Player.Draw();
    }

    Hope this helped.
    Oh wow really? This is such an important thing I'm surprised how many of the books and tutorials I've read didn't mention this... thank you for letting me know about this, it works now.

  5. #5
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,467
    Uniforms in the default uniform block (top-level variables in the shader, set with glUniform()) are part of the program object.

    Named uniform blocks allow you to have uniform variables which are stored in a buffer object. This allows you to use the same variable state with multiple programs, or use a single program in multiple contexts with each instance having their own variables.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •