// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2018 NVIDIA Corporation. All rights reserved. #include "SSAOHelper.h" #include "foundation/PxMat44.h" const char *ssaoFilterVS = STRINGIFY( void main(void) { gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = gl_Vertex * 2.0 - 1.0; } ); const char *ssaoFilterHFS = STRINGIFY( uniform sampler2D ssaoTex; uniform float sx; void main (void) { float SSAO = 0.0; for(int x = -2; x <= 2; x++) { SSAO += texture2D(ssaoTex,vec2(x * sx + gl_TexCoord[0].s,gl_TexCoord[0].t)).r * (3.0 - abs(float(x))); } gl_FragColor = vec4(vec3(SSAO / 9.0),1.0); gl_FragColor.w = gl_FragColor.x; } ); const char *ssaoFilterVFS = STRINGIFY( uniform sampler2D ssaoTex; uniform float sy; void main (void) { float SSAO = 0.0; for(int y = -2; y <= 2; y++) { SSAO += texture2D(ssaoTex,vec2(gl_TexCoord[0].s,y * sy + gl_TexCoord[0].t)).r * (3.0 - abs(float(y))); } gl_FragColor = vec4(vec3(pow((SSAO / 9.0),1.5)),1.0); gl_FragColor.w = gl_FragColor.x; //gl_FragColor = vec4(1,1,1,1); } ); SSAOHelper::SSAOHelper(float fov,float padding,float zNear,float zFar, const char* resourcePath, float scale) : fov(fov),padding(padding),zNear(zNear),zFar(zFar), scale(scale) { char ssaoVSF[5000]; char ssaoFSF[5000]; sprintf(ssaoVSF, "%s\\ssao.vs", resourcePath); sprintf(ssaoFSF, "%s\\ssao.fs", resourcePath); SSAOFilterH.loadShaderCode(ssaoFilterVS,ssaoFilterHFS); SSAOFilterV.loadShaderCode(ssaoFilterVS,ssaoFilterVFS); SSAO.loadShaders(ssaoVSF,ssaoFSF); glUseProgram(SSAO); glUniform1i(glGetUniformLocation(SSAO,"depthTex"),0); glUniform1i(glGetUniformLocation(SSAO,"normalTex"),1); glUniform1i(glGetUniformLocation(SSAO,"unitVecTex"),2); glUseProgram(0); // srand(GetTickCount()); glGenTextures(1,&unitVecTex); PxVec3 *RandomUnitVectorsTextureData = new PxVec3[64 * 64]; for(int i = 0; i < 64 * 64; i++) { RandomUnitVectorsTextureData[i].x = (float)rand() / (float)RAND_MAX * 2.0f - 1.0f; RandomUnitVectorsTextureData[i].y = (float)rand() / (float)RAND_MAX * 2.0f - 1.0f; RandomUnitVectorsTextureData[i].z = (float)rand() / (float)RAND_MAX * 2.0f - 1.0f; RandomUnitVectorsTextureData[i].normalize(); RandomUnitVectorsTextureData[i] = RandomUnitVectorsTextureData[i] * 0.5f + PxVec3(0.5f,0.5f,0.5f); } glBindTexture(GL_TEXTURE_2D,unitVecTex); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,64,64,0,GL_RGB,GL_FLOAT,RandomUnitVectorsTextureData); delete [] RandomUnitVectorsTextureData; PxVec3 *samples = new PxVec3[NUMSAMPLES]; float alfa = physx::PxPi / SAMPLEDIV,beta = physx::PxPiDivTwo / (SAMPLEDIV * 2.0f),radius = 0.5f; for(int i = 0; i < NUMSAMPLES; i++) { samples[i] = PxVec3(cos(alfa),sin(alfa),sin(beta)); samples[i].normalize(); samples[i] *= ((float)NUMSAMPLES - i) / ((float)NUMSAMPLES); samples[i] *= radius; alfa += physx::PxPi / (SAMPLEDIV / 2); if(((i + 1) % SAMPLEDIV) == 0) { alfa += physx::PxPi / SAMPLEDIV; beta += physx::PxPiDivTwo / SAMPLEDIV; } } glUseProgram(SSAO); glUniform3fv(glGetUniformLocation(SSAO,"samples"),NUMSAMPLES,(GLfloat*)samples); glUseProgram(0); delete [] samples; glGenTextures(1,&normalTex); glGenTextures(1,&depthTex); glGenTextures(1,&ssaoTex); glGenTextures(1,&blurTex); glGenFramebuffers(1,&FBO); } PxMat44 PerspectiveProjectionMatrix(float fovy,float x,float y,float n,float f) { float PPM[16]; float coty = 1.0f / tan(fovy * physx::PxPi / 360.0f); float aspect = x / (y > 0.0f ? y : 1.0f); PPM[0] = coty / aspect; PPM[1] = 0.0f; PPM[2] = 0.0f; PPM[3] = 0.0f; PPM[4] = 0.0f; PPM[5] = coty; PPM[6] = 0.0f; PPM[7] = 0.0f; PPM[8] = 0.0f; PPM[9] = 0.0f; PPM[10] = (n + f) / (n - f); PPM[11] = -1.0f; PPM[12] = 0.0f; PPM[13] = 0.0f; PPM[14] = 2.0f * n * f / (n - f); PPM[15] = 0.0f; return PxMat44(PPM); } PxMat44 PerspectiveProjectionMatrixInverse(PxMat44 &PPM) { float PPMI[16]; PPMI[0] = 1.0f / PPM.column0.x; PPMI[1] = 0.0f; PPMI[2] = 0.0f; PPMI[3] = 0.0f; PPMI[4] = 0.0f; PPMI[5] = 1.0f / PPM.column1.y; PPMI[6] = 0.0f; PPMI[7] = 0.0f; PPMI[8] = 0.0f; PPMI[9] = 0.0f; PPMI[10] = 0.0f; PPMI[11] = 1.0f / PPM.column3.z; PPMI[12] = 0.0f; PPMI[13] = 0.0f; PPMI[14] = 1.0f / PPM.column2.w; PPMI[15] = - PPM.column2.z / (PPM.column2.w * PPM.column3.z); return PxMat44(PPMI); } PxMat44 BiasMatrix() { float BM[16]; BM[0] = 0.5f; BM[4] = 0.0f; BM[8] = 0.0f; BM[12] = 0.5f; BM[1] = 0.0f; BM[5] = 0.5f; BM[9] = 0.0f; BM[13] = 0.5f; BM[2] = 0.0f; BM[6] = 0.0f; BM[10] = 0.5f; BM[14] = 0.5f; BM[3] = 0.0f; BM[7] = 0.0f; BM[11] = 0.0f; BM[15] = 1.0f; return PxMat44(BM); } PxMat44 BiasMatrixInverse() { float BMI[16]; BMI[0] = 2.0f; BMI[4] = 0.0f; BMI[8] = 0.0f; BMI[12] = -1.0f; BMI[1] = 0.0f; BMI[5] = 2.0f; BMI[9] = 0.0f; BMI[13] = -1.0f; BMI[2] = 0.0f; BMI[6] = 0.0f; BMI[10] = 2.0f; BMI[14] = -1.0f; BMI[3] = 0.0f; BMI[7] = 0.0f; BMI[11] = 0.0f; BMI[15] = 1.0f; return PxMat44(BMI); } void SSAOHelper::Resize(int w,int h) { realWidth = w; realHeight = h; Width = w*scale; Height = h*scale; fovPad = 2.0f*atan(tan(fov*0.5f*physx::PxPi/180.0f)*(1.0f+padding))*180.0f/physx::PxPi; SWidth = Width*(1.0f+padding); SHeight = Height*(1.0f+padding); glViewport(0,0,SWidth,SHeight); PxMat44 mat(); PxMat44 Projection = PerspectiveProjectionMatrix(fovPad,SWidth,SHeight,zNear,zFar); glMatrixMode(GL_PROJECTION); glLoadMatrixf(&Projection.column0.x); glBindTexture(GL_TEXTURE_2D,normalTex); 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_WRAP_S,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,SWidth,SHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL); glBindTexture(GL_TEXTURE_2D,depthTex); 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_WRAP_S,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); glTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT32,SWidth,SHeight,0,GL_DEPTH_COMPONENT,GL_FLOAT,NULL); glBindTexture(GL_TEXTURE_2D,ssaoTex); 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_WRAP_S,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,SWidth,SHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL); glBindTexture(GL_TEXTURE_2D,blurTex); 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_WRAP_S,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,SWidth,SHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL); PxMat44 biasProjMat = BiasMatrix() * Projection; PxMat44 biasProjMatInv = PerspectiveProjectionMatrixInverse(Projection) * BiasMatrixInverse(); glUseProgram(SSAO); glUniformMatrix4fv(glGetUniformLocation(SSAO,"biasProjMat"),1,GL_FALSE,&biasProjMat.column0.x); glUniformMatrix4fv(glGetUniformLocation(SSAO,"biasProjMatInv"),1,GL_FALSE,&biasProjMatInv.column0.x); glUniform2f(glGetUniformLocation(SSAO,"scaleXY"),(float)SWidth / 64.0f,(float)SHeight / 64.0f); glUseProgram(SSAOFilterH); glUniform1f(glGetUniformLocation(SSAOFilterH,"sx"),1.0f / (float)SWidth); glUseProgram(SSAOFilterV); glUniform1f(glGetUniformLocation(SSAOFilterV,"sy"),1.0f / (float)SHeight); glUseProgram(0); } void SSAOHelper::Destroy() { SSAO.deleteShaders(); SSAOFilterH.deleteShaders(); SSAOFilterV.deleteShaders(); glDeleteTextures(1,&unitVecTex); glDeleteTextures(1,&normalTex); glDeleteTextures(1,&depthTex); glDeleteTextures(1,&ssaoTex); glDeleteTextures(1,&blurTex); glDeleteFramebuffers(1,&FBO); } void SSAOHelper::DoSSAO(void (*renderScene)(), GLuint oldFBO) { glBindFramebuffer(GL_FRAMEBUFFER,FBO); glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,normalTex,0); glFramebufferTexture2D(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,depthTex,0); glViewport(0,0,SWidth,SHeight); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); PxMat44 Projection = PerspectiveProjectionMatrix(fovPad,SWidth,SHeight,zNear,zFar); glMatrixMode(GL_PROJECTION); glLoadMatrixf(&Projection.column0.x); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); renderScene(); glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); // if(Blur) // { glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,ssaoTex,0); glFramebufferTexture2D(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,0,0); glClearColor(0.0f,0.0f,0.0f,1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // } // else // { // glBindFramebuffer(GL_FRAMEBUFFER,0); // } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,depthTex); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,normalTex); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D,unitVecTex); glUseProgram(SSAO); glBegin(GL_QUADS); glVertex2f(0.0f,0.0f); glVertex2f(1.0f,0.0f); glVertex2f(1.0f,1.0f); glVertex2f(0.0f,1.0f); glEnd(); glUseProgram(0); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D,0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,0); // if(Blur) { glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,blurTex,0); glFramebufferTexture2D(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,0,0); glBindTexture(GL_TEXTURE_2D,ssaoTex); glUseProgram(SSAOFilterH); glUniform1f(glGetUniformLocation(SSAOFilterH, "sx"), 1.0f / (float)SWidth); glBegin(GL_QUADS); /* glTexCoord2f(0.0f+fx,0.0f+fy); glVertex2f(0.0f,0.0f); glTexCoord2f(1.0f-fx,0.0f+fy); glVertex2f(1.0f,0.0f); glTexCoord2f(1.0f-fx,1.0f-fy); glVertex2f(1.0f,1.0f); glTexCoord2f(0.0f+fx,1.0f-fy); glVertex2f(0.0f,1.0f); */ glTexCoord2f(0.0f,0.0f); glVertex2f(0.0f,0.0f); glTexCoord2f(1.0f,0.0f); glVertex2f(1.0f,0.0f); glTexCoord2f(1.0f,1.0f); glVertex2f(1.0f,1.0f); glTexCoord2f(0.0f,1.0f); glVertex2f(0.0f,1.0f); glEnd(); glUseProgram(0); glBindFramebuffer(GL_FRAMEBUFFER,oldFBO); //glClearColor(0.0f,0.0f,0.0f,1.0f); //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); glEnable(GL_BLEND); glBlendFunc(GL_ZERO, GL_SRC_ALPHA); glViewport(0,0,realWidth,realHeight); Projection = PerspectiveProjectionMatrix(fov,Width,Height,zNear,zFar); glMatrixMode(GL_PROJECTION); glLoadMatrixf(&Projection.column0.x); glBindTexture(GL_TEXTURE_2D,blurTex); glUseProgram(SSAOFilterV); glUniform1f(glGetUniformLocation(SSAOFilterV, "sy"), 1.0f / (float)SHeight); //float fx = 0.5f*(1.0f-(((float)(SWidth-Width))/((float)Width))); //float fy = 0.5f*(1.0f-(((float)(SHeight-Height))/((float)Height))); float fx = 0.5f*((float)(SWidth-Width)) / ((float)SWidth); float fy = 0.5f*((float)(SHeight-Height)) / ((float)SHeight); glBegin(GL_QUADS); glTexCoord2f(0.0f+fx,0.0f+fy); glVertex2f(0.0f,0.0f); glTexCoord2f(1.0f-fx,0.0f+fy); glVertex2f(1.0f,0.0f); glTexCoord2f(1.0f-fx,1.0f-fy); glVertex2f(1.0f,1.0f); glTexCoord2f(0.0f+fx,1.0f-fy); glVertex2f(0.0f,1.0f); glEnd(); glUseProgram(0); glBindTexture(GL_TEXTURE_2D,0); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); } }