Developer Documentation
ToonRenderer.cc
1/*===========================================================================*\
2* *
3* OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39* *
40\*===========================================================================*/
41
42
43#include <ACG/GL/acg_glew.hh>
44#include "ToonRenderer.hh"
45
48#include <ACG/GL/ShaderCache.hh>
49#include <ACG/GL/ScreenQuad.hh>
50#include <ACG/GL/GLError.hh>
51
52// =================================================
53
54#define CELSHADING_INCLUDE_FILE "ToonRenderer/celshading.glsl"
55#define OUTLINE_VERTEXSHADER_FILE "ToonRenderer/screenquad.glsl"
56#define OUTLINE_FRAGMENTSHADER_FILE "ToonRenderer/outline.glsl"
57
59public:
60
62 // include cel lighting functions defined in CELSHADING_INCLUDE_FILE
63 QString includeCelShading = ACG::ShaderProgGenerator::getShaderDir() + QDir::separator() + QString(CELSHADING_INCLUDE_FILE);
64 _shader->addIncludeFile(includeCelShading);
65
66 // add shader constant that defines the number of different intensity levels used in lighting
67 _shader->addUniform("float g_celPaletteSize", "//number of palettes/intensity levels for cel shading");
68 }
69
71 // include cel lighting functions defined in CELSHADING_INCLUDE_FILE
72 QString includeCelShading = ACG::ShaderProgGenerator::getShaderDir() + QDir::separator() + QString(CELSHADING_INCLUDE_FILE);
73 _shader->addIncludeFile(includeCelShading);
74
75 // Note: We include the cel lighting functions in both shader stages
76 // because the ShaderGenerator may call modifyLightingCode() for either a vertex or fragment shader.
77 // It is not yet known in which stage the lighting is performed.
78
79
80 // Additionally write the depth of each fragment to a secondary render-target.
81 // This depth texture is used in a post-processing outlining step.
82 _shader->addOutput("float outDepth");
83 _shader->addUniform("float g_celPaletteSize", "//number of palettes/intensity levels for cel shading");
84 }
85
86
87 void modifyFragmentEndCode(QStringList* _code) {
88 _code->push_back("outDepth = gl_FragCoord.z;"); // write depth to secondary render texture
89 }
90
91 // modifier replaces default lighting with cel lighting
92 bool replaceDefaultLightingCode() {return true;}
93
94 void modifyLightingCode(QStringList* _code, int _lightId, ACG::ShaderGenLightType _lightType) {
95 // use cel shading functions instead of default lighting:
96
97 QString buf;
98
99 switch (_lightType) {
100 case ACG::SG_LIGHT_DIRECTIONAL:
101 buf = QString("sg_cColor.xyz += LitDirLight_Cel(sg_vPosVS.xyz, sg_vNormalVS, g_vLightDir_%1, g_cLightAmbient_%2, g_cLightDiffuse_%3, g_cLightSpecular_%4, g_celPaletteSize);").arg(_lightId).arg(_lightId).arg(_lightId).arg(_lightId);
102 break;
103
104 case ACG::SG_LIGHT_POINT:
105 buf = QString("sg_cColor.xyz += LitPointLight_Cel(sg_vPosVS.xyz, sg_vNormalVS, g_vLightPos_%1, g_cLightAmbient_%2, g_cLightDiffuse_%3, g_cLightSpecular_%4, g_vLightAtten_%5, g_celPaletteSize);").arg(_lightId).arg(_lightId).arg(_lightId).arg(_lightId).arg(_lightId);
106 break;
107
108 case ACG::SG_LIGHT_SPOT:
109 buf = QString("sg_cColor.xyz += LitSpotLight_Cel(sg_vPosVS.xyz, sg_vNormalVS, g_vLightPos_%1, g_vLightDir_%2, g_cLightAmbient_%3, g_cLightDiffuse_%4, g_cLightSpecular_%5, g_vLightAtten_%6, g_vLightAngleExp_%7, g_celPaletteSize);").arg(_lightId).arg(_lightId).arg(_lightId).arg(_lightId).arg(_lightId).arg(_lightId).arg(_lightId);
110 break;
111
112 default: break;
113 }
114
115 _code->push_back(buf);
116 }
117
118
119 static CelShadingModifier instance;
120};
121
122
123CelShadingModifier CelShadingModifier::instance;
124
125// =================================================
126
127ToonRenderer::ToonRenderer()
128 : progOutline_(0), paletteSize_(2.0f), outlineCol_(0.0f, 0.0f, 0.0f)
129{
130 ACG::ShaderProgGenerator::registerModifier(&CelShadingModifier::instance);
131}
132
133
134ToonRenderer::~ToonRenderer() {
135}
136
137QString ToonRenderer::checkOpenGL() {
138 if ( !ACG::openGLVersion(3, 2) )
139 return QString("Insufficient OpenGL Version! OpenGL 3.2 or higher required");
140
141 // Check extensions
142 QString missing("");
143 if(!ACG::openGLVersion(1,5)) // extension is part of opengl spec since version 1.5
144 { // i recommend removing this check in favor of restricting
145 // to a more modern version of opengl e.g. 2.1 should be minimum
146 if ( !ACG::checkExtensionSupported("GL_ARB_vertex_buffer_object") )
147 missing += "GL_ARB_vertex_buffer_object extension missing\n";
148 }
149#ifndef __APPLE__
150 if(!ACG::openGLVersion(1,4))
151 {
152 if ( !ACG::checkExtensionSupported("GL_ARB_vertex_program") )
153 missing += "GL_ARB_vertex_program extension missing\n";
154 }
155#endif
156 return missing;
157}
158
159void ToonRenderer::initializePlugin() {
160}
161
162void ToonRenderer::exit() {
163 delete progOutline_;
164 progOutline_ = 0;
165
166 viewerRes_.clear();
167}
168
169QString ToonRenderer::renderObjectsInfo(bool _outputShaderInfo) {
170 std::vector<ACG::ShaderModifier*> modifiers;
171 modifiers.push_back(&CelShadingModifier::instance);
172 return dumpCurrentRenderObjectsToString(&sortedObjects_[0], _outputShaderInfo, &modifiers);
173}
174
175void ToonRenderer::render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties) {
176
177 // Cel shading:
178 // - Restriction of the number of lighting intensity levels
179 // - in shader: l dot n is quantized based on the number of allowed shading tones.
180 // currently a constant sized step function is used to quantize the intensity
181
182 // collect renderobjects + prepare OpenGL state
184
185 // init/update fbos
186 ViewerResources* viewRes = &viewerRes_[_properties.viewerId()];
187 viewRes->resize(_glState->viewport_width(), _glState->viewport_height());
188
189 // --------------------------------------------------
190 // 1st pass: draw scene to intermediate fbo
191
192 // enable color/depth write access
193 glDepthMask(1);
194 glColorMask(1,1,1,1);
195
196 // bind fbo for scene + depth tex
197 viewRes->scene_->bind();
198
199 glViewport(0, 0, _glState->viewport_width(), _glState->viewport_height());
200
201 // clear depth texture
202 glDrawBuffer(GL_COLOR_ATTACHMENT1);
203 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
204 glClear(GL_COLOR_BUFFER_BIT);
205
206 // clear scene color
207 glDrawBuffer(GL_COLOR_ATTACHMENT0);
208 ACG::Vec4f clearColor = _properties.backgroundColor();
209 glClearColor(clearColor[0], clearColor[1], clearColor[2], 1.0f);
210 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
211
212 // attachment0: scene colors
213 // attachment1: scene depth
214 GLenum colorDepthTarget[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
215 glDrawBuffers(2, colorDepthTarget);
216
217 // render every object
218 for (int i = 0; i < getNumRenderObjects(); ++i) {
219
220 // Take original shader and modify the output to take only the normal as the color
221 GLSL::Program* prog = ACG::ShaderCache::getInstance()->getProgram(&sortedObjects_[i]->shaderDesc, CelShadingModifier::instance);
222
223 int bRelink = 0;
224 if (prog->getFragDataLocation("outFragment") != 0) {
225 prog->bindFragDataLocation(0, "outFragment");
226 bRelink++;
227 }
228 if (prog->getFragDataLocation("outDepth") != 1) {
229 prog->bindFragDataLocation(1, "outDepth");
230 bRelink++;
231 }
232 if (bRelink)
233 prog->link();
234
235 prog->use();
236 prog->setUniform("g_celPaletteSize", paletteSize_);
237
239 }
240
241 viewRes->scene_->unbind();
242
243 // ----------------------------------------------------------
244 // 2nd pass: compose final image with outlining as scene color * edge factor
245
246 if (!progOutline_)
247 progOutline_ = GLSL::loadProgram(OUTLINE_VERTEXSHADER_FILE, OUTLINE_FRAGMENTSHADER_FILE);
248
249 // restore previous fbo
251
252
253 // enable color/depth write access
254 glDepthMask(1);
255 glColorMask(1,1,1,1);
256
257 // note: using glDisable(GL_DEPTH_TEST) not only disables depth testing,
258 // but actually discards any write operations to the depth buffer.
259 // However, we can provide scene depth for further post-processing.
260 // -> Enable depth testing with func=always
261 glEnable(GL_DEPTH_TEST);
262 glDepthFunc(GL_ALWAYS);
263 glDisable(GL_BLEND);
264
265 // setup composition shader
266 progOutline_->use();
267 progOutline_->setUniform("samplerScene", 0);
268 progOutline_->setUniform("samplerDepth", 1);
269 progOutline_->setUniform("texcoordOffset", ACG::Vec2f(1.0f / float(viewRes->scene_->width()), 1.0f / float(viewRes->scene_->height()) ));
270 progOutline_->setUniform("clipPlanes", ACG::Vec2f(_glState->near_plane(), _glState->far_plane()));
271 progOutline_->setUniform("outlineColor", outlineCol_);
272
273 glActiveTexture(GL_TEXTURE1);
274 glBindTexture(GL_TEXTURE_2D, viewRes->scene_->getAttachment(GL_COLOR_ATTACHMENT1));
275
276 glActiveTexture(GL_TEXTURE0);
277 glBindTexture(GL_TEXTURE_2D, viewRes->scene_->getAttachment(GL_COLOR_ATTACHMENT0));
278
279
281
283
284 // reset depth func to opengl default
285 glDepthFunc(GL_LESS);
286
288
289 // restore common opengl state
290 // log window remains hidden otherwise
292}
293
294
296{
297 QAction * action = new QAction("Toon Renderer Options" , this );
298
299 connect(action,SIGNAL(triggered( bool )),this,SLOT(actionDialog( bool )));
300
301 return action;
302}
303
304void ToonRenderer::paletteSizeChanged( int _val ) {
305 paletteSize_ = float(_val) / 100.0f;
306}
307
308void ToonRenderer::outlineColorChanged( QColor _col ) {
309 outlineCol_[0] = _col.redF();
310 outlineCol_[1] = _col.greenF();
311 outlineCol_[2] = _col.blueF();
312}
313
314void ToonRenderer::ViewerResources::resize( int _newWidth, int _newHeight ) {
315 if (!_newHeight || !_newWidth) return;
316
317
318 if (!scene_) {
319 // scene fbo with 2 color attachments + depth buffer
320 // attachment0: scene color
321 // attachment1: scene depth
322 scene_ = new ACG::FBO();
323 scene_->init();
324 scene_->attachTexture2D(GL_COLOR_ATTACHMENT0, _newWidth, _newHeight, GL_RGBA, GL_RGBA);
325 scene_->attachTexture2D(GL_COLOR_ATTACHMENT1, _newWidth, _newHeight, GL_R32F, GL_RED);
326 scene_->attachTexture2DDepth(_newWidth, _newHeight);
327 }
328
329 if (scene_->height() == _newHeight &&
330 scene_->width() == _newWidth)
331 return;
332
333 scene_->resize(_newWidth, _newHeight);
334}
335
336
337
338
Definition: FBO.hh:72
void resize(GLsizei _width, GLsizei _height, bool _forceResize=false)
resize function (if textures created by this class)
Definition: FBO.cc:550
GLsizei width() const
get width of fbo texture
Definition: FBO.hh:149
GLsizei height() const
get height of fbo texture
Definition: FBO.hh:152
void attachTexture2D(GLenum _attachment, GLsizei _width, GLsizei _height, GLuint _internalFmt, GLenum _format, GLint _wrapMode=GL_CLAMP_TO_EDGE, GLint _minFilter=GL_NEAREST, GLint _magFilter=GL_NEAREST)
function to attach a texture to fbo
Definition: FBO.cc:207
void init()
function to generate the framebuffer object
Definition: FBO.cc:86
void attachTexture2DDepth(GLsizei _width, GLsizei _height, GLuint _internalFmt=GL_DEPTH_COMPONENT32, GLenum _format=GL_DEPTH_COMPONENT)
function to attach a depth-buffer texture to fbo (using GL_DEPTH_ATTACHMENT)
Definition: FBO.cc:334
double far_plane() const
get far clipping distance
Definition: GLState.hh:861
int viewport_width() const
get viewport width
Definition: GLState.hh:847
int viewport_height() const
get viewport height
Definition: GLState.hh:849
double near_plane() const
get near clipping distance
Definition: GLState.hh:858
std::vector< ACG::RenderObject * > sortedObjects_
sorted list of renderobjects without overlay objects (sorted in rendering order)
Definition: IRenderer.hh:517
int getNumRenderObjects() const
Get the number of collected render objects (not including overlay objects or gl4.2 line objects)
Definition: IRenderer.cc:1201
virtual void renderObject(ACG::RenderObject *_obj, GLSL::Program *_prog=0, bool _constRenderStates=false, const std::vector< unsigned int > *_shaderModifiers=0)
Render one renderobject.
Definition: IRenderer.cc:1129
virtual void finishRenderingPipeline(bool _drawOverlay=true)
Draw overlay objects and reset OpenGL state.
Definition: IRenderer.cc:667
virtual void prepareRenderingPipeline(ACG::GLState *_glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode *_scenegraphRoot)
Prepares renderer and OpenGL for any draw-related calls including.
Definition: IRenderer.cc:532
virtual QString dumpCurrentRenderObjectsToString(ACG::RenderObject **_list=0, bool _outputShaders=false, std::vector< ACG::ShaderModifier * > *_modifiers=0)
Outputs the current render objects to the string.
Definition: IRenderer.cc:1272
virtual void restoreInputFbo()
Restore the previously saved input Fbo configuration (fbo id + viewport)
Definition: IRenderer.cc:783
static void draw(GLSL::Program *_prog=0)
Draw the screen quad.
Definition: ScreenQuad.cc:138
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
Definition: ShaderCache.cc:84
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
Definition: ShaderCache.cc:102
void addOutput(const QString &_output)
Add one GLSL output specifier.
void addUniform(QString _uniform, QString _comment="")
Add one GLSL uniform specifier.
void addIncludeFile(QString _fileName)
Imports another shader, same as #include.
static QString getShaderDir()
static unsigned int registerModifier(ShaderModifier *_modifier)
Shader modifiers have to be registered before they can be used. They also must remain allocated for t...
void modifyLightingCode(QStringList *_code, int _lightId, ACG::ShaderGenLightType _lightType)
Modify the default lighting code of the shader generator.
Definition: ToonRenderer.cc:94
bool replaceDefaultLightingCode()
Specify whether this modifier replaces or extends the default lighting code.
Definition: ToonRenderer.cc:92
void modifyFragmentEndCode(QStringList *_code)
Append code the the fragment shader.
Definition: ToonRenderer.cc:87
void modifyFragmentIO(ACG::ShaderGenerator *_shader)
Add your own inputs/outputs to the fragment shader.
Definition: ToonRenderer.cc:70
void modifyVertexIO(ACG::ShaderGenerator *_shader)
Add your own inputs/outputs to the vertex shader.
Definition: ToonRenderer.cc:61
GLSL program class.
Definition: GLSLShader.hh:211
int getFragDataLocation(const char *_name)
Get location of the fragment data output.
Definition: GLSLShader.cc:724
void disable()
Resets to standard rendering pipeline.
Definition: GLSLShader.cc:355
void link()
Links the shader objects to the program.
Definition: GLSLShader.cc:326
void use()
Enables the program object for using.
Definition: GLSLShader.cc:345
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
Definition: GLSLShader.cc:385
void bindFragDataLocation(unsigned int _index, const char *_name)
Bind fragment output data to name.
Definition: GLSLShader.cc:692
QString renderObjectsInfo(bool _outputShaderInfo)
Return a qstring of the current render objects.
QAction * optionsAction()
Return options menu.
GLSL::Program * progOutline_
outline shader: multiply scene color with edge factor derived from edges in depth buffer
Definition: ToonRenderer.hh:98
std::map< int, ViewerResources > viewerRes_
float paletteSize_
size of cel shading palette
ACG::Vec3f outlineCol_
outline color
int viewerId()
Get the id of the viewer this viewerproperties belongs to.
ACG::Vec4f backgroundColor()
Get current background color.
void drawMode(ACG::SceneGraph::DrawModes::DrawMode _mode)
set draw mode (No test if this mode is available!)
bool checkExtensionSupported(const std::string &_extension)
Definition: gl.cc:107
bool openGLVersion(const int _major, const int _minor, bool _verbose)
Definition: gl.cc:129
void glCheckErrors()
Definition: GLError.hh:96
GLSL::PtrProgram loadProgram(const char *vertexShaderFile, const char *tessControlShaderFile, const char *tessEvaluationShaderFile, const char *geometryShaderFile, const char *fragmentShaderFile, const GLSL::StringList *macros, bool verbose)
Definition: GLSLShader.cc:1076
ACG::SceneGraph::BaseNode * getSceneGraphRootNode()
get scenegraph root node