Files
2025-11-28 23:13:44 +05:30

384 lines
12 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 "HDRHelper.h"
#include "foundation/PxMat44.h"
namespace
{
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);
}
}
const char *HDRToneMappingVS = STRINGIFY(
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_Vertex * 2.0 - 1.0;
}
);
const char *HDRBlurHFS = STRINGIFY(
uniform sampler2D colorTex;
uniform float sx;
void main (void)
{
vec3 bloom = vec3(0.0, 0.0, 0.0);
const float hdrScale = 1.5;
const int kernelSize = 10;
const float invScale = 1.0 / (hdrScale * float(kernelSize));
for (int x = -kernelSize; x <= kernelSize; x++)
{
float s = gl_TexCoord[0].s + x * sx;
float t = gl_TexCoord[0].t;
vec3 color = texture2D(colorTex, vec2(s,t)).rgb;
float luminance = dot(color, vec3(0.2125, 0.7154, 0.0721));
if (luminance > 1.0)
{
bloom += color * ((kernelSize+1) - abs(float(x)));
}
}
gl_FragColor = vec4(bloom * invScale, 1.0);
}
);
const char *HDRBlurVFS = STRINGIFY(
uniform sampler2D colorTex;
uniform sampler2D blurTex;
uniform float sy;
void main (void)
{
const float hdrScale = 1.5;
const int kernelSize = 10;
const float invScale = 1.0 / (hdrScale * float(kernelSize) * 100.0);
vec3 colorP = texture2D(colorTex, gl_TexCoord[0]).rgb;
vec3 bloom = vec3(0.0, 0.0, 0.0);
for (int y = -kernelSize; y <= kernelSize; y++)
{
float s = gl_TexCoord[0].s;
float t = gl_TexCoord[0].t + y * sy;
vec3 color = texture2D(blurTex, vec2(s,t)).rgb;
float luminance = dot(color, vec3(0.2125, 0.7154, 0.0721));
if (luminance > 1.0)
{
bloom += color * ((kernelSize+1) - abs(float(y)));
}
}
vec3 hdrColor = invScale * bloom + colorP;
vec3 toneMappedColor = 2.0 * hdrColor / (hdrColor + vec3(1.0));
gl_FragColor = vec4(toneMappedColor, 1.0);
}
);
const char *HDRDepthOfFieldFS = STRINGIFY(
uniform sampler2D colorTex;
uniform sampler2D depthTex;
uniform float sx;
uniform float sy;
void main(void)
{
const float depthEnd = 0.993;
const float depthSize = 0.01;
vec3 colorP = texture2D(colorTex, gl_TexCoord[0]).rgb;
float depth = texture2D(depthTex, gl_TexCoord[0].st).r;
if ((depth - depthEnd) < depthSize)
{
const int depthKernelSize = 5;
vec3 colorSum = vec3(0.0);
float cnt = 0.0;
for (int x = -depthKernelSize; x <= depthKernelSize; x++)
for (int y = -depthKernelSize; y <= depthKernelSize; y++)
{
float s = gl_TexCoord[0].s + x * sy;
float t = gl_TexCoord[0].t + y * sy;
float scalex = ((depthKernelSize + 1) - abs(float(x))) / depthKernelSize;
float scaley = ((depthKernelSize + 1) - abs(float(y))) / depthKernelSize;
float scale = scalex * scaley;
vec3 color = texture2D(colorTex, vec2(s, t)).rgb;
colorSum += scale * color;
cnt += scale;
}
colorSum /= cnt;
float depthScale = pow(max(0.0f, min(1.0, (abs(depth - depthEnd)) / depthSize)), 1.5);
colorP = depthScale * colorSum + (1.0 - depthScale) * colorP;
}
gl_FragColor = vec4(colorP, 1.0);
}
);
HDRHelper::HDRHelper(float fov,float padding,float zNear,float zFar, const char* resourcePath, float scale) : fov(fov),padding(padding),zNear(zNear),zFar(zFar), scale(scale)
{
mShaderBloomH.loadShaderCode(HDRToneMappingVS, HDRBlurHFS);
mShaderBloomV.loadShaderCode(HDRToneMappingVS, HDRBlurVFS);
mShaderDOF.loadShaderCode(HDRToneMappingVS, HDRDepthOfFieldFS);
glGenTextures(1,&mHDRColorTex);
glGenTextures(1,&mHDRDepthTex);
glGenTextures(1,&mHDRBlurTex);
glGenTextures(1,&mHDRBloomTex);
glGenFramebuffers(1,&mHDRFbo);
glBindFramebuffer(GL_FRAMEBUFFER, mHDRFbo);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,mHDRColorTex, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glGenFramebuffers(1,&mHDRBlurFbo);
glBindFramebuffer(GL_FRAMEBUFFER, mHDRBlurFbo);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,mHDRBlurTex, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
//printf("Frame buffer status %d\n\n\n",
// (status == GL_FRAMEBUFFER_COMPLETE) ? 1 : 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void HDRHelper::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;
glViewport(0,0,w,h);
// allocate HDR color buffer
glBindFramebuffer(GL_FRAMEBUFFER, mHDRFbo);
glBindTexture(GL_TEXTURE_2D,mHDRColorTex);
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_RGBA16F,w,h,0,GL_RGBA,GL_FLOAT,NULL);
glBindTexture(GL_TEXTURE_2D,mHDRDepthTex);
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_COMPONENT24,w,h,0,GL_DEPTH_COMPONENT,GL_FLOAT,NULL);
// allocate HDR color buffer for blur operations
glBindFramebuffer(GL_FRAMEBUFFER, mHDRBlurFbo);
glBindTexture(GL_TEXTURE_2D,mHDRBlurTex);
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_RGBA16F,w,h,0,GL_RGBA,GL_FLOAT,NULL);
glBindTexture(GL_TEXTURE_2D,mHDRBloomTex);
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_RGBA16F,w,h,0,GL_RGBA,GL_FLOAT,NULL);
// set program values
glUseProgram(mShaderBloomH);
glUniform1f(glGetUniformLocation(mShaderBloomH,"sx"),1.0f / (float)w);
glUseProgram(mShaderBloomV);
glUniform1f(glGetUniformLocation(mShaderBloomV,"sy"),1.0f / (float)h);
glUseProgram(mShaderDOF);
glUniform1f(glGetUniformLocation(mShaderDOF,"sx"),1.0f / (float)w);
glUniform1f(glGetUniformLocation(mShaderDOF,"sy"),1.0f / (float)h);
glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void HDRHelper::Destroy() {
mShaderBloomH.deleteShaders();
mShaderBloomV.deleteShaders();
glDeleteTextures(1,&mHDRColorTex);
glDeleteTextures(1,&mHDRDepthTex);
glDeleteTextures(1,&mHDRBlurTex);
glDeleteTextures(1,&mHDRBloomTex);
glDeleteFramebuffers(1,&mHDRFbo);
glDeleteFramebuffers(1,&mHDRBlurFbo);
}
void HDRHelper::beginHDR(bool useOwnFbo)
{
if (useOwnFbo)
{
glBindFramebuffer(GL_FRAMEBUFFER, mHDRFbo);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,mHDRColorTex, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,mHDRDepthTex,0);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
}
void HDRHelper::endHDR(bool useOwnFbo)
{
if (useOwnFbo)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void
drawQuads(float s = 1.0f)
{
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f,0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex2f(s,0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex2f(s,s);
glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f,s);
glEnd();
}
void HDRHelper::DoHDR(GLuint oldFBO, bool useDOF) {
PxMat44 Projection = PerspectiveProjectionMatrix(fov,Width,Height,zNear,zFar);
// render stored HDR fbo onto blur fbo, first with horizontal blur
glBindFramebuffer(GL_FRAMEBUFFER, mHDRBlurFbo);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,mHDRBlurTex,0);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,0,0);
glViewport(0,0,realWidth,realHeight);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(&Projection.column0.x);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mHDRColorTex);
glUseProgram(mShaderBloomH);
glUniform1f(glGetUniformLocation(mShaderBloomH, "sx"), 1.0f / (float)realWidth);
glUniform1i(glGetUniformLocation(mShaderBloomH,"colorTex"),0);
drawQuads();
glUseProgram(0);
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,0);
// now apply vertical blur for the bloom
if (useDOF)
{
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,mHDRBloomTex,0);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,0,0);
}
else
glBindFramebuffer(GL_FRAMEBUFFER,oldFBO);
glViewport(0,0,realWidth,realHeight);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(&Projection.column0.x);
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,mHDRColorTex);
glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,mHDRBlurTex);
glUseProgram(mShaderBloomV);
glUniform1f(glGetUniformLocation(mShaderBloomV, "sy"), 1.0f / (float)realHeight);
glUniform1i(glGetUniformLocation(mShaderBloomV,"colorTex"),0);
glUniform1i(glGetUniformLocation(mShaderBloomV,"blurTex"),1);
drawQuads();
glUseProgram(0);
glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,0);
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,0);
// now render the final image onto supplied fbo, apply DOF
if (!useDOF) return;
glBindFramebuffer(GL_FRAMEBUFFER,oldFBO);
glViewport(0,0,realWidth,realHeight);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(&Projection.column0.x);
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,mHDRBloomTex);
glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,mHDRDepthTex);
glUseProgram(mShaderDOF);
glUniform1f(glGetUniformLocation(mShaderDOF, "sx"), 1.0f / (float)realWidth);
glUniform1f(glGetUniformLocation(mShaderDOF, "sy"), 1.0f / (float)realHeight);
glUniform1i(glGetUniformLocation(mShaderDOF,"colorTex"),0);
glUniform1i(glGetUniformLocation(mShaderDOF,"depthTex"),1);
drawQuads();
glUseProgram(0);
glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,0);
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,0);
}