The expiration time for new job artifacts in CI/CD pipelines is now 30 days (GitLab default). Previously generated artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

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"
#include "core/properties/floatingpointproperty.h"