Developer Documentation
Loading...
Searching...
No Matches
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
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)
virtual void renderObject(ACG::RenderObject *_obj, GLSL::Program *_prog=0, bool _constRenderStates=false, const std::vector< unsigned int > *_shaderModifiers=0)
Render one renderobject.
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.
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.
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
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 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.
bool replaceDefaultLightingCode()
Specify whether this modifier replaces or extends the default lighting code.
void modifyFragmentEndCode(QStringList *_code)
Append code the the fragment shader.
void modifyFragmentIO(ACG::ShaderGenerator *_shader)
Add your own inputs/outputs to the fragment shader.
void modifyVertexIO(ACG::ShaderGenerator *_shader)
Add your own inputs/outputs to the vertex shader.
GLSL program class.
int getFragDataLocation(const char *_name)
Get location of the fragment data output.
void disable()
Resets to standard rendering pipeline.
void link()
Links the shader objects to the program.
void use()
Enables the program object for using.
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
void bindFragDataLocation(unsigned int _index, const char *_name)
Bind fragment output data to name.
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
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)
ACG::SceneGraph::BaseNode * getSceneGraphRootNode()
get scenegraph root node