Files
PhysX4.1/kaplademo/source/demoFramework/SSAOHelper.cpp
2025-11-28 23:13:44 +05:30

426 lines
13 KiB
C++

//
// 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);
}
}