From 42c69abccf8439a0921bd676cc24d8cfa4891371 Mon Sep 17 00:00:00 2001 From: ganovelli Date: Fri, 29 Oct 2010 17:18:29 +0000 Subject: [PATCH] =?UTF-8?q?first=20working=20commit=20for=20the=20apss=20(?= =?UTF-8?q?from=20Algebraic=20point=20set=20surfaces=20Ga=C3=ABl=20Guenneb?= =?UTF-8?q?aud=20and=20Markus=20Gross,=20SIG07)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../splatting_apss/shaders/Finalization.glsl | 112 +++ .../gl/splatting_apss/shaders/Raycasting.glsl | 345 +++++++ wrap/gl/splatting_apss/splatrenderer.h | 843 ++++++++++++++++++ wrap/gl/splatting_apss/splatrenderer.qrc | 6 + 4 files changed, 1306 insertions(+) create mode 100644 wrap/gl/splatting_apss/shaders/Finalization.glsl create mode 100644 wrap/gl/splatting_apss/shaders/Raycasting.glsl create mode 100644 wrap/gl/splatting_apss/splatrenderer.h create mode 100644 wrap/gl/splatting_apss/splatrenderer.qrc diff --git a/wrap/gl/splatting_apss/shaders/Finalization.glsl b/wrap/gl/splatting_apss/shaders/Finalization.glsl new file mode 100644 index 00000000..2e4986fb --- /dev/null +++ b/wrap/gl/splatting_apss/shaders/Finalization.glsl @@ -0,0 +1,112 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* 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. * +* * +****************************************************************************/ + +#extension GL_ARB_texture_rectangle : enable + +#ifndef EXPE_DEPTH_INTERPOLATION + #define EXPE_DEPTH_INTERPOLATION 0 +#endif + +#ifndef EXPE_OUTPUT_DEPTH + #define EXPE_OUTPUT_DEPTH 0 +#endif + +// avoid an annoying bug with the nvidia driver 87XX serie. +#define epsilon 0.000001 + +uniform vec4 viewport; + +#ifndef EXPE_DEFERRED_SHADING + +uniform sampler2DRect ColorWeight; +#if (EXPE_OUTPUT_DEPTH==1) +uniform sampler2DRect Depth; +#endif + +void Finalization(void) +{ + vec4 color = texture2DRect(ColorWeight, gl_FragCoord.st - viewport.xy + epsilon); + #if (EXPE_OUTPUT_DEPTH==1) + gl_FragDepth = texture2DRect(Depth, gl_FragCoord.st + epsilon).x; + #endif + if (color.w<0.001) + discard; + gl_FragColor = color/color.w; + gl_FragColor.a = 1.; +} + +#else + +uniform vec2 unproj; + +uniform sampler2DRect ColorWeight; +uniform sampler2DRect NormalWeight; + +#if ( (EXPE_DEPTH_INTERPOLATION==0) || (EXPE_OUTPUT_DEPTH==1)) +uniform sampler2DRect Depth; +#endif + +void Finalization(void) +{ + vec4 color = texture2DRect(ColorWeight, gl_FragCoord.st - viewport.xy + epsilon); + + if (color.w<0.001) + discard; + + + if(color.w>0.001) + color.xyz /= color.w; + + vec3 viewVec = normalize(gl_TexCoord[0].xyz); + vec4 normaldepth = texture2DRect(NormalWeight, gl_FragCoord.st + epsilon); + + normaldepth.xyz = normaldepth.xyz/normaldepth.w; + + #if (EXPE_OUTPUT_DEPTH==1) + gl_FragDepth = texture2DRect(Depth, gl_FragCoord.st + epsilon).x; + #endif + + #if EXPE_DEPTH_INTERPOLATION==2 + float depth = -normaldepth.z; + #elif EXPE_DEPTH_INTERPOLATION==1 + float depth = unproj.y/(2.0*normaldepth.z+unproj.x-1.0); + #else + float depth = texture2DRect(Depth, gl_FragCoord.st + epsilon).x; + depth = unproj.y/(2.0*depth+unproj.x-1.0); + #endif + + vec3 normal = normaldepth.xyz; + #if EXPE_DEPTH_INTERPOLATION!=0 + normal.z = sqrt(1. - dot(vec3(normal.xy,0),vec3(normal.xy,0))); + #endif + normal = normalize(normal); + vec3 eyePos = gl_TexCoord[0].xyz * depth; + + gl_FragColor = meshlabLighting(color, eyePos, normal); + gl_FragColor.a = 1.0; +} + +#endif + + + diff --git a/wrap/gl/splatting_apss/shaders/Raycasting.glsl b/wrap/gl/splatting_apss/shaders/Raycasting.glsl new file mode 100644 index 00000000..4e42cf41 --- /dev/null +++ b/wrap/gl/splatting_apss/shaders/Raycasting.glsl @@ -0,0 +1,345 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2009 \/)\/ * +* 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. * +* * +****************************************************************************/ + +// #version 110 +// #extension all : enable + +#pragma optimize(on) + +#ifndef EXPE_EWA_HINT + #define EXPE_EWA_HINT 0 +#endif + +#ifndef EXPE_DEPTH_INTERPOLATION + #define EXPE_DEPTH_INTERPOLATION 0 +#endif + +//-------------------------------------------------------------------------------- +// shared variables +//-------------------------------------------------------------------------------- + +// custom vertex attributes +//attribute float radius; + +#ifdef CLIPPED_SPLAT +attribute vec3 secondNormal; +varying vec4 clipLine; +#endif + +// standard uniforms +uniform float expeRadiusScale; +uniform float expePreComputeRadius; +uniform float expeDepthOffset; + +// varying +varying vec4 covmat; +varying vec3 fragNormal; + +varying vec3 fragNoverCdotN; +varying vec3 fragCenter; +varying float scaleSquaredDistance; + +#ifdef EXPE_ATI_WORKAROUND +varying vec4 fragCenterAndRadius; +#endif + +#ifdef EXPE_DEPTH_CORRECTION +varying float depthOffset; +#endif + +uniform vec2 halfVp; +uniform float oneOverEwaRadius; + + +#ifdef EXPE_BACKFACE_SHADING + #undef EXPE_EARLY_BACK_FACE_CULLING + //#define EXPE_EWA_HINT 2 +#endif + +//-------------------------------------------------------------------------------- +// Visibility Splatting +// Vertex Shader +//-------------------------------------------------------------------------------- + +#ifdef __VisibilityVP__ +varying vec2 scaledFragCenter2d; +void VisibilityVP(void) +{ + vec3 normal = normalize(gl_NormalMatrix * gl_Normal); + // Point in eye space + vec4 ePos = gl_ModelViewMatrix * gl_Vertex; + + float dotpn = dot(normal.xyz,ePos.xyz); + + vec4 oPos; + + #ifdef EXPE_EARLY_BACK_FACE_CULLING + // back_face culling + oPos = vec4(0,0,1,0); + if(dotpn<0.) + { + #endif + + float radius = gl_MultiTexCoord2.x * expeRadiusScale; + + vec4 pointSize; + pointSize.x = radius * expePreComputeRadius / ePos.z; + gl_PointSize = max(1.0, pointSize.x); + + scaleSquaredDistance = 1.0 / (radius * radius); + //fragNormal = normal; + fragCenter = ePos.xyz; + fragNoverCdotN = normal/dot(ePos.xyz,normal); + + #ifndef EXPE_DEPTH_CORRECTION + ePos.xyz += normalize(ePos.xyz) * expeDepthOffset * radius; + #else + //ePos.xyz += normalize(ePos.xyz) * expeDepthOffset * radius; + depthOffset = expeDepthOffset * radius; + #endif + + oPos = gl_ProjectionMatrix * ePos; + + #if (EXPE_EWA_HINT>0) + scaledFragCenter2d = 0.5*((oPos.xy/oPos.w)+1.0)*halfVp*oneOverEwaRadius; + #endif + + #ifdef EXPE_ATI_WORKAROUND + fragCenterAndRadius.xyz = (oPos.xyz/oPos.w) + 1.0; + fragCenterAndRadius.xy = fragCenterAndRadius.xy*halfVp; + fragCenterAndRadius.z = fragCenterAndRadius.z*0.5; + fragCenterAndRadius.w = pointSize.x; + #endif + + #ifndef EXPE_EARLY_BACK_FACE_CULLING + oPos.w = oPos.w * ( (dotpn<0.0) ? 1.0 : 0.0); + #else + } + #endif + + gl_Position = oPos; +} + +#endif + +//-------------------------------------------------------------------------------- +// Visibility Splatting +// Fragment Shader +//-------------------------------------------------------------------------------- + +#ifdef __VisibilityFP__ +varying vec2 scaledFragCenter2d; +uniform vec3 rayCastParameter1; +uniform vec3 rayCastParameter2; +uniform vec2 depthParameterCast; + +void VisibilityFP(void) +{ + #ifdef EXPE_ATI_WORKAROUND + vec3 fragCoord; + fragCoord.xy = fragCenterAndRadius.xy + (gl_TexCoord[0].st-0.5) * fragCenterAndRadius.w; + fragCoord.z = fragCenterAndRadius.z; + #else + vec3 fragCoord = gl_FragCoord.xyz; + #endif + // compute q in object space + vec3 qOne = rayCastParameter1 * fragCoord + rayCastParameter2; // MAD + float oneOverDepth = dot(qOne,-fragNoverCdotN); // DP3 + float depth = (1.0/oneOverDepth); // RCP + vec3 diff = fragCenter + qOne * depth; // MAD + float r2 = dot(diff,diff); // DP3 + + #if (EXPE_EWA_HINT>0) + vec2 d2 = oneOverEwaRadius*gl_FragCoord.xy - scaledFragCenter2d; // MAD + float r2d = dot(d2,d2); // DP3 + gl_FragColor = vec4(min(r2d,r2*scaleSquaredDistance)); + #else + gl_FragColor = vec4(r2*scaleSquaredDistance); + #endif + + #ifdef EXPE_DEPTH_CORRECTION + oneOverDepth = 1.0/(-depth+depthOffset); + gl_FragDepth = depthParameterCast.x * oneOverDepth + depthParameterCast.y; // MAD + #endif +} + +#endif + +#ifdef __AttributeVP__ + +varying vec2 scaledFragCenter2d; + +void AttributeVP(void) +{ + // transform normal + vec3 normal = normalize(gl_NormalMatrix * gl_Normal); + // Point in eye space + vec4 ePos = gl_ModelViewMatrix * gl_Vertex; + + float dotpn = dot(normal.xyz,ePos.xyz); + + vec4 oPos; + + #ifdef EXPE_EARLY_BACK_FACE_CULLING + // back_face culling + oPos = vec4(0,0,1,0); + if(dotpn<0.) + { + #endif + + #ifdef EXPE_BACKFACE_SHADING + if(dotpn>0.) + { + dotpn = -dotpn; + normal = -normal; + } + #endif + + float radius = gl_MultiTexCoord2.x * expeRadiusScale * 1.05; + + vec4 pointSize; + pointSize.x = radius * expePreComputeRadius / ePos.z; + + #if (EXPE_EWA_HINT>0) + gl_PointSize = max(2.0, pointSize.x); + #else + gl_PointSize = max(1.0, pointSize.x); + #endif + + scaleSquaredDistance = 1. / (radius * radius); + ///********* uncommented fragNormal.... + //fragNormal = normal; + fragCenter = ePos.xyz; + fragNoverCdotN = normal/dot(ePos.xyz,normal); + + // Output color + #ifdef EXPE_DEFERRED_SHADING + fragNormal.xyz = normal.xyz; + gl_FrontColor = gl_Color; + #else + // Output color + #ifdef EXPE_LIGHTING + gl_FrontColor = expeLighting(gl_Color, ePos.xyz, normal.xyz, 1.); + #else + gl_FrontColor = meshlabLighting(gl_Color, ePos.xyz, normal.xyz); + #endif + #endif + + oPos = gl_ModelViewProjectionMatrix * gl_Vertex; + + #ifdef EXPE_ATI_WORKAROUND + fragCenterAndRadius.xyz = (oPos.xyz/oPos.w) + 1.0; + fragCenterAndRadius.xy = fragCenterAndRadius.xy*halfVp; + fragCenterAndRadius.z = fragCenterAndRadius.z*0.5; + fragCenterAndRadius.w = pointSize.x; + #endif + + #if (EXPE_EWA_HINT>0) + scaledFragCenter2d = ((oPos.xy/oPos.w)+1.0)*halfVp*oneOverEwaRadius; + #endif + + #ifndef EXPE_EARLY_BACK_FACE_CULLING + oPos.w = oPos.w * (dotpn<0. ? 1.0 : 0.0); + #else + } + #endif + + gl_Position = oPos; +} + +#endif + +//-------------------------------------------------------------------------------- +// EWA Splatting +// Fragment Shader +//-------------------------------------------------------------------------------- + +#ifdef __AttributeFP__ +// this sampler is only used by this fragment shader + +varying vec2 scaledFragCenter2d; +uniform vec3 rayCastParameter1; +uniform vec3 rayCastParameter2; +uniform vec2 depthParameterCast; + +// uniform sampler1D Kernel1dMap; + +void AttributeFP(void) +{ + #ifdef EXPE_ATI_WORKAROUND + vec3 fragCoord; + fragCoord.xy = fragCenterAndRadius.xy + (gl_TexCoord[0].st-0.5) * fragCenterAndRadius.w; + fragCoord.z = fragCenterAndRadius.z; + #else + vec3 fragCoord = gl_FragCoord.xyz; + #endif + +#if 1 + vec3 qOne = rayCastParameter1 * fragCoord + rayCastParameter2; // MAD + float oneOverDepth = dot(qOne,fragNoverCdotN); // DP3 + float depth = (1.0/oneOverDepth); // RCP + vec3 diff = fragCenter - qOne * depth; // MAD + float r2 = dot(diff,diff); // DP3 + + #if (EXPE_EWA_HINT>0) + vec2 d2 = oneOverEwaRadius*gl_FragCoord.xy - scaledFragCenter2d; // MAD + float r2d = dot(d2,d2); // DP3 +// float weight = texture1D(Kernel1dMap, min(r2d,r2*scaleSquaredDistance)).a; // MUL + MIN + TEX + float weight = min(r2d,r2*scaleSquaredDistance); + weight = clamp(1.-weight,0,1); + weight = weight*weight; + #else + //float weight = texture1D(Kernel1dMap, r2*scaleSquaredDistance).a; // MUL + TEX + float weight = clamp(1.-r2*scaleSquaredDistance,0.0,1.0); + weight = weight*weight; + #endif + weight *= 0.1; // limits overflow + + #ifdef EXPE_DEPTH_CORRECTION + gl_FragDepth = depthParameterCast.x * oneOverDepth + depthParameterCast.y; // MAD + #endif + + #ifdef EXPE_DEFERRED_SHADING + gl_FragData[0].rgb = gl_Color.rgb; // MOV + gl_FragData[1].xyz = fragNormal.xyz; // MOV + gl_FragData[1].w = weight; // MOV + gl_FragData[0].w = weight; + + #if EXPE_DEPTH_INTERPOLATION==2 // linear space + gl_FragData[1].z = -depth; // MOV + #elif EXPE_DEPTH_INTERPOLATION==1 // window space + #ifdef EXPE_DEPTH_CORRECTION + gl_FragData[1].z = gl_FragDepth; + #else + gl_FragData[1].z = fragCoord.z; + #endif + #endif + + #else + gl_FragColor.rgb = gl_Color.rgb; // MOV + gl_FragColor.w = weight; + #endif +#endif +} + +#endif diff --git a/wrap/gl/splatting_apss/splatrenderer.h b/wrap/gl/splatting_apss/splatrenderer.h new file mode 100644 index 00000000..02b2c733 --- /dev/null +++ b/wrap/gl/splatting_apss/splatrenderer.h @@ -0,0 +1,843 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005 \/)\/ * +* 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. * +* * +****************************************************************************/ + +#ifndef SPLATRENDERER_H +#define SPLATRENDERER_H + +#include +#include +#include +#include +#include +#define GL_TEST_ERR\ + {\ + GLenum eCode;\ + if((eCode=glGetError())!=GL_NO_ERROR)\ + std::cerr << "OpenGL error : " << gluErrorString(eCode) << " in " << __FILE__ << " : " << __LINE__ << std::endl;\ + } + +class QGLFramebufferObject; + +/* + Rendering with Algebraic Point Set Surfaces, by Gael Guennebaud. + paper: Algebraic Point Set Surfaces SIGGRAPH '07 +*/ +template +class SplatRenderer +{ + bool mIsSupported; + bool init_called; + + enum { + DEFERRED_SHADING_BIT = 0x000001, + DEPTH_CORRECTION_BIT = 0x000002, + OUTPUT_DEPTH_BIT = 0x000004, + BACKFACE_SHADING_BIT = 0x000008, + FLOAT_BUFFER_BIT = 0x000010 + }; + int mFlags; + int mCachedFlags; + int mRenderBufferMask; + int mSupportedMask; + + //int mCurrentPass; + int mBindedPass; + GLuint mDummyTexId; // on ATI graphics card we need to bind a texture to get point sprite working ! + bool mWorkaroundATI; + bool mBuggedAtiBlending; + GLuint mNormalTextureID; + GLuint mDepthTextureID; + ProgramVF mShaders[3]; + QString mShaderSrcs[6]; + QGLFramebufferObject* mRenderBuffer; + float mCachedMV[16]; + float mCachedProj[16]; + GLint mCachedVP[4]; + + struct UniformParameters + { + float radiusScale; + float preComputeRadius; + float depthOffset; + float oneOverEwaRadius; + vcg::Point2f halfVp; + vcg::Point3f rayCastParameter1; + vcg::Point3f rayCastParameter2; + vcg::Point2f depthParameterCast; + + void loadTo(Program& prg); + void update(float* mv, float* proj, GLint* vp); + }; + + UniformParameters mParams; + + QString loadSource(const QString& func,const QString& file); + void configureShaders(); + void updateRenderBuffer(); + void enablePass(int n); + void drawSplats(std::vector & , vcg::GLW::ColorMode cm, vcg::GLW::TextureMode tm); + void drawSplats( + std::vector< std::vector * > & positions, + std::vector< std::vector * > & normals, + std::vector< std::vector > * > & colors, + std::vector & radius, + vcg::GLW::ColorMode cm, vcg::GLW::TextureMode tm); + + +public: + + void Clear(); + void Destroy(); + bool isSupported() {return mIsSupported;} + void Init(QGLWidget *gla); + void Render( std::vector &meshes, vcg::GLW::ColorMode cm, vcg::GLW::TextureMode tm); + + void Render( + std::vector< std::vector * > & positions, + std::vector< std::vector * > & normals, + std::vector< std::vector > * > & colors, + std::vector & radius, + vcg::GLW::ColorMode cm, vcg::GLW::TextureMode tm); + +};// end class + +template +void SplatRenderer:: Destroy(){ + delete mRenderBuffer; + mRenderBuffer = 0; + glDeleteTextures(1,&mDepthTextureID); + glDeleteTextures(1,&mNormalTextureID); + for(int i = 0; i < 3; ++i) + this->mShaders[i].prog.Del(); + + Clear(); +} + +template +void SplatRenderer::Clear() +{ + mNormalTextureID = 0; + mDepthTextureID = 0; + mIsSupported = false; + mRenderBuffer = 0; + mWorkaroundATI = false; + mBuggedAtiBlending = false; + mDummyTexId = 0; + + mFlags = DEFERRED_SHADING_BIT | DEPTH_CORRECTION_BIT | FLOAT_BUFFER_BIT | OUTPUT_DEPTH_BIT; + mCachedFlags = ~mFlags; + // union of bits which controls the render buffer + mRenderBufferMask = DEFERRED_SHADING_BIT | FLOAT_BUFFER_BIT; + + init_called = false; +} + + +template +QString SplatRenderer::loadSource(const QString& func,const QString& filename) +{ + QString res; + QFile f(":/SplatRenderer/shaders/" + filename); + if (!f.open(QFile::ReadOnly)) + { + std::cerr << "failed to load shader file " << filename.toAscii().data() << "\n"; + return res; + } + else qDebug("Succesfully loaded shader func '%s' in file '%s'",qPrintable(func),qPrintable(filename)); + QTextStream stream(&f); + res = stream.readAll(); + f.close(); + res = QString("#define __%1__ 1\n").arg(func) + + QString("#define %1 main\n").arg(func) + + res; + return res; +} +template +void SplatRenderer::configureShaders() +{ + const char* passNames[3] = {"Visibility","Attribute","Finalization"}; + QString defines = ""; + if (mFlags & DEFERRED_SHADING_BIT) + defines += "#define EXPE_DEFERRED_SHADING\n"; + if (mFlags & DEPTH_CORRECTION_BIT) + defines += "#define EXPE_DEPTH_CORRECTION\n"; + if (mFlags & OUTPUT_DEPTH_BIT) + defines += "#define EXPE_OUTPUT_DEPTH 1\n"; + if (mFlags & BACKFACE_SHADING_BIT) + defines += "#define EXPE_BACKFACE_SHADING\n"; + if (mWorkaroundATI) + defines += "#define EXPE_ATI_WORKAROUND\n"; + + QString shading = +"vec4 meshlabLighting(vec4 color, vec3 eyePos, vec3 normal)" +"{" +" normal = normalize(normal);" +" vec3 lightVec = normalize(gl_LightSource[0].position.xyz);" +" vec3 halfVec = normalize( lightVec - normalize(eyePos) );" +" float aux_dot = dot(normal,lightVec);" +" float diffuseCoeff = clamp(aux_dot, 0.0, 1.0);" +" float specularCoeff = aux_dot>0.0 ? clamp(pow(clamp(dot(halfVec, normal),0.0,1.0),gl_FrontMaterial.shininess), 0.0, 1.0) : 0.0;" +" return vec4(color.rgb * ( gl_FrontLightProduct[0].ambient.rgb + diffuseCoeff * gl_FrontLightProduct[0].diffuse.rgb) + specularCoeff * gl_FrontLightProduct[0].specular.rgb, 1.0);" +"}\n"; + + for (int k=0;k<3;++k) + { + QString vsrc = shading + defines + mShaderSrcs[k*2+0]; + QString fsrc = shading + defines + mShaderSrcs[k*2+1]; + mShaders[k].SetSources(mShaderSrcs[k*2+0]!="" ? vsrc.toAscii().data() : 0, + mShaderSrcs[k*2+1]!="" ? fsrc.toAscii().data() : 0); + mShaders[k].prog.Link(); + if (mShaderSrcs[k*2+0]!="") + { + std::string compileinfo = mShaders[k].vshd.InfoLog(); + if (compileinfo.size()>0) + std::cout << "Vertex shader info (" << passNames[k] << ":\n" << compileinfo << "\n"; + } + if (mShaderSrcs[k*2+1]!="") + { + std::string compileinfo = mShaders[k].fshd.InfoLog(); + if (compileinfo.size()>0) + std::cout << "Fragment shader info (" << passNames[k] << ":\n" << compileinfo << "\n"; + } + std::string linkinfo = mShaders[k].prog.InfoLog(); + if (linkinfo.size()>0) + std::cout << "Link info (" << passNames[k] << ":\n" << linkinfo << "\n"; + } +} + +template +void SplatRenderer::Init(QGLWidget *gla) +{ + + mIsSupported = true; + gla->makeCurrent(); + // FIXME this should be done in meshlab !!! ?? + glewInit(); + + const char* rs = (const char*)glGetString(GL_RENDERER); + QString rendererString(""); + if(rs) + rendererString = QString(rs); + mWorkaroundATI = rendererString.startsWith("ATI") || rendererString.startsWith("AMD"); + // FIXME: maybe some recent HW correctly supports floating point blending... + mBuggedAtiBlending = rendererString.startsWith("ATI") || rendererString.startsWith("AMD"); + + if (mWorkaroundATI && mDummyTexId==0) + { + glActiveTexture(GL_TEXTURE0); + glGenTextures(1,&mDummyTexId); + glBindTexture(GL_TEXTURE_2D, mDummyTexId); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0); + } + + // let's check the GPU capabilities + mSupportedMask = DEPTH_CORRECTION_BIT | BACKFACE_SHADING_BIT; + if (!QGLFramebufferObject::hasOpenGLFramebufferObjects ()) + { + mIsSupported = false; + return; + } + if (GLEW_ARB_texture_float) + mSupportedMask |= FLOAT_BUFFER_BIT; + else + std::cout << "Splatting: warning floating point textures are not supported.\n"; + + if (GLEW_ARB_draw_buffers && (!mBuggedAtiBlending)) + mSupportedMask |= DEFERRED_SHADING_BIT; + else + std::cout << "Splatting: warning deferred shading is not supported.\n"; + + if (GLEW_ARB_shadow) + mSupportedMask |= OUTPUT_DEPTH_BIT; + else + std::cerr << "Splatting: warning copy of the depth buffer is not supported.\n"; + + mFlags = mFlags & mSupportedMask; + + // load shader source + mShaderSrcs[0] = loadSource("VisibilityVP","Raycasting.glsl"); + mShaderSrcs[1] = loadSource("VisibilityFP","Raycasting.glsl"); + mShaderSrcs[2] = loadSource("AttributeVP","Raycasting.glsl"); + mShaderSrcs[3] = loadSource("AttributeFP","Raycasting.glsl"); + mShaderSrcs[4] = ""; + mShaderSrcs[5] = loadSource("Finalization","Finalization.glsl"); + + //mCurrentPass = 2; + mBindedPass = -1; + GL_TEST_ERR +} + +template +void SplatRenderer::updateRenderBuffer() +{ + if ( (!mRenderBuffer) + || (mRenderBuffer->width()!=mCachedVP[2]) + || (mRenderBuffer->height()!=mCachedVP[3]) + || ( (mCachedFlags & mRenderBufferMask) != (mFlags & mRenderBufferMask) )) + { + delete mRenderBuffer; + GLenum fmt = (mFlags&FLOAT_BUFFER_BIT) ? GL_RGBA16F_ARB : GL_RGBA; + mRenderBuffer = new QGLFramebufferObject(mCachedVP[2], mCachedVP[3], + (mFlags&OUTPUT_DEPTH_BIT) ? QGLFramebufferObject::NoAttachment : QGLFramebufferObject::Depth, + GL_TEXTURE_RECTANGLE_ARB, fmt); + + if (!mRenderBuffer->isValid()) + { + std::cout << "SplatRenderer: invalid FBO\n"; + } + + GL_TEST_ERR + if (mFlags&DEFERRED_SHADING_BIT) + { + // in deferred shading mode we need an additional buffer to accumulate the normals + if (mNormalTextureID==0) + glGenTextures(1,&mNormalTextureID); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mNormalTextureID); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, fmt, mCachedVP[2], mCachedVP[3], 0, GL_RGBA, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + mRenderBuffer->bind(); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, mNormalTextureID, 0); + mRenderBuffer->release(); + GL_TEST_ERR + } + + if (mFlags&OUTPUT_DEPTH_BIT) + { + // to output the depth values to the final depth buffer we need to + // attach a depth buffer as a texture + if (mDepthTextureID==0) + glGenTextures(1,&mDepthTextureID); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mDepthTextureID); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24_ARB, mCachedVP[2], mCachedVP[3], 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + mRenderBuffer->bind(); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, mDepthTextureID, 0); + mRenderBuffer->release(); + GL_TEST_ERR + } + } +} + + +template +void SplatRenderer::Render(std::vector & meshes, vcg::GLW::ColorMode cm, vcg::GLW::TextureMode tm ) +{ + if(meshes.empty()) return; + + GL_TEST_ERR + + /*************** First Pass ***********/ + // this is the first pass of the frame, so let's update the shaders, buffers, etc... + glGetIntegerv(GL_VIEWPORT, mCachedVP); + glGetFloatv(GL_MODELVIEW_MATRIX, mCachedMV); + glGetFloatv(GL_PROJECTION_MATRIX, mCachedProj); + + updateRenderBuffer(); + if (mCachedFlags != mFlags) + configureShaders(); + + mCachedFlags = mFlags; + + mParams.update(mCachedMV, mCachedProj, mCachedVP); + //float s = meshes[0]->glw.GetHintParamf(vcg::GLW::HNPPointSize); + //if (s>1) + // s = pow(s,0.3f); + float s = 1.f; + mParams.radiusScale *= s; + + // FIXME since meshlab does not set any material properties, let's define some here + glDisable(GL_COLOR_MATERIAL); + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 64); + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, vcg::Point4f(0.3, 0.3, 0.3, 1.).V()); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vcg::Point4f(0.6, 0.6, 0.6, 1.).V()); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, vcg::Point4f(0.5, 0.5, 0.5, 1.).V()); + + mRenderBuffer->bind(); + if (mFlags&DEFERRED_SHADING_BIT) + { + GLenum buf[2] = {GL_COLOR_ATTACHMENT0_EXT,GL_COLOR_ATTACHMENT1_EXT}; + glDrawBuffersARB(2, buf); + } + glViewport(mCachedVP[0],mCachedVP[1],mCachedVP[2],mCachedVP[3]); + glClearColor(0,0,0,0); + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + //* End Setup of first Pass Now a simple rendering of all the involved meshes.*/ + mParams.loadTo(mShaders[0].prog); + enablePass(0); + drawSplats(meshes,cm,tm); + + // begin second pass + mParams.loadTo(mShaders[1].prog); + enablePass(1); + + drawSplats(meshes,cm,tm); + + //* Start third Pass Setup */ + + // this is the last pass: normalization by the sum of weights + deferred shading + mRenderBuffer->release(); + if (mFlags&DEFERRED_SHADING_BIT) + glDrawBuffer(GL_BACK); + + enablePass(2); + + // switch to normalized 2D rendering mode + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + mShaders[2].prog.Uniform("viewport",float(mCachedVP[0]),float(mCachedVP[1]),float(mCachedVP[2]),float(mCachedVP[3])); + mShaders[2].prog.Uniform("ColorWeight",GLint(0)); // this is a texture unit + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB,mRenderBuffer->texture()); + + if (mFlags&DEFERRED_SHADING_BIT) + { + mShaders[2].prog.Uniform("unproj", mCachedProj[10], mCachedProj[14]); + mShaders[2].prog.Uniform("NormalWeight",GLint(1)); // this is a texture unit + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB,mNormalTextureID); + GL_TEST_ERR + } + + if (mFlags&OUTPUT_DEPTH_BIT) + { + mShaders[2].prog.Uniform("Depth",GLint(2)); // this is a texture unit + glActiveTexture(GL_TEXTURE2);GL_TEST_ERR + glBindTexture(GL_TEXTURE_RECTANGLE_ARB,mDepthTextureID);GL_TEST_ERR + GL_TEST_ERR + } + else + { + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + } + + // draw a quad covering the whole screen + vcg::Point3f viewVec(1./mCachedProj[0], 1./mCachedProj[5], -1); + + glBegin(GL_QUADS); + glColor3f(1, 0, 0); + glTexCoord3f(viewVec.X(),viewVec.Y(),viewVec.Z()); + glMultiTexCoord2f(GL_TEXTURE1,1.,1.); + glVertex3f(1,1,0); + + glColor3f(1, 1, 0); + glTexCoord3f(-viewVec.X(),viewVec.Y(),viewVec.Z()); + glMultiTexCoord2f(GL_TEXTURE1,0.,1.); + glVertex3f(-1,1,0); + + glColor3f(0, 1, 1); + glTexCoord3f(-viewVec.X(),-viewVec.Y(),viewVec.Z()); + glMultiTexCoord2f(GL_TEXTURE1,0.,0.); + glVertex3f(-1,-1,0); + + glColor3f(1, 0, 1); + glTexCoord3f(viewVec.X(),-viewVec.Y(),viewVec.Z()); + glMultiTexCoord2f(GL_TEXTURE1,1.,0.); + glVertex3f(1,-1,0); + glEnd(); + if (!(mFlags&OUTPUT_DEPTH_BIT)) + { + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + } + + glUseProgram(0); + + // restore matrices + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + GL_TEST_ERR + +} + + +template +void SplatRenderer::Render( + std::vector< std::vector * > & positions, + std::vector< std::vector * > & normals, + std::vector< std::vector > * > & colors, + std::vector & radius, vcg::GLW::ColorMode cm, vcg::GLW::TextureMode tm ) +{ + if(positions.empty()) return; + + GL_TEST_ERR + + /*************** First Pass ***********/ + // this is the first pass of the frame, so let's update the shaders, buffers, etc... + glGetIntegerv(GL_VIEWPORT, mCachedVP); + glGetFloatv(GL_MODELVIEW_MATRIX, mCachedMV); + glGetFloatv(GL_PROJECTION_MATRIX, mCachedProj); + + updateRenderBuffer(); + if (mCachedFlags != mFlags) + configureShaders(); + + mCachedFlags = mFlags; + + mParams.update(mCachedMV, mCachedProj, mCachedVP); + //float s = meshes[0]->glw.GetHintParamf(vcg::GLW::HNPPointSize); + //if (s>1) + // s = pow(s,0.3f); + float s = 1.f; + mParams.radiusScale *= s; + + // FIXME since meshlab does not set any material properties, let's define some here + glDisable(GL_COLOR_MATERIAL); + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 64); + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, vcg::Point4f(0.3, 0.3, 0.3, 1.).V()); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vcg::Point4f(0.6, 0.6, 0.6, 1.).V()); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, vcg::Point4f(0.5, 0.5, 0.5, 1.).V()); + + mRenderBuffer->bind(); + if (mFlags&DEFERRED_SHADING_BIT) + { + GLenum buf[2] = {GL_COLOR_ATTACHMENT0_EXT,GL_COLOR_ATTACHMENT1_EXT}; + glDrawBuffersARB(2, buf); + } + glViewport(mCachedVP[0],mCachedVP[1],mCachedVP[2],mCachedVP[3]); + glClearColor(0,0,0,0); + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + //* End Setup of first Pass Now a simple rendering of all the involved meshes.*/ + mParams.loadTo(mShaders[0].prog); + enablePass(0); + drawSplats(positions,normals,colors,radius,cm,tm); + + // begin second pass + mParams.loadTo(mShaders[1].prog); + enablePass(1); + + drawSplats(positions,normals,colors,radius,cm,tm); + + //* Start third Pass Setup */ + + // this is the last pass: normalization by the sum of weights + deferred shading + mRenderBuffer->release(); + if (mFlags&DEFERRED_SHADING_BIT) + glDrawBuffer(GL_BACK); + + enablePass(2); + + // switch to normalized 2D rendering mode + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + mShaders[2].prog.Uniform("viewport",float(mCachedVP[0]),float(mCachedVP[1]),float(mCachedVP[2]),float(mCachedVP[3])); + mShaders[2].prog.Uniform("ColorWeight",GLint(0)); // this is a texture unit + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB,mRenderBuffer->texture()); + + if (mFlags&DEFERRED_SHADING_BIT) + { + mShaders[2].prog.Uniform("unproj", mCachedProj[10], mCachedProj[14]); + mShaders[2].prog.Uniform("NormalWeight",GLint(1)); // this is a texture unit + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB,mNormalTextureID); + GL_TEST_ERR + } + + if (mFlags&OUTPUT_DEPTH_BIT) + { + mShaders[2].prog.Uniform("Depth",GLint(2)); // this is a texture unit + glActiveTexture(GL_TEXTURE2);GL_TEST_ERR + glBindTexture(GL_TEXTURE_RECTANGLE_ARB,mDepthTextureID);GL_TEST_ERR + GL_TEST_ERR + } + else + { + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + } + + // draw a quad covering the whole screen + vcg::Point3f viewVec(1./mCachedProj[0], 1./mCachedProj[5], -1); + + glBegin(GL_QUADS); + glColor3f(1, 0, 0); + glTexCoord3f(viewVec.X(),viewVec.Y(),viewVec.Z()); + glMultiTexCoord2f(GL_TEXTURE1,1.,1.); + glVertex3f(1,1,0); + + glColor3f(1, 1, 0); + glTexCoord3f(-viewVec.X(),viewVec.Y(),viewVec.Z()); + glMultiTexCoord2f(GL_TEXTURE1,0.,1.); + glVertex3f(-1,1,0); + + glColor3f(0, 1, 1); + glTexCoord3f(-viewVec.X(),-viewVec.Y(),viewVec.Z()); + glMultiTexCoord2f(GL_TEXTURE1,0.,0.); + glVertex3f(-1,-1,0); + + glColor3f(1, 0, 1); + glTexCoord3f(viewVec.X(),-viewVec.Y(),viewVec.Z()); + glMultiTexCoord2f(GL_TEXTURE1,1.,0.); + glVertex3f(1,-1,0); + glEnd(); + if (!(mFlags&OUTPUT_DEPTH_BIT)) + { + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + } + + glUseProgram(0); + + // restore matrices + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + GL_TEST_ERR + +} +#if 0 +void SplatRenderer::Draw(QAction *a, MeshModel &m, RenderMode &rm, QGLWidget * gla) +{ + if (m.vert.RadiusEnabled) + { + if (mCurrentPass==2) + return; + + enablePass(mCurrentPass); + /*if (mCurrentPass==1)*/ drawSplats(m, rm); + } + else if (mCurrentPass==2) + { + MeshRenderInterface::Draw(a, m, rm, gla); + } +} +#endif +template +void SplatRenderer::enablePass(int n) +{ + if (mBindedPass!=n) + { + if (mBindedPass>=0) + mShaders[mBindedPass].prog.Unbind(); + mShaders[n].prog.Bind(); + mBindedPass = n; + + // set GL states + if (n==0) + { + glDisable(GL_LIGHTING); +// glDisable(GL_POINT_SMOOTH); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + + glAlphaFunc(GL_LESS,1); + glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE); + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); + glEnable(GL_ALPHA_TEST); + glEnable(GL_DEPTH_TEST); + +// glActiveTexture(GL_TEXTURE0); +// glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); +// glEnable(GL_POINT_SPRITE_ARB); + } + if (n==1) + { + glDisable(GL_LIGHTING); + glEnable(GL_POINT_SMOOTH); + glActiveTexture(GL_TEXTURE0); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + + glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE,GL_ONE); +// //glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE,GL_ZERO); +// glBlendFunc(GL_ONE,GL_ZERO); + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glDisable(GL_ALPHA_TEST); + +// glActiveTexture(GL_TEXTURE0); + + } + if ( (n==0) || (n==1) ) + { + // enable point sprite rendering mode + glActiveTexture(GL_TEXTURE0); + if (mWorkaroundATI) + { + glBindTexture(GL_TEXTURE_2D, mDummyTexId); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 2, 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0); + glPointParameterf(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT); + // hm... ^^^^ + } + glTexEnvf(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); + glEnable(GL_POINT_SPRITE_ARB); + } + if (n==2) + { + glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); + glDepthMask(GL_TRUE); + glDisable(GL_LIGHTING); + glDisable(GL_BLEND); + } + } +} + + +template +void SplatRenderer::drawSplats( + std::vector< std::vector * > & positions, + std::vector< std::vector * > & normals, + std::vector< std::vector > * > & colors, + std::vector & radius, + vcg::GLW::ColorMode cm, vcg::GLW::TextureMode tm) +{ + for(unsigned int ii = 0; ii < positions.size();++ii) + { + + glBegin(GL_POINTS); + glMultiTexCoord1f(GL_TEXTURE2, radius[ii] ); + + for(unsigned int vi= 0;vi< positions[ii]->size() ;++vi){ + vcg::Point3 co = (*colors[ii])[vi]; + glColor3ub ( co[0],co[1],co[2]); + glNormal((*normals[ii])[vi]); + glVertex( (*positions[ii])[vi]); + } + glEnd(); + } +} + + +template +void SplatRenderer::drawSplats(std::vector & meshes, vcg::GLW::ColorMode cm, vcg::GLW::TextureMode tm) +{ + + // check if we have to use the immediate mode + if(meshes.empty()) return; + int nV = 0; + unsigned int ii = 0; + for(; ii < meshes.size();++ii){ + nV+=meshes[ii]->vn; + if((nV>150000) || (meshes[ii]->vn!=(int) meshes[ii]->vert.size())) + break; + } + bool immediatemode = ii glw; + glw.m = &m; + glw.Draw(vcg::GLW::DMPoints,cm,tm); + + glClientActiveTexture(GL_TEXTURE2); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + } +} + +template +void SplatRenderer::UniformParameters::update(float* mv, float* proj, GLint* vp) +{ + // extract the uniform scale + float scale = vcg::Point3f(mv[0],mv[1],mv[2]).Norm(); + + radiusScale = scale; + preComputeRadius = - std::max(proj[0]*vp[2], proj[5]*vp[3]); + depthOffset = 2.0; + oneOverEwaRadius = 0.70710678118654; + halfVp = vcg::Point2f(0.5*vp[2], 0.5*vp[3]); + rayCastParameter1 =vcg::Point3f(2./(proj[0]*vp[2]), 2./(proj[5]*vp[3]), 0.0); + rayCastParameter2 =vcg::Point3f(-1./proj[0], -1./proj[5], -1.0); + depthParameterCast = vcg::Point2f(0.5*proj[14], 0.5-0.5*proj[10]); +} +template +void SplatRenderer ::UniformParameters::loadTo(Program& prg) +{ + prg.Bind(); + prg.Uniform("expeRadiusScale",radiusScale); + prg.Uniform("expePreComputeRadius",preComputeRadius); + prg.Uniform("expeDepthOffset",depthOffset); + prg.Uniform("oneOverEwaRadius",oneOverEwaRadius); + prg.Uniform("halfVp",halfVp); + prg.Uniform("rayCastParameter1",rayCastParameter1); + prg.Uniform("rayCastParameter2",rayCastParameter2); + prg.Uniform("depthParameterCast",depthParameterCast); +} + +#endif + diff --git a/wrap/gl/splatting_apss/splatrenderer.qrc b/wrap/gl/splatting_apss/splatrenderer.qrc new file mode 100644 index 00000000..2aa027c7 --- /dev/null +++ b/wrap/gl/splatting_apss/splatrenderer.qrc @@ -0,0 +1,6 @@ + + + shaders/Raycasting.glsl + shaders/Finalization.glsl + +