Commit 094842ea authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Extensive update for GeometryRenderer:

 * Supports different render modes: GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_POLYGON
 * Supports optional wireframe rendering using Single-pass Wireframe Rendering technique
 * Supports calculation of per-face normals, if not present in geometry
 * Fixed shading
parent 3fcec774
......@@ -23,23 +23,46 @@
// ================================================================================================
#include "tools/shading.frag"
#include "tools/texture3d.frag"
// input from geometry shader
in vec4 geom_Position;
in vec3 geom_TexCoord;
in vec4 geom_Color;
in vec3 geom_Normal;
noperspective in vec3 geom_EdgeDistance;
in vec3 ex_TexCoord; ///< incoming texture coordinate
in vec4 ex_Position; ///< incoming texture coordinate
// output fragment color
out vec4 out_Color;
out vec4 out_Color; ///< outgoing fragment color
// additional uniforms
uniform bool _useSolidColor;
uniform vec4 _solidColor;
uniform vec4 _wireframeColor;
uniform float _lineWidth;
uniform vec4 _color;
uniform LightSource _lightSource;
uniform vec3 _cameraPosition;
void main() {
out_Color = _color;
out_Color = _useSolidColor ? _solidColor : geom_Color;
#ifdef ENABLE_SHADING
// compute gradient (needed for shading and normals)
vec3 gradient = ex_TexCoord;
out_Color.rgb = calculatePhongShading(ex_Position.xyz / ex_Position.z, _lightSource, _cameraPosition, gradient, _color.rgb, _color.rgb, vec3(1.0, 1.0, 1.0));
// perform Phong shading
out_Color.rgb = calculatePhongShading(geom_Position.xyz / geom_Position.w, _lightSource, _cameraPosition, geom_Normal, out_Color.rgb, out_Color.rgb, vec3(1.0, 1.0, 1.0));
#endif
#ifdef WIREFRAME_RENDERING
// Find the smallest distance to the edges
float d = min(geom_EdgeDistance.x, min(geom_EdgeDistance.y, geom_EdgeDistance.z));
// Determine the mix factor with the line color
float aliasingWidth = min(1.0, (_lineWidth/8.0));
float mixVal = smoothstep(_lineWidth - aliasingWidth, _lineWidth + aliasingWidth, d);
// Mix the surface color with the line color
out_Color = mix(_wireframeColor, out_Color, mixVal);
#endif
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
// Code taken and inspired from the "OpenGL 4.0 Shading Language Cookbook", Chapter 6:
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
in vec4 vert_Position[];
in vec3 vert_TexCoord[]; ///< incoming texture coordinate
in vec4 vert_Color[];
in vec3 vert_Normal[];
out vec4 geom_Position;
out vec3 geom_TexCoord;
out vec4 geom_Color; ///< outgoing fragment color
out vec3 geom_Normal;
noperspective out vec3 geom_EdgeDistance;
/// Matrix defining viewport transformation
uniform mat4 _viewportMatrix;
uniform bool _computeNormals;
void main() {
vec3 normal = normalize(cross(vert_Position[2].xyz - vert_Position[0].xyz, vert_Position[1].xyz - vert_Position[0].xyz));
// Transform each vertex into viewport space
vec3 p0 = vec3(_viewportMatrix * (gl_in[0].gl_Position / gl_in[0].gl_Position.w));
vec3 p1 = vec3(_viewportMatrix * (gl_in[1].gl_Position / gl_in[1].gl_Position.w));
vec3 p2 = vec3(_viewportMatrix * (gl_in[2].gl_Position / gl_in[2].gl_Position.w));
// Find the altitudes (ha, hb and hc)
float a = length(p1 - p2);
float b = length(p2 - p0);
float c = length(p1 - p0);
float alpha = acos((b*b + c*c - a*a) / (2.0*b*c));
float beta = acos((a*a + c*c - b*b) / (2.0*a*c));
float ha = abs(c * sin(beta));
float hb = abs(c * sin(alpha));
float hc = abs(b * sin(alpha));
// Send the triangle along with the edge distances
geom_EdgeDistance = vec3(ha, 0, 0);
geom_Normal = _computeNormals ? normal : vert_Normal[0];
geom_Position = vert_Position[0];
geom_TexCoord = vert_TexCoord[0];
gl_Position = gl_in[0].gl_Position;
EmitVertex();
geom_EdgeDistance = vec3(0, hb, 0);
geom_Normal = _computeNormals ? normal : vert_Normal[1];
geom_Position = vert_Position[1];
geom_TexCoord = vert_TexCoord[1];
gl_Position = gl_in[1].gl_Position;
EmitVertex();
geom_EdgeDistance = vec3(0, 0, hc);
geom_Normal = _computeNormals ? normal : vert_Normal[2];
geom_Position = vert_Position[2];
geom_TexCoord = vert_TexCoord[2];
gl_Position = gl_in[2].gl_Position;
EmitVertex();
EndPrimitive();
}
\ No newline at end of file
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
layout (location = 0) in vec3 in_Position; ///< incoming vertex position
layout (location = 1) in vec3 in_TexCoord; ///< incoming texture coordinate
layout (location = 2) in vec4 in_Color; ///< incoming color
layout (location = 3) in vec3 in_Normal; ///< incoming normals
#ifdef HAS_GEOMETRY_SHADER
out vec4 vert_Position; ///< outgoing world coordinates
out vec3 vert_TexCoord; ///< outgoing texture coordinate
out vec4 vert_Color; ///< outgoing color
out vec3 vert_Normal; ///< outgoing world normals
#else
out vec4 geom_Position; ///< outgoing texture coordinate
out vec3 geom_TexCoord; ///< outgoing color
out vec4 geom_Color; ///< outgoing world coordinates
out vec3 geom_Normal; ///< outgoing world normals
#endif
/// Matrix defining model-to-world transformation
uniform mat4 _modelMatrix = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
/// Matrix defining view transformation
uniform mat4 _viewMatrix = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
/// Matrix defining projection transformation
uniform mat4 _projectionMatrix = mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
void main() {
#ifdef HAS_GEOMETRY_SHADER
// set outputs for geometry shader
vert_Position = vec4(in_Position, 1.0);
gl_Position = _projectionMatrix * (_viewMatrix * (_modelMatrix * vec4(in_Position, 1.0)));
vert_TexCoord = in_TexCoord;
vert_Color = in_Color;
vert_Normal = in_Normal;
#else
// set outputs for fragment shader
geom_Position = vec4(in_Position, 1.0);
gl_Position = _projectionMatrix * (_viewMatrix * (_modelMatrix * vec4(in_Position, 1.0)));
geom_TexCoord = in_TexCoord;
geom_Color = in_Color;
geom_Normal = in_Normal;
#endif
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#include "geometryrendererdemo.h"
#include "core/datastructures/imagedata.h"
#include "core/classification/geometry1dtransferfunction.h"
#include "core/classification/tfgeometry1d.h"
#include "core/datastructures/geometrydatafactory.h"
namespace campvis {
GeometryRendererDemo::GeometryRendererDemo(DataContainer* dc)
: AutoEvaluationPipeline(dc)
, _camera("camera", "Camera")
, _geometryReader()
, _gr(&_canvasSize)
, _trackballEH(0)
{
addProperty(&_camera);
_trackballEH = new TrackballNavigationEventListener(&_camera, &_canvasSize);
_trackballEH->addLqModeProcessor(&_gr);
addEventListenerToBack(_trackballEH);
addProcessor(&_geometryReader);
addProcessor(&_gr);
}
GeometryRendererDemo::~GeometryRendererDemo() {
delete _trackballEH;
}
void GeometryRendererDemo::init() {
AutoEvaluationPipeline::init();
_geometryReader.s_validated.connect(this, &GeometryRendererDemo::onProcessorValidated);
_camera.addSharedProperty(&_gr.p_camera);
_gr.p_renderTargetID.setValue("combine");
_gr.p_renderMode.selectById("triangles");
_renderTargetID.setValue("combine");
_geometryReader.p_url.setValue(CAMPVIS_SOURCE_DIR "/modules/vis/sampledata/left_ventricle_mesh.vtk");
_geometryReader.p_targetImageID.setValue("reader.output");
_geometryReader.p_targetImageID.addSharedProperty(&_gr.p_geometryID);
MeshGeometry* cube = GeometryDataFactory::createCube(tgt::Bounds(tgt::vec3(0.f), tgt::vec3(1.f)), tgt::Bounds(tgt::vec3(0.f), tgt::vec3(1.f)));
getDataContainer().addData("reader.output", cube);
_trackballEH->reinitializeCamera(cube);
}
void GeometryRendererDemo::deinit() {
_geometryReader.s_validated.disconnect(this);
AutoEvaluationPipeline::deinit();
}
void GeometryRendererDemo::onProcessorValidated(AbstractProcessor* processor) {
if (processor == &_geometryReader) {
// update camera
ScopedTypedData<IHasWorldBounds> img(*_data, _geometryReader.p_targetImageID.getValue());
if (img != 0) {
_trackballEH->reinitializeCamera(img);
}
}
}
}
\ No newline at end of file
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#ifndef GEOMETRYRENDERERDEMO_H__
#define GEOMETRYRENDERERDEMO_H__
#include "core/eventhandlers/trackballnavigationeventlistener.h"
#include "core/pipeline/autoevaluationpipeline.h"
#include "core/properties/cameraproperty.h"
#include "modules/io/processors/vtkimagereader.h"
#include "modules/vis/processors/geometryrenderer.h"
namespace campvis {
class GeometryRendererDemo : public AutoEvaluationPipeline {
public:
/**
* Creates a AutoEvaluationPipeline.
*/
GeometryRendererDemo(DataContainer* dc);
/**
* Virtual Destructor
**/
virtual ~GeometryRendererDemo();
/// \see AutoEvaluationPipeline::init()
virtual void init();
/// \see AutoEvaluationPipeline::deinit()
virtual void deinit();
/// \see AbstractPipeline::getName()
virtual const std::string getName() const { return getId(); };
static const std::string getId() { return "GeometryRendererDemo"; };
protected:
/**
* Slot getting called when one of the observed processors got validated.
* Updates the camera properties, when the input image has changed.
* \param processor The processor that emitted the signal
*/
virtual void onProcessorValidated(AbstractProcessor* processor);
CameraProperty _camera;
VtkImageReader _geometryReader;
GeometryRenderer _gr;
TrackballNavigationEventListener* _trackballEH;
};
}
#endif // GEOMETRYRENDERERDEMO_H__
......@@ -35,6 +35,16 @@
#include "core/pipeline/processordecoratorshading.h"
namespace campvis {
static const GenericOption<GLenum> renderOptions[7] = {
GenericOption<GLenum>("points", "GL_POINTS", GL_POINTS),
GenericOption<GLenum>("lines", "GL_LINES", GL_LINES),
GenericOption<GLenum>("linestrip", "GL_LINE_STRIP", GL_LINE_STRIP),
GenericOption<GLenum>("triangles", "GL_TRIANGLES", GL_TRIANGLES),
GenericOption<GLenum>("trianglefan", "GL_TRIANGLE_FAN", GL_TRIANGLE_FAN),
GenericOption<GLenum>("trianglestrip", "GL_TRIANGLE_STRIP", GL_TRIANGLE_STRIP),
GenericOption<GLenum>("polygon", "GL_POLYGON", GL_POLYGON)
};
const std::string GeometryRenderer::loggerCat_ = "CAMPVis.modules.vis.GeometryRenderer";
GeometryRenderer::GeometryRenderer(IVec2Property* viewportSizeProp)
......@@ -42,15 +52,31 @@ namespace campvis {
, p_geometryID("geometryID", "Input Geometry ID", "gr.input", DataNameProperty::READ)
, p_renderTargetID("p_renderTargetID", "Output Image", "gr.output", DataNameProperty::WRITE)
, p_camera("camera", "Camera")
, p_color("color", "Rendering Color", tgt::vec4(1.f), tgt::vec4(0.f), tgt::vec4(1.f))
, _shader(0)
, p_useSolidColor("UseSolidColor", "Use Solid Color", true, AbstractProcessor::INVALID_RESULT | AbstractProcessor::INVALID_PROPERTIES)
, p_solidColor("SolidColor", "Solid Color", tgt::vec4(1.f, .5f, 0.f, 1.f), tgt::vec4(0.f), tgt::vec4(1.f))
, p_renderMode("RenderMode", "Render Mode", renderOptions, 7, AbstractProcessor::INVALID_RESULT | AbstractProcessor::INVALID_PROPERTIES)
, p_pointSize("PointSize", "Point Size", 3.f, .1f, 10.f)
, p_lineWidth("LineWidth", "Line Width", 1.f, .1f, 10.f)
, p_showWireframe("ShowWireframe", "Show Wireframe", true, AbstractProcessor::INVALID_RESULT | AbstractProcessor::INVALID_SHADER | AbstractProcessor::INVALID_PROPERTIES)
, p_wireframeColor("WireframeColor", "Wireframe Color", tgt::vec4(1.f, 1.f, 1.f, 1.f), tgt::vec4(0.f), tgt::vec4(1.f))
, _pointShader(0)
, _meshShader(0)
{
addDecorator(new ProcessorDecoratorShading());
addProperty(&p_geometryID);
addProperty(&p_renderTargetID);
addProperty(&p_camera);
addProperty(&p_color);
addProperty(&p_renderMode);
addProperty(&p_useSolidColor);
addProperty(&p_solidColor);
addProperty(&p_pointSize);
addProperty(&p_lineWidth);
addProperty(&p_showWireframe);
addProperty(&p_wireframeColor);
decoratePropertyCollection(this);
}
......@@ -61,33 +87,49 @@ namespace campvis {
void GeometryRenderer::init() {
VisualizationProcessor::init();
_shader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "modules/vis/glsl/geometryrenderer.frag", "", false);
if (_shader != 0) {
_shader->setAttributeLocation(0, "in_Position");
}
_pointShader = ShdrMgr.loadSeparate("modules/vis/glsl/geometryrenderer.vert", "modules/vis/glsl/geometryrenderer.frag", generateGlslHeader(false), false);
_meshShader = ShdrMgr.loadSeparate("modules/vis/glsl/geometryrenderer.vert", "modules/vis/glsl/geometryrenderer.geom", "modules/vis/glsl/geometryrenderer.frag", generateGlslHeader(true), false);
}
void GeometryRenderer::deinit() {
ShdrMgr.dispose(_shader);
_shader = 0;
ShdrMgr.dispose(_pointShader);
_pointShader = 0;
VisualizationProcessor::deinit();
}
void GeometryRenderer::updateResult(DataContainer& data) {
ScopedTypedData<GeometryData> proxyGeometry(data, p_geometryID.getValue());
if (proxyGeometry != 0 && _shader != 0) {
if (proxyGeometry != 0 && _pointShader != 0 && _meshShader != 0) {
// select correct shader
tgt::Shader* leShader = 0;
if (p_renderMode.getOptionValue() == GL_POINTS || p_renderMode.getOptionValue() == GL_LINES || p_renderMode.getOptionValue() == GL_LINE_STRIP)
leShader = _pointShader;
else
leShader = _meshShader;
// calculate viewport matrix for NDC -> viewport conversion
tgt::vec2 halfViewport = tgt::vec2(getEffectiveViewportSize()) / 2.f;
tgt::mat4 viewportMatrix = tgt::mat4::createTranslation(tgt::vec3(halfViewport, 0.f)) * tgt::mat4::createScale(tgt::vec3(halfViewport, 1.f));
// set modelview and projection matrices
_shader->activate();
_shader->setIgnoreUniformLocationError(true);
decorateRenderProlog(data, _shader);
_shader->setUniform("_projectionMatrix", p_camera.getValue().getProjectionMatrix());
_shader->setUniform("_viewMatrix", p_camera.getValue().getViewMatrix());
_shader->setUniform("_color", p_color.getValue());
_shader->setUniform("_cameraPosition", p_camera.getValue().getPosition());
_shader->setIgnoreUniformLocationError(false);
// create entry points texture
leShader->activate();
leShader->setIgnoreUniformLocationError(true);
decorateRenderProlog(data, leShader);
leShader->setUniform("_projectionMatrix", p_camera.getValue().getProjectionMatrix());
leShader->setUniform("_viewMatrix", p_camera.getValue().getViewMatrix());
leShader->setUniform("_viewportMatrix", viewportMatrix);
leShader->setUniform("_computeNormals", proxyGeometry->getNormalsBuffer() == 0);
leShader->setUniform("_useSolidColor", p_useSolidColor.getValue());
leShader->setUniform("_solidColor", p_solidColor.getValue());
leShader->setUniform("_wireframeColor", p_wireframeColor.getValue());
leShader->setUniform("_lineWidth", p_lineWidth.getValue());
leShader->setUniform("_cameraPosition", p_camera.getValue().getPosition());
leShader->setIgnoreUniformLocationError(false);
FramebufferActivationGuard fag(this);
createAndAttachColorTexture();
createAndAttachDepthTexture();
......@@ -96,10 +138,10 @@ namespace campvis {
glDepthFunc(GL_LESS);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
proxyGeometry->render();
proxyGeometry->render(p_renderMode.getOptionValue());
decorateRenderEpilog(_shader);
_shader->deactivate();
decorateRenderEpilog(leShader);
leShader->deactivate();
glDisable(GL_DEPTH_TEST);
LGL_ERROR;
......@@ -112,15 +154,52 @@ namespace campvis {
validate(INVALID_RESULT);
}
std::string GeometryRenderer::generateGlslHeader() const {
std::string GeometryRenderer::generateGlslHeader(bool hasGeometryShader) const {
std::string toReturn = getDecoratedHeader();
if (p_showWireframe.getValue())
toReturn += "#define WIREFRAME_RENDERING\n";
if (hasGeometryShader)
toReturn += "#define HAS_GEOMETRY_SHADER\n";
return toReturn;
}
void GeometryRenderer::updateShader() {
_shader->setHeaders(generateGlslHeader());
_shader->rebuild();
_pointShader->setHeaders(generateGlslHeader(false));
_pointShader->rebuild();
_meshShader->setHeaders(generateGlslHeader(true));
_meshShader->rebuild();
validate(INVALID_SHADER);
}
void GeometryRenderer::updateProperties(DataContainer& dataContainer) {
p_solidColor.setVisible(p_useSolidColor.getValue());
switch (p_renderMode.getOptionValue()) {
case GL_POINTS:
p_pointSize.setVisible(true);
p_lineWidth.setVisible(false);
p_showWireframe.setVisible(false);
break;
case GL_LINES: // fallthrough
case GL_LINE_STRIP:
p_pointSize.setVisible(false);
p_lineWidth.setVisible(true);
p_showWireframe.setVisible(false);
break;
case GL_TRIANGLES: // fallthrough
case GL_TRIANGLE_FAN: // fallthrough
case GL_TRIANGLE_STRIP: // fallthrough
case GL_POLYGON:
p_pointSize.setVisible(false);
p_lineWidth.setVisible(p_showWireframe.getValue());
p_showWireframe.setVisible(true);
break;
}
p_wireframeColor.setVisible(p_showWireframe.getValue());
}
}
......@@ -31,8 +31,9 @@
#include "core/pipeline/abstractprocessordecorator.h"
#include "core/properties/cameraproperty.h"
#include "core/properties/datanameproperty.h"
#include "core/properties/genericproperty.h"