Skip to content
Permalink
Browse files

Switch rendering to proper multipass

Now rendering works as:
1) Depth prepass (currently redudant)
2) Shadow maps (depth only)
3) Color and lighting (color(containing ambient) + ambient + normal)
4) SSAO pass (occulusion)
5) Combine (color minus occulusion * ambient)
  • Loading branch information...
enginmanap committed Dec 12, 2018
1 parent 0dd1d46 commit 6ebfe205da841e24448a4813db2e70a461a73641
@@ -17,7 +17,7 @@ ENDIF()

include(libs/CmakeLists.txt)

set(SOURCE_FILES src/Utils/Logger.cpp src/Utils/Logger.h src/ImGuiHelper.cpp src/ImGuiHelper.h src/main.cpp src/SDL2Helper.cpp src/SDL2Helper.h src/GLHelper.cpp src/GLHelper.h src/GameObjects/Model.cpp src/GameObjects/Model.h src/World.cpp src/World.h src/InputHandler.cpp src/InputHandler.h src/Camera.cpp src/Camera.h src/GameObjects/SkyBox.cpp src/GameObjects/SkyBox.h src/Assets/TextureAsset.cpp src/Assets/TextureAsset.h src/Assets/CubeMapAsset.cpp src/Assets/CubeMapAsset.h src/GLSLProgram.cpp src/GLSLProgram.h src/Renderable.h src/Utils/GLMConverter.cpp src/Utils/GLMConverter.h src/BulletDebugDrawer.cpp src/BulletDebugDrawer.h src/GUI/GUITextBase.cpp src/GUI/GUITextBase.h src/GUI/GUILayer.cpp src/GUI/GUILayer.h src/PhysicalRenderable.cpp src/PhysicalRenderable.h src/GUI/GUIRenderable.cpp src/GUI/GUIRenderable.h src/FontManager.cpp src/FontManager.h src/GUI/GUIFPSCounter.cpp src/GUI/GUIFPSCounter.h src/Utils/AssimpUtils.cpp src/Utils/AssimpUtils.h src/GameObjects/Light.cpp src/GameObjects/Light.h src/Material.cpp src/Material.h src/Assets/AssetManager.cpp src/Assets/AssetManager.h src/Assets/Asset.cpp src/Assets/Asset.h src/Assets/ModelAsset.cpp src/Assets/ModelAsset.h src/Assets/MeshAsset.cpp src/Assets/MeshAsset.h src/Assets/BoneNode.cpp src/Assets/BoneNode.h src/Utils/GLMUtils.h src/Options.h src/GUI/GUITextDynamic.cpp src/GUI/GUITextDynamic.h src/AI/ActorInterface.cpp src/AI/AIMovementGrid.cpp src/GameObjects/Players/PhysicalPlayer.cpp src/GameObjects/Players/PhysicalPlayer.h src/CameraAttachment.h src/GameObjects/Players/FreeMovingPlayer.cpp src/GameObjects/Players/FreeMovingPlayer.h src/GameObjects/Players/FreeCursorPlayer.cpp src/GameObjects/Players/FreeCursorPlayer.cpp src/GameObjects/Players/Player.h src/GameObjects/GameObject.h src/WorldLoader.cpp src/WorldLoader.h src/WorldSaver.cpp src/WorldSaver.h src/GameObjects/TriggerObject.cpp src/GameObjects/TriggerObject.h src/Transformation.cpp src/Assets/Animations/AnimationAssimp.h src/Assets/Animations/AnimationAssimp.cpp src/Assets/Animations/AnimationLoader.h src/Assets/Animations/AnimationLoader.cpp src/Assets/Animations/AnimationNode.cpp src/Assets/Animations/AnimationNode.h src/Assets/Animations/AnimationCustom.cpp src/Assets/Animations/AnimationCustom.h src/GamePlay/LimonAPI.h src/GamePlay/LimonAPI.cpp src/GamePlay/TriggerInterface.h src/GamePlay/AnimateOnTrigger.cpp src/GamePlay/AnimateOnTrigger.h src/GamePlay/AddGuiTextOnTrigger.cpp src/GamePlay/AddGuiTextOnTrigger.h src/GamePlay/TriggerInterface.cpp src/GamePlay/RemoveGuiTextOnTrigger.h src/GamePlay/RemoveGuiTextOnTrigger.cpp src/AnimationSequencer.cpp src/AnimationSequencer.h src/GUI/GUICursor.cpp src/GUI/GUICursor.h src/GameObjects/GUIText.cpp src/GameObjects/GUIText.h src/Options.cpp src/ALHelper.cpp src/ALHelper.h src/Assets/SoundAsset.cpp src/Assets/SoundAsset.h src/GameObjects/Sound.cpp src/GameObjects/Sound.h src/GamePlay/AddSoundToObject.cpp src/GamePlay/AddSoundToObject.h src/GUI/GUIImageBase.cpp src/GUI/GUIImageBase.h src/GameObjects/GUIImage.cpp src/GameObjects/GUIImage.h src/GameObjects/GUIButton.cpp src/GameObjects/GUIButton.h src/GameObjects/Players/MenuPlayer.cpp src/GameObjects/Players/MenuPlayer.h src/main.h src/GamePlay/ChangeWorldOnTrigger.cpp src/GamePlay/ChangeWorldOnTrigger.h src/GamePlay/QuitGameOnTrigger.cpp src/GamePlay/QuitGameOnTrigger.h src/GamePlay/ReturnPreviousWorldOnTrigger.cpp src/GamePlay/ReturnPreviousWorldOnTrigger.h src/Assets/Animations/AnimationAssimpSection.cpp src/GameObjects/GUIAnimation.cpp src/GameObjects/GUIAnimation.h src/GamePlay/PlayerExtensionInterface.cpp src/GameObjects/ModelGroup.cpp src/GameObjects/ModelGroup.h src/Utils/CombiningObject.cpp src/Utils/CombiningObject.h)
set(SOURCE_FILES src/Utils/Logger.cpp src/Utils/Logger.h src/ImGuiHelper.cpp src/ImGuiHelper.h src/main.cpp src/SDL2Helper.cpp src/SDL2Helper.h src/GLHelper.cpp src/GLHelper.h src/GameObjects/Model.cpp src/GameObjects/Model.h src/World.cpp src/World.h src/InputHandler.cpp src/InputHandler.h src/Camera.cpp src/Camera.h src/GameObjects/SkyBox.cpp src/GameObjects/SkyBox.h src/Assets/TextureAsset.cpp src/Assets/TextureAsset.h src/Assets/CubeMapAsset.cpp src/Assets/CubeMapAsset.h src/GLSLProgram.cpp src/GLSLProgram.h src/Renderable.h src/Utils/GLMConverter.cpp src/Utils/GLMConverter.h src/BulletDebugDrawer.cpp src/BulletDebugDrawer.h src/GUI/GUITextBase.cpp src/GUI/GUITextBase.h src/GUI/GUILayer.cpp src/GUI/GUILayer.h src/PhysicalRenderable.cpp src/PhysicalRenderable.h src/GUI/GUIRenderable.cpp src/GUI/GUIRenderable.h src/FontManager.cpp src/FontManager.h src/GUI/GUIFPSCounter.cpp src/GUI/GUIFPSCounter.h src/Utils/AssimpUtils.cpp src/Utils/AssimpUtils.h src/GameObjects/Light.cpp src/GameObjects/Light.h src/Material.cpp src/Material.h src/Assets/AssetManager.cpp src/Assets/AssetManager.h src/Assets/Asset.cpp src/Assets/Asset.h src/Assets/ModelAsset.cpp src/Assets/ModelAsset.h src/Assets/MeshAsset.cpp src/Assets/MeshAsset.h src/Assets/BoneNode.cpp src/Assets/BoneNode.h src/Utils/GLMUtils.h src/Options.h src/GUI/GUITextDynamic.cpp src/GUI/GUITextDynamic.h src/AI/ActorInterface.cpp src/AI/AIMovementGrid.cpp src/GameObjects/Players/PhysicalPlayer.cpp src/GameObjects/Players/PhysicalPlayer.h src/CameraAttachment.h src/GameObjects/Players/FreeMovingPlayer.cpp src/GameObjects/Players/FreeMovingPlayer.h src/GameObjects/Players/FreeCursorPlayer.cpp src/GameObjects/Players/FreeCursorPlayer.cpp src/GameObjects/Players/Player.h src/GameObjects/GameObject.h src/WorldLoader.cpp src/WorldLoader.h src/WorldSaver.cpp src/WorldSaver.h src/GameObjects/TriggerObject.cpp src/GameObjects/TriggerObject.h src/Transformation.cpp src/Assets/Animations/AnimationAssimp.h src/Assets/Animations/AnimationAssimp.cpp src/Assets/Animations/AnimationLoader.h src/Assets/Animations/AnimationLoader.cpp src/Assets/Animations/AnimationNode.cpp src/Assets/Animations/AnimationNode.h src/Assets/Animations/AnimationCustom.cpp src/Assets/Animations/AnimationCustom.h src/GamePlay/LimonAPI.h src/GamePlay/LimonAPI.cpp src/GamePlay/TriggerInterface.h src/GamePlay/AnimateOnTrigger.cpp src/GamePlay/AnimateOnTrigger.h src/GamePlay/AddGuiTextOnTrigger.cpp src/GamePlay/AddGuiTextOnTrigger.h src/GamePlay/TriggerInterface.cpp src/GamePlay/RemoveGuiTextOnTrigger.h src/GamePlay/RemoveGuiTextOnTrigger.cpp src/AnimationSequencer.cpp src/AnimationSequencer.h src/GUI/GUICursor.cpp src/GUI/GUICursor.h src/GameObjects/GUIText.cpp src/GameObjects/GUIText.h src/Options.cpp src/ALHelper.cpp src/ALHelper.h src/Assets/SoundAsset.cpp src/Assets/SoundAsset.h src/GameObjects/Sound.cpp src/GameObjects/Sound.h src/GamePlay/AddSoundToObject.cpp src/GamePlay/AddSoundToObject.h src/GUI/GUIImageBase.cpp src/GUI/GUIImageBase.h src/GameObjects/GUIImage.cpp src/GameObjects/GUIImage.h src/GameObjects/GUIButton.cpp src/GameObjects/GUIButton.h src/GameObjects/Players/MenuPlayer.cpp src/GameObjects/Players/MenuPlayer.h src/main.h src/GamePlay/ChangeWorldOnTrigger.cpp src/GamePlay/ChangeWorldOnTrigger.h src/GamePlay/QuitGameOnTrigger.cpp src/GamePlay/QuitGameOnTrigger.h src/GamePlay/ReturnPreviousWorldOnTrigger.cpp src/GamePlay/ReturnPreviousWorldOnTrigger.h src/Assets/Animations/AnimationAssimpSection.cpp src/GameObjects/GUIAnimation.cpp src/GameObjects/GUIAnimation.h src/GamePlay/PlayerExtensionInterface.cpp src/GameObjects/ModelGroup.cpp src/GameObjects/ModelGroup.h src/PostProcess/QuadRenderBase.cpp src/PostProcess/QuadRenderBase.h src/PostProcess/CombinePostProcess.h src/PostProcess/CombinePostProcess.cpp src/PostProcess/SSAOPostProcess.cpp src/PostProcess/SSAOPostProcess.h)

add_executable(LimonEngine ${SOURCE_FILES})

@@ -7,15 +7,17 @@ in VS_FS {
} from_vs;

uniform sampler2D diffuseSpecularLighted;
uniform sampler2D ambientWithSSAO;
uniform sampler2D ambient;
uniform sampler2D ssao;

void main()
{

vec4 baseColor = texture(diffuseSpecularLighted, from_vs.textureCoordinates).rgba;
vec3 ambientFactor = texture(ambientWithSSAO, from_vs.textureCoordinates).rgb;
vec3 ambientFactor = texture(ambient, from_vs.textureCoordinates).rgb;
float ssao = texture(ssao, from_vs.textureCoordinates).r;

finalColor = baseColor + vec4(ambientFactor, 0.0);
finalColor = baseColor - (vec4(ambientFactor, 0.0) * ssao);
}


@@ -156,46 +156,12 @@ void main(void) {

normalOutput = normal;

float occlusion = 0.0;

if(length(playerTransforms.position - from_vs.fragPos) < 100) {
vec3 randomVec = texture(ssaoNoiseSampler, from_vs.fragPos.xy * playerTransforms.noiseScale).xyz;

vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);

float uRadius = 0.5f;
for(int i = 0; i < ssaoSampleCount; ++i){
// get sample position
vec3 samplePosition = TBN * ssaoKernel[i]; // From tangent to view-space
samplePosition = samplePosition * uRadius;
samplePosition += vec3(from_vs.fragPos);

vec4 offset = vec4(samplePosition, 1.0);
offset = playerTransforms.cameraProjection * offset; // from view to clip-space
offset.xyz /= offset.w; // perspective divide
offset.xyz = offset.xyz * 0.5 + 0.5; // transform to range 0.0 - 1.0

float sampleDepth = texture(ssaoSampler, offset.xy).r;

vec3 realElement = calcViewSpacePos(vec3(offset.xy, sampleDepth));
vec3 kernelElement = calcViewSpacePos(offset.xyz);

float rangeCheck= abs(realElement.z - kernelElement.z) < 1 ? 1.0 : 0.0;
occlusion += (realElement.z >= kernelElement.z ? 1.0 : 0.0) * rangeCheck;
}

occlusion = occlusion / ssaoSampleCount;
}
occlusion = 1 - occlusion;

vec3 lightingColorFactor;
if((material.isMap & 0x0008)!=0) {
ambientColor = vec3(texture(ambientSampler, from_vs.textureCoord));
} else {
ambientColor = material.ambient * occlusion;
ambientColor = material.ambient;
}
vec3 lightingColorFactor = ambientColor;

float shadow;
for(int i=0; i < NR_POINT_LIGHTS; ++i){
@@ -421,8 +421,8 @@ GLHelper::GLHelper(Options *options): options(options) {
glBindTexture(GL_TEXTURE_2D, normalMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, screenWidth, screenHeight, 0, GL_RGB, GL_FLOAT, nullptr);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
@@ -462,10 +462,41 @@ GLHelper::GLHelper(Options *options): options(options) {
unsigned int attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers(3, attachments);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "default frame buffer is not complete!" << std::endl;
std::cerr << "coloring frame buffer is not complete!" << std::endl;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);

// SSAO Framebuffer
glGenFramebuffers(1, &ssaoGenerationFrameBuffer);

glGenTextures(1, &ssaoMap);
glBindTexture(GL_TEXTURE_2D, ssaoMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, screenWidth, screenHeight, 0, GL_RGB, GL_FLOAT, nullptr);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glBindTexture(GL_TEXTURE_2D, 0);

glBindFramebuffer(GL_FRAMEBUFFER, ssaoGenerationFrameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, ssaoMap, 0);

glGenRenderbuffers(1, &rboDepth2);
glBindRenderbuffer(GL_RENDERBUFFER, rboDepth2);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, screenWidth, screenHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth2);
unsigned int attachments2[2] = { GL_NONE, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, attachments2);
GLenum fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (fbStatus != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "SSAO frame buffer is not complete: " << fbStatus << ": " << gluErrorString(fbStatus) << std::endl;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);

// SSAO Framebuffer


/****************************** SSAO NOISE **************************************/
std::uniform_real_distribution<GLfloat> randomFloats(0.0, 1.0); // generates random floats between 0.0 and 1.0
@@ -690,12 +721,26 @@ void GLHelper::switchRenderToColoring() {
checkErrors("switchRenderToColoring");
}

void GLHelper::switchRenderToSSAOGeneration() {
glViewport(0, 0, screenWidth, screenHeight);
glBindFramebuffer(GL_FRAMEBUFFER, ssaoGenerationFrameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, ssaoMap, 0);
state->attachTexture(depthMap, 1);
state->attachTexture(normalMap, 2);
state->attachTexture(noiseTexture, 3);
glCullFace(GL_BACK);
checkErrors("switchRenderToColoring");
}



void GLHelper::switchRenderToCombining(){
glViewport(0, 0, screenWidth, screenHeight);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//we combine diffuse+specular lighted with ambient / SSAO
state->attachTexture(diffuseAndSpecularLightedMap, 1);
state->attachTexture(ambientMap, 2);
state->attachTexture(ssaoMap,3);
//glEnable(GL_CULL_FACE);
checkErrors("switchRenderToCombining");

@@ -853,7 +898,7 @@ void GLHelper::reshape() {
glViewport(0, 0, options->getScreenWidth(), options->getScreenHeight());
aspect = float(options->getScreenHeight()) / float(options->getScreenWidth());
perspectiveProjectionMatrix = glm::perspective(options->PI/3.0f, 1.0f / aspect, 0.01f, 10000.0f);
inverseTransposeProjection = glm::transpose(glm::inverse(perspectiveProjectionMatrix));
inverseTransposeProjection = glm::inverse(perspectiveProjectionMatrix);
orthogonalProjectionMatrix = glm::ortho(0.0f, (float) options->getScreenWidth(), 0.0f, (float) options->getScreenHeight());
checkErrors("reshape");
}
@@ -205,6 +205,10 @@ class GLHelper {
GLuint diffuseAndSpecularLightedMap;
GLuint ambientMap;
GLuint rboDepth;
GLuint rboDepth2;

GLuint ssaoGenerationFrameBuffer;
GLuint ssaoMap;

unsigned int noiseTexture;

@@ -326,6 +330,8 @@ class GLHelper {
glClear(GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, depthOnlyFrameBuffer);
glClear(GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, ssaoGenerationFrameBuffer);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//clear for default

@@ -401,6 +407,7 @@ class GLHelper {
void switchRenderToDepthPrePass();

void switchRenderToColoring();
void switchRenderToSSAOGeneration();

void switchRenderToCombining();

@@ -46,7 +46,6 @@ Model::Model(uint32_t objectID, AssetManager *assetManager, const float mass, co
animatedProgram = new GLSLProgram(glHelper, "./Engine/Shaders/Model/vertexAnimated.glsl",
"./Engine/Shaders/Model/fragment.glsl", true);
this->setSamplersAndUBOs(animatedProgram);
generateAndSetSSAOKernels(animatedProgram, 64);
}
//set up the program to render object
meshMeta->program = animatedProgram;
@@ -58,7 +57,6 @@ Model::Model(uint32_t objectID, AssetManager *assetManager, const float mass, co
nonAnimatedProgram = new GLSLProgram(glHelper, "./Engine/Shaders/Model/vertex.glsl",
"./Engine/Shaders/Model/fragment.glsl", true);
this->setSamplersAndUBOs(nonAnimatedProgram);
generateAndSetSSAOKernels(nonAnimatedProgram, 64);
}
meshMeta->program = nonAnimatedProgram;
}
@@ -128,33 +126,6 @@ Model::Model(uint32_t objectID, AssetManager *assetManager, const float mass, co
}
}

void Model::generateAndSetSSAOKernels(GLSLProgram *programToSet, uint32_t kernelSize) const {
// generate sample kernel
// ----------------------
std::vector<glm::vec3> ssaoKernel;
std::uniform_real_distribution<GLfloat> randomFloats(0.0, 1.0); // generates random floats between 0.0 and 1.0
std::default_random_engine generator;
for (unsigned int i = 0; i < kernelSize; ++i){
glm::vec3 sample(randomFloats(generator) * 2.0 - 1.0, randomFloats(generator) * 2.0 - 1.0, randomFloats(generator));
sample = glm::normalize(sample);
//sample *= randomFloats(generator);
float scale = float(i) / kernelSize;

// scale samples s.t. they're more aligned to center of kernel
scale = glm::lerp(0.1f, 1.0f, scale * scale);
sample *= scale;
ssaoKernel.push_back(sample);
//std::cout << "sampleKernel" << glm::to_string(sample) << std::endl;
}

if(!programToSet->setUniform("ssaoKernel[0]", ssaoKernel)) {
std::cerr << "uniform variable \"ssaoKernel\" couldn't be set" << std::endl;
}
if(!programToSet->setUniform("ssaoSampleCount", (int32_t)ssaoKernel.size())) {
std::cerr << "uniform variable \"ssaoSampleCount\" couldn't be set" << std::endl;
}
}

void Model::setupForTime(long time) {
if(animated && !animationLastFramePlayed) {
//check if we need to blend
@@ -241,8 +241,6 @@ class Model : public PhysicalRenderable, public GameObject {
selectedBoneID = attachmentBoneID;
return getAttachmentTransform(attachmentBoneID);
}

void generateAndSetSSAOKernels(GLSLProgram *programToSet, uint32_t kernelSize) const;
};

#endif //LIMONENGINE_MODEL_H
@@ -0,0 +1,15 @@
//
// Created by engin on 12.12.2018.
//

#include "CombinePostProcess.h"
#include "../GLSLProgram.h"

CombinePostProcess::CombinePostProcess(GLHelper* glHelper) : QuadRenderBase(glHelper) {
initializeProgram();
}

void CombinePostProcess::initializeProgram() {
program = new GLSLProgram(glHelper, "./Engine/Shaders/CombineAll/vertex.glsl",
"./Engine/Shaders/CombineAll/fragment.glsl", false);
}
@@ -0,0 +1,18 @@
//
// Created by engin on 12.12.2018.
//

#ifndef LIMONENGINE_COMBINEPOSTPROCESS_H
#define LIMONENGINE_COMBINEPOSTPROCESS_H

#include "QuadRenderBase.h"

class CombinePostProcess : public QuadRenderBase {
void initializeProgram() override;

public:
CombinePostProcess(GLHelper* glHelper);
};


#endif //LIMONENGINE_COMBINEPOSTPROCESS_H
Oops, something went wrong.

0 comments on commit 6ebfe20

Please sign in to comment.
You can’t perform that action at this time.