Purpose of the Sample:
This sample demonstrates how to write your own custom MSAA resolve. The following example shades the jagged edges red.
CGame.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
#ifndef __CGAME__ #define __CGAME__ #include <glad/glad.h> #include "shader_s.h" class Model; class Mesh; class CGame { public: CGame() {}; void Initialize(unsigned int screenWidth, unsigned int screenHeight); void Shutdown(); void Render(); void OnResize(int screenWidth, int screenHeight); private: void SetupGPUProgram(); void SetupModel(); void SetupFullscreenQuad(); Shader* m_pShaderPass0; Shader* m_pShaderPass1; Shader* m_pShaderStencilPass; Shader* m_pShaderBlitPass; Model* m_pManModel; Model* m_pStencilModel; GLuint m_ColorTextureId; GLuint m_IntermediateFBOId; Mesh* m_pFullscreenQuad; unsigned int m_Width; unsigned int m_Height; }; #endif |
CGame.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
#include "CGame.h" #define STB_IMAGE_IMPLEMENTATION #include "stb_image/stb_image.h" #include "Model.h" #include "Mesh.h" #include "glm/mat4x4.hpp" #include "glm/vec3.hpp" #include "glm/glm.hpp" #include "glm/gtc/matrix_transform.hpp" #include "glm/gtc/type_ptr.hpp" #include void CGame::Initialize(unsigned int screenWidth, unsigned int screenHeight) { m_Width = screenWidth; m_Height = screenHeight; SetupGPUProgram(); SetupModel(); SetupFullscreenQuad(); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glEnable(GL_STENCIL_TEST); glEnable(GL_MULTISAMPLE); GLuint depthStencilId; glGenFramebuffers(1, &m_IntermediateFBOId); glBindFramebuffer(GL_FRAMEBUFFER, m_IntermediateFBOId); glGenTextures(1, &m_ColorTextureId); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_ColorTextureId); glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB8, m_Width, m_Height, GL_TRUE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_ColorTextureId, 0); glGenRenderbuffers(1, &depthStencilId); glBindRenderbuffer(GL_RENDERBUFFER, depthStencilId); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, screenWidth, screenHeight); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilId); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) { // Great! } glBindFramebuffer(GL_FRAMEBUFFER, 0); } void CGame::Shutdown() { } void CGame::OnResize(int width, int height) { m_Width = width; m_Height = height; glViewport(0, 0, m_Width, m_Height); glScissor(0, 0, m_Width, m_Height); } void CGame::Render() { static auto startTime = std::chrono::high_resolution_clock::now(); auto currentTime = std::chrono::high_resolution_clock::now(); float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count(); time = 0.0f; float camYOffset = -0.5f; float camZOffset = 5.0f; glEnable(GL_MULTISAMPLE); glBindFramebuffer(GL_FRAMEBUFFER, m_IntermediateFBOId); glClearColor(0.0f, 1.0f, 0.0f, 1.0f); glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Draw the Filled Man glm::mat4 model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)); glm::mat4 view; view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, -2.0f + camYOffset, -10.0f + camZOffset)); glm::mat4 projection; projection = glm::perspective(glm::radians(60.0f), m_Width / static_cast(m_Height), 0.03f, 100.0f); glm::mat4 mvp = projection * view * model; m_pShaderPass0->use(); m_pShaderPass0->setMatrix4x4("modelMatrix", glm::value_ptr(model)); m_pShaderPass0->setMatrix4x4("viewMatrix", glm::value_ptr(view)); m_pShaderPass0->setMatrix4x4("projectionMatrix", glm::value_ptr(projection)); m_pShaderPass0->setMatrix4x4("mvpMatrix", glm::value_ptr(mvp)); m_pShaderPass0->setFloat("time", time); glDepthFunc(GL_LEQUAL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); m_pManModel->meshes[0].Draw(*m_pShaderPass0); // Blit intermediate FBO to backbuffer FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); m_pShaderBlitPass->use(); glActiveTexture(0); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_ColorTextureId); glDepthFunc(GL_ALWAYS); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); m_pFullscreenQuad->Draw(*m_pShaderBlitPass); } void CGame::SetupModel() { m_pManModel = new Model(); m_pManModel->Load("man.obj"); m_pStencilModel = new Model(); m_pStencilModel->Load("quad.obj"); } void CGame::SetupGPUProgram() { m_pShaderPass0 = new Shader("vertexPass0.glsl", "fragmentPass0.glsl"); m_pShaderBlitPass = new Shader("vertexBlit.glsl", "fragmentBlit.glsl"); } void CGame::SetupFullscreenQuad() { vector vertices; float positions[4][3] = { { -1, -1, 0.3f }, { -1, 1, 0.3f }, { 1, 1, 0.3f }, { 1, -1, 0.3f } }; float uvs[4][2] = { { 0,0 }, { 0,1 }, { 1,1 }, { 1,0 } }; float indicesVals[6] = { 0,1,2, 0,2,3 }; for (int i = 0; i < 4; ++i) { Vertex vertex; vertex.Position.x = positions[i][0]; vertex.Position.y = positions[i][1]; vertex.Position.z = positions[i][2]; vertex.TexCoords.x = uvs[i][0]; vertex.TexCoords.y = uvs[i][1]; vertices.push_back(vertex); } vector indices(indicesVals, indicesVals + 6); m_pFullscreenQuad = new Mesh(vertices, indices); } |
vertexPass0.glsl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#version 330 core layout (location = 0) in vec3 position; layout (location = 1) in vec3 normal; uniform mat4 modelMatrix; uniform mat4 viewMatrix; uniform mat4 projectionMatrix; uniform mat4 mvpMatrix; uniform float time; out vec4 fsNormal; void main() { vec4 pos = mvpMatrix * vec4(position.xyz, 1); fsNormal = vec4(normal.xyz, 0); gl_Position = pos; } |
fragmentPass0.glsl
1 2 3 4 5 6 7 8 9 10 |
#version 330 core out vec4 FragColor; in vec4 fsNormal; void main() { vec3 color = vec3(0,0,1); FragColor = vec4(color.rgb, 1.0f); } |
vertexBlit.glsl – Custom MSAA Resolve
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#version 330 core layout (location = 0) in vec3 position; layout (location = 1) in vec3 normal; layout (location = 2) in vec2 uv; uniform float time; out vec2 fsUV; out float fsTime; void main() { fsUV = uv; fsTime = time; gl_Position = vec4(position.xyz, 1); } |
fragmentBlit.glsl – Custom MSAA Resolve
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#version 330 core out vec4 FragColor; in vec2 fsUV; in float fsTime; uniform sampler2DMS colorBufferTextureMS; void main() { ivec2 size = textureSize(colorBufferTextureMS); ivec2 uv = ivec2(size * fsUV); vec3 color0 = texelFetch(colorBufferTextureMS, uv, 0).rgb; vec3 color1 = texelFetch(colorBufferTextureMS, uv, 1).rgb; vec3 color2 = texelFetch(colorBufferTextureMS, uv, 2).rgb; vec3 color3 = texelFetch(colorBufferTextureMS, uv, 3).rgb; vec3 color = (color0 + color1 + color2 + color3) * 0.25; float t = abs(step(color.g, 0.5) + step(color.b, 0.5)) - 1.0; color = mix(color, vec3(1,0,0), t); FragColor = vec4(color.rgb, 1.0f); } |