2021-01-27 15:30:03 +01:00

350 lines
11 KiB
C++

/****************************************************************************
* MeshLab o o *
* An extendible mesh processor o o *
* _ O _ *
* Copyright(C) 2005, 2006 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#include <meshlab/glarea.h>
#include "ssao.h"
#include <common/globals.h>
SSAO::SSAO(float radius):DecorateShader()
{
this->_radius = radius;
this->_depth = 0;
this->_color1 = 0;
this->_normalMapFrag = 0;
this->_normalMapVert = 0;
this->_normalMapShaderProgram = 0;
this->_depthMap = 0;
this->_color2= 0;
this->_ssaoVert = 0;
this->_ssaoFrag = 0;
this->_ssaoShaderProgram = 0;
this->_blurVert = 0;
this->_blurFrag = 0;
this->_blurShaderProgram = 0;
this->_fbo = 0;
this->_fbo2 = 0;
}
SSAO::~SSAO(){
glDetachShader(this->_normalMapShaderProgram, this->_normalMapVert);
glDetachShader(this->_normalMapShaderProgram, this->_normalMapFrag);
glDeleteShader(this->_normalMapVert);
glDeleteShader(this->_normalMapFrag);
glDeleteProgram(this->_normalMapShaderProgram);
glDetachShader(this->_ssaoShaderProgram, this->_ssaoVert);
glDetachShader(this->_ssaoShaderProgram, this->_ssaoFrag);
glDeleteShader(this->_ssaoVert);
glDeleteShader(this->_ssaoFrag);
glDeleteProgram(this->_ssaoShaderProgram);
glDetachShader(this->_blurShaderProgram, this->_blurVert);
glDetachShader(this->_blurShaderProgram, this->_blurFrag);
glDeleteShader(this->_blurVert);
glDeleteShader(this->_blurFrag);
glDeleteProgram(this->_blurShaderProgram);
glDeleteTextures(1, &(this->_color1));
glDeleteTextures(1, &(this->_depthMap));
glDeleteFramebuffers(1, &(this->_depth));
glDeleteTextures(1, &(this->_color2));
glDeleteTextures(1, &(this->_color2));
glDeleteFramebuffers(1, &_fbo);
glDeleteFramebuffers(1, &_fbo2);
}
bool SSAO::init()
{
if(!this->initGlew() || !this->initSetup())
return false;
if(!compileAndLink(
this->_ssaoShaderProgram,
this->_ssaoVert,
this->_ssaoFrag,
meshlab::defaultShadersPath() + "/decorate_shadow/ssao/ssao") ||
!compileAndLink(
this->_normalMapShaderProgram,
this->_normalMapVert,
this->_normalMapFrag,
meshlab::defaultShadersPath() + "/decorate_shadow/ssao/normalMap") ||
!compileAndLink(
this->_blurShaderProgram,
this->_blurVert,
this->_blurFrag,
meshlab::defaultShadersPath() + "/decorate_shadow/ssao/blur"))
return false;
return true;
}
void SSAO::runShader(MeshDocument& md, GLArea* gla)
{
/***********************************************************/
//NORMAL MAP and DEPTH MAP generation
/***********************************************************/
MLSceneGLSharedDataContext* ctx = NULL;
if ((gla == NULL) || (gla->mvc() == NULL))
return;
ctx = gla->mvc()->sharedDataContext();
if (ctx == NULL)
return;
this->bind();
glUseProgram(this->_normalMapShaderProgram);
vcg::Matrix44f mProj, mInverseProj;
glMatrixMode(GL_PROJECTION);
glGetFloatv(GL_PROJECTION_MATRIX, mProj.V());
glMatrixMode(GL_MODELVIEW);
mProj.transposeInPlace();
mInverseProj = vcg::Inverse(mProj);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
MLRenderingData dt;
MLRenderingData::RendAtts atts;
atts[MLRenderingData::ATT_NAMES::ATT_VERTPOSITION] = true;
atts[MLRenderingData::ATT_NAMES::ATT_VERTNORMAL] = true;
atts[MLRenderingData::ATT_NAMES::ATT_FACENORMAL] = true;
dt.set(MLRenderingData::PR_SOLID, atts);
foreach(MeshModel *m, md.meshList)
{
if ((m != NULL) && (m->visible))
{
ctx->drawAllocatedAttributesSubset(m->id(), gla->context(), dt);
}
}
glUseProgram(0);
/***********************************************************/
//SSAO PASS
/***********************************************************/
glBindFramebuffer(GL_FRAMEBUFFER, _fbo2);
glUseProgram(this->_ssaoShaderProgram);
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, this->_noise);
GLuint noiseloc = glGetUniformLocation(this->_ssaoShaderProgram, "rnm");
glUniform1i(noiseloc, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, this->_color1);
GLuint loc = glGetUniformLocation(this->_ssaoShaderProgram, "normalMap");
glUniform1i(loc, 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, this->_depthMap);
loc = glGetUniformLocation(this->_ssaoShaderProgram, "depthMap");
glUniform1i(loc, 2);
GLuint radiusLoc = glGetUniformLocation(this->_ssaoShaderProgram, "rad");
glUniform1f(radiusLoc, this->_radius);
GLuint matrixLoc = glGetUniformLocation(this->_ssaoShaderProgram, "proj");
glUniformMatrix4fv(matrixLoc, 1, 0, mProj.transpose().V());
GLuint invMatrixLoc = glGetUniformLocation(this->_ssaoShaderProgram, "invProj");
glUniformMatrix4fv(invMatrixLoc, 1, 0, mInverseProj.transpose().V());
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f( 1.0f, -1.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
glEnd();
glUseProgram(0);
/***********************************************************/
//BLURRING horizontal
/***********************************************************/
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glUseProgram(this->_blurShaderProgram);
float blur_coef(0.8f);
GLfloat scale = 1/(this->_texW * blur_coef);
GLuint scaleLoc = glGetUniformLocation(this->_blurShaderProgram, "scale");
glUniform2f(scaleLoc, scale, 0.0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, this->_color2);
loc = glGetUniformLocation(this->_blurShaderProgram, "scene");
glUniform1i(loc, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f( 1.0f, -1.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
glEnd();
/***********************************************************/
//BLURRING vertical
/***********************************************************/
this->unbind();
glUniform2f(scaleLoc, 0.0, scale);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, this->_color1);
loc = glGetUniformLocation(this->_blurShaderProgram, "scene");
glUniform1i(loc, 0);
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f( 1.0f, -1.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
glEnd();
glUseProgram(0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
bool SSAO::setup()
{
if (!GLEW_EXT_framebuffer_object) {
qWarning("FBO not supported!");
return false;
}
if (_initOk)
return true;
//genero i 2 framebuffer object che mi servono.
glGenFramebuffers(1, &_fbo);
glGenFramebuffers(1, &_fbo2);
//attacco il primo...adesso le modifiche andranno a modificare solo _fbo
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
//Generates first color texture
this->genColorTextureEXT(this->_color1, GL_COLOR_ATTACHMENT0);
this->genDepthMapTexture24(this->_depthMap, false);
GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffersARB(0, drawBuffers);
int err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
_initOk = (err == GL_FRAMEBUFFER_COMPLETE);
if(!this->_initOk)
return this->_initOk;
//attacco il secondo fbo...adesso le modifiche andranno a modificare solo _fbo2
glBindFramebuffer(GL_FRAMEBUFFER, _fbo2);
//Generates first color texture
this->genColorTextureEXT(this->_color2, GL_COLOR_ATTACHMENT0);
//Generates render buffer for depth attachment
this->genDepthRenderBufferEXT(this->_depth);
GLenum drawBuffers2[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffersARB(0, drawBuffers2);
this->loadNoiseTxt();
err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
_initOk = (err == GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return _initOk;
}
bool SSAO::loadNoiseTxt(){
QImage image = QImage();
QString textureName = QString(":/rand.png");
if (QFile(textureName).exists())
{
image = QImage(textureName);
noiseWidth=image.width();
noiseHeight=image.height();
QImage tmpGL = QGLWidget::convertToGLFormat(image);
image = QImage(tmpGL);
}
else {
qDebug("Warning failed to load noise texture!");
assert(0);
return false;
}
// Creates The Texture
glGenTextures(1, &(this->_noise));
glBindTexture(GL_TEXTURE_2D, this->_noise);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, noiseWidth , noiseHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, image.bits());
return true;
}
void SSAO::printNoiseTxt(){
QImage img(noiseWidth , noiseHeight, QImage::Format_RGB32);
unsigned char *tempBuf = new unsigned char[noiseWidth * noiseHeight * 3];
unsigned char *tempBufPtr = tempBuf;
glBindTexture(GL_TEXTURE_2D, this->_noise);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, tempBufPtr);
for (int i = 0; i < noiseWidth; ++i) {
QRgb *scanLine = (QRgb*)img.scanLine(i);
for (int j = 0; j < noiseHeight; ++j) {
scanLine[j] = qRgb(tempBufPtr[0], tempBufPtr[1], tempBufPtr[2]);
tempBufPtr += 3;
}
}
delete[] tempBuf;
img.mirrored().save("_noise.png", "PNG");
}