From 05d84fa038f1602a4ebdc5327c6ccfcf316afeb9 Mon Sep 17 00:00:00 2001 From: Paolo Cignoni cignoni Date: Wed, 10 Dec 2008 23:03:16 +0000 Subject: [PATCH] renamed splatrender to the standard naming scheme render_splatting --- .../shaders/Finalization.glsl | 90 +++ .../shaders/Raycasting.glsl | 322 ++++++++++ .../renderer_splatting/splatrenderer.cpp | 556 ++++++++++++++++++ .../renderer_splatting/splatrenderer.h | 116 ++++ .../renderer_splatting/splatrenderer.pro | 11 + .../renderer_splatting/splatrenderer.qrc | 6 + 6 files changed, 1101 insertions(+) create mode 100644 src/meshlabplugins/renderer_splatting/shaders/Finalization.glsl create mode 100644 src/meshlabplugins/renderer_splatting/shaders/Raycasting.glsl create mode 100644 src/meshlabplugins/renderer_splatting/splatrenderer.cpp create mode 100644 src/meshlabplugins/renderer_splatting/splatrenderer.h create mode 100644 src/meshlabplugins/renderer_splatting/splatrenderer.pro create mode 100644 src/meshlabplugins/renderer_splatting/splatrenderer.qrc diff --git a/src/meshlabplugins/renderer_splatting/shaders/Finalization.glsl b/src/meshlabplugins/renderer_splatting/shaders/Finalization.glsl new file mode 100644 index 000000000..e4b2c093a --- /dev/null +++ b/src/meshlabplugins/renderer_splatting/shaders/Finalization.glsl @@ -0,0 +1,90 @@ + +#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; +#ifdef EXPE_OUTPUT_DEPTH +uniform sampler2DRect Depth; +#endif + +void Finalization(void) +{ + vec4 color = texture2DRect(ColorWeight, gl_FragCoord.st - viewport.xy + epsilon); + #ifdef EXPE_OUTPUT_DEPTH + 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/src/meshlabplugins/renderer_splatting/shaders/Raycasting.glsl b/src/meshlabplugins/renderer_splatting/shaders/Raycasting.glsl new file mode 100644 index 000000000..868399c9b --- /dev/null +++ b/src/meshlabplugins/renderer_splatting/shaders/Raycasting.glsl @@ -0,0 +1,322 @@ + +// #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); + 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/src/meshlabplugins/renderer_splatting/splatrenderer.cpp b/src/meshlabplugins/renderer_splatting/splatrenderer.cpp new file mode 100644 index 000000000..87eede280 --- /dev/null +++ b/src/meshlabplugins/renderer_splatting/splatrenderer.cpp @@ -0,0 +1,556 @@ +/**************************************************************************** +* 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. * +* * +****************************************************************************/ + +#include + +#include +#include +#include +#include "splatrenderer.h" +#include +#include +#include +#include + +using namespace std; +using namespace vcg; + +#define GL_TEST_ERR\ + {\ + GLenum eCode;\ + if((eCode=glGetError())!=GL_NO_ERROR)\ + std::cerr << "OpenGL error : " << gluErrorString(eCode) << " in " << __FILE__ << " : " << __LINE__ << std::endl;\ + } + +SplatRendererPlugin::SplatRendererPlugin() +{ + 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; +} + +void SplatRendererPlugin::initActionList() +{ + actionList << new QAction("Splatting", this); +} + +QString SplatRendererPlugin::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; +} + +void SplatRendererPlugin::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"; + } +} + +void SplatRendererPlugin::Init(QAction *a, MeshModel &m, RenderMode &rm, 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 +} + +void SplatRendererPlugin::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 + } + } +} + +void SplatRendererPlugin::Render(QAction *a, MeshModel &m, RenderMode &rm, QGLWidget * /* gla */) +{ + GL_TEST_ERR + mShaders[mCurrentPass].prog.Unbind(); + + mCurrentPass = (mCurrentPass+1) % 3; + + if (mCurrentPass==0) + { + // 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); + GL_TEST_ERR + + updateRenderBuffer(); GL_TEST_ERR + if (mCachedFlags != mFlags) + configureShaders(); + + GL_TEST_ERR + mCachedFlags = mFlags; + + mParams.update(mCachedMV, mCachedProj, mCachedVP); + float s = m.glw.GetHintParamf(GLW::HNPPointSize); + if (s>1) + s = pow(s,0.3f); + mParams.radiusScale *= s; + GL_TEST_ERR + + // 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()); + } + + if (mCurrentPass==2) + {//return; + // this is the last pass: normalization by the sum of weights + deferred shading + GL_TEST_ERR + mRenderBuffer->release(); + if (mFlags&DEFERRED_SHADING_BIT) + glDrawBuffer(GL_BACK); + + enablePass(mCurrentPass); + + // switch to normalized 2D rendering mode + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + GL_TEST_ERR + + mShaders[2].prog.Uniform("viewport",float(mCachedVP[0]),float(mCachedVP[1]),float(mCachedVP[2]),float(mCachedVP[3])); + mShaders[2].prog.Uniform("ColorWeight",0.0f); // this is a texture unit + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB,mRenderBuffer->texture()); + GL_TEST_ERR + + if (mFlags&DEFERRED_SHADING_BIT) + { + GL_TEST_ERR + mShaders[2].prog.Uniform("unproj", mCachedProj[10], mCachedProj[14]); + mShaders[2].prog.Uniform("NormalWeight",1.0f); // this is a texture unit + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB,mNormalTextureID); + GL_TEST_ERR + } + + if (mFlags&OUTPUT_DEPTH_BIT) + { + GL_TEST_ERR + mShaders[2].prog.Uniform("Depth",2.0f); // this is a texture unit + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB,mDepthTextureID); + 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); + + GL_TEST_ERR + 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(); + GL_TEST_ERR + if (!(mFlags&OUTPUT_DEPTH_BIT)) + { + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + } + + // restore matrices + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + GL_TEST_ERR + } + else + { + GL_TEST_ERR + mParams.loadTo(mShaders[mCurrentPass].prog); + if (mCurrentPass==0) + { + 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); + } + enablePass(mCurrentPass); + GL_TEST_ERR + } +} + +void SplatRendererPlugin::Draw(QAction *a, MeshModel &m, RenderMode &rm, QGLWidget * gla) +{ + if (m.cm.vert.RadiusEnabled) + { + if (mCurrentPass==2) + return; + + enablePass(mCurrentPass); + /*if (mCurrentPass==1)*/ drawSplats(m, rm); + } + else if (mCurrentPass==2) + { + MeshRenderInterface::Draw(a, m, rm, gla); + } +} + +void SplatRendererPlugin::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); GL_TEST_ERR; + glActiveTexture(GL_TEXTURE0); GL_TEST_ERR; + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); GL_TEST_ERR; + + 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); GL_TEST_ERR; + // 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); + } + } +} + +void SplatRendererPlugin::drawSplats(MeshModel &m, RenderMode &rm) +{ + if(m.cm.vn!=(int)m.cm.vert.size()) + { + // manual rendering + int cm = rm.colorMode; + if( (cm == GLW::CMPerFace) && (!tri::HasPerFaceColor(m.cm)) ) + cm=GLW::CMNone; + glPushMatrix(); + glMultMatrix(m.cm.Tr); + CMeshO::VertexIterator vi; + glBegin(GL_POINTS); + if(cm==GLW::CMPerMesh) + glColor(m.cm.C()); + + for(vi=m.cm.vert.begin();vi!=m.cm.vert.end();++vi) + if(!(*vi).IsD()) + { + glMultiTexCoord1f(GL_TEXTURE2, (*vi).cR()); + glNormal((*vi).cN()); + if (cm==GLW::CMPerVert) glColor((*vi).C()); + glVertex((*vi).P()); + } + glEnd(); + glPopMatrix(); + return; + } + + // bind the radius + glClientActiveTexture(GL_TEXTURE2); + glTexCoordPointer( + 1, + GL_FLOAT, + size_t(m.cm.vert[1].cR())-size_t(m.cm.vert[0].cR()), + &m.cm.vert[0].cR() + ); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + + // draw the vertices + m.Render(vcg::GLW::DMPoints,rm.colorMode,rm.textureMode); + + glClientActiveTexture(GL_TEXTURE2); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); +} + +void SplatRendererPlugin::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 = Point2f(0.5*vp[2], 0.5*vp[3]); + rayCastParameter1 = Point3f(2./(proj[0]*vp[2]), 2./(proj[5]*vp[3]), 0.0); + rayCastParameter2 = Point3f(-1./proj[0], -1./proj[5], -1.0); + depthParameterCast = Point2f(0.5*proj[14], 0.5-0.5*proj[10]); +} + +void SplatRendererPlugin::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); +} + +Q_EXPORT_PLUGIN(SplatRendererPlugin) diff --git a/src/meshlabplugins/renderer_splatting/splatrenderer.h b/src/meshlabplugins/renderer_splatting/splatrenderer.h new file mode 100644 index 000000000..f8b352f96 --- /dev/null +++ b/src/meshlabplugins/renderer_splatting/splatrenderer.h @@ -0,0 +1,116 @@ +/**************************************************************************** +* 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 +#include +#include +#include +class QGLFramebufferObject; + +class SplatRendererPlugin : public QObject, public MeshRenderInterface +{ + Q_OBJECT + Q_INTERFACES(MeshRenderInterface) + + bool mIsSupported; + QList actionList; + + 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(MeshModel &m, RenderMode &rm); + +public: + + SplatRendererPlugin(); + + QList actions () + { + if(actionList.isEmpty()) initActionList(); + return actionList; + } + + void initActionList(); + + virtual bool isSupported() {return mIsSupported;} + virtual void Init(QAction *a, MeshModel &m, RenderMode &rm, QGLWidget *gla); + virtual void Render(QAction *a, MeshModel &m, RenderMode &rm, QGLWidget *gla); + virtual void Draw(QAction *a, MeshModel &m, RenderMode &rm, QGLWidget *gla); + virtual int passNum() { return 3; } + +}; + +#endif + diff --git a/src/meshlabplugins/renderer_splatting/splatrenderer.pro b/src/meshlabplugins/renderer_splatting/splatrenderer.pro new file mode 100644 index 000000000..70cf0a2b2 --- /dev/null +++ b/src/meshlabplugins/renderer_splatting/splatrenderer.pro @@ -0,0 +1,11 @@ +include (../../shared.pri) + +HEADERS = splatrenderer.h +SOURCES = splatrenderer.cpp $$GLEWCODE + +TARGET = splatrenderer + +QT += opengl +RESOURCES = splatrenderer.qrc + +# CONFIG += debug diff --git a/src/meshlabplugins/renderer_splatting/splatrenderer.qrc b/src/meshlabplugins/renderer_splatting/splatrenderer.qrc new file mode 100644 index 000000000..2aa027c79 --- /dev/null +++ b/src/meshlabplugins/renderer_splatting/splatrenderer.qrc @@ -0,0 +1,6 @@ + + + shaders/Raycasting.glsl + shaders/Finalization.glsl + +