Developer Documentation
Loading...
Searching...
No Matches
ClassicDepthPeeling.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
44#include "ClassicDepthPeeling.hh"
46#include <ObjectTypes/Light/LightNode.hh>
47
48#include <ACG/GL/GLError.hh>
49
50
51// this define enables a shader export of the generated peel shader for debugging purpose
52//#define DEPTHPEELING_SHADER_EXPORT
53
54
55DepthPeelingPlugin::DepthPeelingPlugin() :
56 blendQueryID_(0),
57 glStateTmp_(0),
58 numLights_(0)
59{
60
61 for (unsigned int i = 0; i < 16; ++i)
62 lightTypes_[i] = LIGHTTYPE_POINT;
63
64 for (unsigned int i = 0; i < PEEL_NUM_COMBINATIONS; ++i)
65 peelProgs_[i] = 0;
66
67 for (unsigned int i = 0; i < PEEL_NUM_COMBINATIONS*3; ++i)
68 peelShaders_[i] = 0;
69
70 for (unsigned int i = 0; i < 8; ++i)
71 blendShaders_[i] = 0;
72
73 for (unsigned int i = 0; i < 4; ++i)
74 blendDualPeelProg_[i] = 0;
75
76 for (unsigned int i = 0; i < 16; ++i)
77 glLightIDs_[i] = 0;
78
79
80}
81
82DepthPeelingPlugin::~DepthPeelingPlugin() {
83
84}
85
86
87DepthPeelingPlugin::ViewerResources::ViewerResources()
88{
89 rtWidth_ = rtHeight_ = 0;
90
91 glWidth_ = glHeight_ = 0;
92
93 memset(blendDualPeelTexID_, 0, 7*4);
94
96}
97
98void DepthPeelingPlugin::initializePlugin()
99{
100 memset(blendShaders_, 0, sizeof(blendShaders_));
101 memset(peelShaders_, 0, sizeof(peelShaders_));
102
103 memset(blendDualPeelProg_, 0, sizeof(blendDualPeelProg_));
104 memset(peelProgs_, 0, sizeof(peelProgs_));
105
106 blendQueryID_ = 0;
107 numLights_ = 0;
108
110}
111
113
114void DepthPeelingPlugin::exit()
115{
117}
118
120
121QString DepthPeelingPlugin::rendererName() {
122 return QString("Classical Depth Peeling Renderer");
123}
124
126
127void DepthPeelingPlugin::supportedDrawModes(ACG::SceneGraph::DrawModes::DrawMode& _mode) {
129}
130
132
133
134void DepthPeelingPlugin::drawQuadProj(float x0, float y0, float w, float h)
135{
136 // quad in projection space
137 // here only position are passed to GL
138 // tex-coords can be generated in a vertex-shader as follows
139 // uv = pos * (.5, -.5) + (.5, .5)
140
141 glBegin(GL_QUADS);
142 {
143 glVertex2f(x0, y0);
144 glVertex2f(x0, y0-h);
145 glVertex2f(x0+w, y0-h);
146 glVertex2f(x0+w, y0);
147 }
148 glEnd();
149}
150
152
154{
155
156 if (_node)
157 {
158 BaseNode::StatusMode status(_node->status());
159
160 // If the subtree is hidden, ignore this node and its children while rendering
161 if (status != BaseNode::HideSubtree)
162 {
163
164 if (_node->status() != BaseNode::HideNode)
165 {
166 ACG::SceneGraph::LightNode* lnode = dynamic_cast<ACG::SceneGraph::LightNode*>(_node);
167 if (lnode)
168 {
170 lnode->getLightSource(&light);
171
172// GLenum lightID = lnode->getGLLightID();
173 GLenum lightID = numLights_ + GL_LIGHT0;
174
175 if (lightID != GL_INVALID_ENUM)
176 {
177 int id = lightID - GL_LIGHT0;
178
179 if (numLights_ < 8)
180 {
181 if (light.directional())
182 lightTypes_[numLights_] = LIGHTTYPE_DIRECTIONAL;
183 else if (light.spotCutoff() > 179.5f)
184 lightTypes_[numLights_] = LIGHTTYPE_POINT;
185 else
186 lightTypes_[numLights_] = LIGHTTYPE_SPOT;
187
189
190 ++numLights_;
191 }
192
193 }
194
195 }
196 }
197
198 // Process children?
199 if (status != BaseNode::HideChildren)
200 {
201
202 BaseNode::ChildIter cIt, cEnd(_node->childrenEnd());
203
204 // Process all children which are not second pass
205 for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
206 if (~(*cIt)->traverseMode() & BaseNode::SecondPass)
207 traverseLightNodes(*cIt);
208
209 // Process all children which are second pass
210 for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
211 if ((*cIt)->traverseMode() & BaseNode::SecondPass)
212 traverseLightNodes(*cIt);
213
214 }
215
216 }
217 }
218}
219
220// depth peeling shader generation
221
222void DepthPeelingPlugin::generatePeelingShaders(GLSL::StringList* _strVertexShaderOut,
223 GLSL::StringList* _strFragmentShaderOut,
224 GLSL::StringList* _strGeometryShaderOut,
225 bool _textured,
226 bool _flatShaded,
227 bool _phong,
228 bool _vertexColor,
229 bool _wireFrame)
230{
231 if (_flatShaded) _phong = false;
232 if (_vertexColor) _phong = false;
233
234 std::string strColor = "color";
235 std::string strNormal = "normal";
236 std::string strFragPos = "vPosVS";
237
238 if (_flatShaded)
239 strFragPos = "VPosVS";
240
241 if (_wireFrame)
242 _flatShaded = _vertexColor = _textured = _phong = false;
243
244 std::string strCode = "";
245
246 for (unsigned int i = 0; i < numLights_ && (!_wireFrame); ++i)
247 {
248 // new code block for this light
249 strCode += "{\n";
250
251 std::string strLight = "gl_LightSource[" + std::to_string(glLightIDs_[i]) + "]";
252 std::string strMaterial = "gl_FrontLightProduct[" + std::to_string(glLightIDs_[i]) + "]";
253
254 // light vector
255 if (lightTypes_[i] == LIGHTTYPE_DIRECTIONAL)
256 strCode += "vec3 vLightVS = " + strLight + ".position.xyz;\n";
257 else
258 strCode += "vec3 vLightVS = " + strLight + ".position.xyz - " + strFragPos + ".xyz;\n";
259
260 strCode += "vec3 vLightDir = normalize(vLightVS);\n";
261
262 // ambient
263 strCode += "vec4 colLight = " + strMaterial + ".ambient;\n";
264
265 // diffuse
266 strCode += "float ldotn = dot(vLightDir, " + strNormal + ");\n";
267 strCode += "ldotn = clamp(ldotn, 0.0, 1.0);\n";
268 strCode += "colLight += ldotn * ";
269 if (_textured && _phong)
270 strCode += "diffColor * ";
271
272 if (_vertexColor)
273 {
274 if (_flatShaded)
275 strCode += "vColor[2];\n";
276 else
277 strCode += "gl_Color;\n";
278 }
279 else
280 strCode += strMaterial + ".diffuse;\n";
281
282 //specular
283 strCode += "colLight += floor(ldotn + 0.9) * pow(ldotn, gl_FrontMaterial.shininess) * " + strMaterial + ".specular;\n";
284
285
286 if (lightTypes_[i] == LIGHTTYPE_DIRECTIONAL)
287 strCode += strColor + ".rgb += colLight.rgb;\n";
288 else
289 {
290 // attenuation
291 strCode += "float fLenSq = dot(vLightVS, vLightVS);\n";
292 strCode += "float atten = " + strLight + ".constantAttenuation + " +
293 strLight + ".linearAttenuation * sqrt(fLenSq) + " +
294 strLight + ".quadraticAttenuation * fLenSq;\n";
295
296 if (lightTypes_[i] == LIGHTTYPE_POINT)
297 strCode += strColor + ".rgb += colLight.rgb / atten;\n";
298 else
299 {
300 // spotlight
301 strCode += "float spot = -dot(vLightDir, " + strLight + ".spotDirection);\n";
302 strCode += "spot *= step(" + strLight + ".spotCosCutoff, spot);\n";
303 strCode += "spot *= pow(spot, " + strLight + ".spotExponent);\n";
304
305 strCode += strColor + ".rgb += " + "(spot / atten) * colLight.rgb;\n";
306 }
307 }
308
309 strCode += "}\n";
310 }
311
312 const char* szVertexShader[] = {"varying vec2 vTexCoord;",
313 "varying vec3 vNormal; // normal: view space",
314 "varying vec4 vPosVS; // position in view space",
315 "varying vec4 vColor; // used in gouraud / flat shading only",
316 "",
317 "void main(void)",
318 "{",
319 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;",
320 " ",
321 " vNormal = gl_NormalMatrix * gl_Normal; // gl_NormalMatrix : upper left 3x3 of WorldViewIT",
322 " vPosVS = (gl_ModelViewMatrix * gl_Vertex);",
323 " vTexCoord = gl_MultiTexCoord0.xy;",
324 ""};
325 // NOTE: this vertex shader code misses the ending '}' to append the lighting code later
326
327 // geometry shader for flat shading only
328 const char* szGeometryShaderStart[] = {
329 "#version 120",
330 "#extension GL_ARB_geometry_shader4 : enable",
331 "",
332 "varying vec2 vTexCoord[3];",
333 "varying vec4 vPosVS[3];",
334 "varying vec3 vNormal[3];",
335 "varying vec4 vColor[3];",
336 "",
337 "varying vec2 VTexCoord;",
338 "varying vec3 VNormal;",
339 "varying vec4 VPosVS;",
340 "varying vec4 VColor;",
341 "",
342 "",
343 "void main()",
344 "{",
345 " // recompute triangle normal",
346// " vec3 normal = cross(vNormal[2].xyz - vNormal[0].xyz, vNormal[1].xyz - vNormal[0].xyz);",
347 " vec3 normal = cross(gl_PositionIn[1].xyz - gl_PositionIn[0].xyz, gl_PositionIn[2].xyz - gl_PositionIn[0].xyz);",
348 " normal = normalize(normal);",
349 " normal = gl_NormalMatrix * normal;",
350// " normal = vNormal[2].xyz;",
351 " ",
352 " VPosVS = (gl_PositionIn[0] + gl_PositionIn[1] + gl_PositionIn[2]) / 3.0;",
353 " VPosVS = gl_ModelViewMatrix * VPosVS; // triangle center in view space needed for point and spot lights",
354 " vec4 color = vec4(gl_FrontMaterial.emission.rgb, gl_FrontMaterial.diffuse.a);",
355 ""};
356
357 const char* szGeometryShaderEnd[] = {
358 "",
359 " for(int i = 0; i < 3; i++)",
360 " {",
361 " gl_Position = gl_ModelViewProjectionMatrix * gl_PositionIn[i];",
362 " VTexCoord = vTexCoord[i];",
363 " VNormal = normal;",
364 " VPosVS = vPosVS[i];",
365// " VColor = (normal+vec3(0.5,0.5,0.5)).xyzz*0.5;",
366 " VColor = color;",
367 " EmitVertex();",
368 " }",
369 " EndPrimitive();",
370 " ",
371 "}"};
372
373 const char* szFragmentShaderStart[] = {"varying vec2 vTexCoord;",
374 "varying vec3 vNormal; ",
375 "varying vec4 vPosVS;",
376 "varying vec4 vColor;",
377 "",
378 "uniform sampler2D DiffuseTex;",
379 "uniform sampler2DRect DepthBlenderTex;",
380 "uniform sampler2DRect FrontBlenderTex;",
381 "",
382 "#define MAX_DEPTH 1.0",
383 "",
384 "",
385 "void main(void)",
386 "{",
387 " // window-space depth interpolated linearly in screen space",
388 " float fragDepth = gl_FragCoord.z;",
389 "",
390 " vec2 depthBlender = texture2DRect(DepthBlenderTex, gl_FragCoord.xy).xy;",
391 " vec4 forwardTemp = texture2DRect(FrontBlenderTex, gl_FragCoord.xy);",
392 " ",
393 " // Depths and 1.0-alphaMult always increase",
394 " // so we can use pass-through by default with MAX blending",
395 " gl_FragData[0].xy = depthBlender;",
396 " ",
397 " // Front colors always increase (DST += SRC*ALPHA_MULT)",
398 " // so we can use pass-through by default with MAX blending",
399 " gl_FragData[1] = forwardTemp;",
400 " ",
401 " // Because over blending makes color increase or decrease,",
402 " // we cannot pass-through by default.",
403 " // Each pass, only one fragment writes a color greater than 0",
404 " gl_FragData[2] = vec4(0.0);",
405 "",
406 " float nearestDepth = -depthBlender.x;",
407 " float farthestDepth = depthBlender.y;",
408 " float alphaMultiplier = 1.0 - forwardTemp.w;",
409 "",
410 " if (fragDepth < nearestDepth || fragDepth > farthestDepth) {",
411 " // Skip this depth in the peeling algorithm",
412 " gl_FragData[0].xy = vec2(-MAX_DEPTH);",
413 " return;",
414 " }",
415 " ",
416 " if (fragDepth > nearestDepth && fragDepth < farthestDepth) {",
417 " // This fragment needs to be peeled again",
418 " gl_FragData[0].xy = vec2(-fragDepth, fragDepth);",
419 " return;",
420 " }",
421 " ",
422 " // If we made it here, this fragment is on the peeled layer from last pass",
423 " // therefore, we need to shade it, and make sure it is not peeled any farther",
424 "",};
425
426 const char* szFragmentShaderEnd[] = {"",
427 " gl_FragData[0].xy = vec2(-MAX_DEPTH);",
428 " ",
429 " if (fragDepth == nearestDepth) {",
430 " gl_FragData[1].xyz += color.rgb * color.a * alphaMultiplier;",
431 " gl_FragData[1].w = 1.0 - alphaMultiplier * (1.0 - color.a);",
432 " } else {",
433 " gl_FragData[2] += color;",
434 " }",
435 "}"};
436
437 // assemble final shaders:
438
439 // vertex shader
440 for (unsigned int i = 0; i < sizeof(szVertexShader) / sizeof(char*); ++i)
441 {
442 std::string str = szVertexShader[i];
443 if (_phong)
444 {
445 if (!strncmp("varying vec4 vColor", str.c_str(), strlen("varying vec4 vColor")))
446 {
447// str.replace(str.begin(), str.begin() + 7, "flat out");
448 str += "\n";
449 continue;
450 }
451 }
452 str += "\n";
453 _strVertexShaderOut->push_back(str);
454 }
455
456 // finalize vertex shader
457 if (!_phong && !_flatShaded && !_wireFrame)
458 {
459 // lighting code:
460 _strVertexShaderOut->push_back("\nvec4 color = vec4(gl_FrontMaterial.emission.rgb, gl_FrontMaterial.diffuse.a);");
461 _strVertexShaderOut->push_back("\nvec3 normal = vNormal;\n");
462
463 std::string::size_type curPos = 0;
464 std::string::size_type newLinePos = strCode.find_first_of('\n');
465 while (newLinePos != std::string::npos)
466 {
467 _strVertexShaderOut->push_back(strCode.substr(curPos, newLinePos - curPos + 1));
468 curPos = newLinePos + 1;
469 newLinePos = strCode.find_first_of('\n', curPos);
470 }
471 _strVertexShaderOut->push_back("\nvColor = color;\n");
472 }
473 if (_flatShaded)
474 {
475 if (_vertexColor)
476 _strVertexShaderOut->push_back("vColor = gl_Color;\n");
477 _strVertexShaderOut->push_back("gl_Position = gl_Vertex;\n");
478 }
479
480 _strVertexShaderOut->push_back("\n}");
481
482 // fragment shader:
483 for (unsigned int i = 0; i < sizeof(szFragmentShaderStart) / sizeof(char*); ++i)
484 {
485 std::string str = szFragmentShaderStart[i];
486 if (_phong)
487 {
488 if (!strncmp("varying vec4 vColor", str.c_str(), strlen("varying vec4 vColor")))
489 {
490// str.replace(str.begin(), str.begin() + 7, "flat in");
491 str += "\n";
492 continue;
493 }
494 }
495 if (_flatShaded)
496 {
497 if (!strncmp("varying vec2 vTexCoord", str.c_str(), strlen("varying vec2 vTexCoord")))
498 str = "varying vec2 VTexCoord;";
499 if (!strncmp("varying vec3 vNormal", str.c_str(), strlen("varying vec3 vNormal")))
500 str = "varying vec3 VNormal;";
501 if (!strncmp("varying vec4 vPosVS", str.c_str(), strlen("varying vec4 vPosVS")))
502 str = "varying vec4 VPosVS;";
503 if (!strncmp("varying vec4 vColor", str.c_str(), strlen("varying vec4 vColor")))
504 str = "varying vec4 VColor;";
505 }
506 str += "\n";
507 _strFragmentShaderOut->push_back(str);
508 }
509
510 if (!_wireFrame)
511 {
512 if (!_flatShaded)
513 {
514 _strFragmentShaderOut->push_back(" vec3 normal = normalize(vNormal);\n");
515// _strFragmentShaderOut->push_back(" vec3 normal = normalize(cross(dFdx(vPosVS.xyz), dFdy(vPosVS.xyz)));\n");
516 _strFragmentShaderOut->push_back(" vec4 color = vec4(gl_FrontMaterial.emission.rgb, gl_FrontMaterial.diffuse.a);\n");
517 if (_textured)
518 _strFragmentShaderOut->push_back(" vec4 diffColor = texture2D(DiffuseTex, vTexCoord); color.a *= diffColor.a;\n");
519 }
520 else
521 {
522 _strFragmentShaderOut->push_back(" vec4 color = vec4(gl_FrontMaterial.emission.rgb, gl_FrontMaterial.diffuse.a);\n");
523 _strFragmentShaderOut->push_back(" vec4 vColor = VColor;\n");
524 if (_textured)
525 _strFragmentShaderOut->push_back(" vec4 diffColor = texture2D(DiffuseTex, VTexCoord); color.a *= diffColor.a;\n");
526 }
527
528 if (!_phong)
529 {
530 if (_textured)
531 _strFragmentShaderOut->push_back(" color = diffColor * vColor;\n");
532 else
533 _strFragmentShaderOut->push_back(" color = vColor;\n");
534 }
535 else
536 {
537 // lighting code:
538 std::string::size_type curPos = 0;
539 std::string::size_type newLinePos = strCode.find_first_of('\n');
540 while (newLinePos != std::string::npos)
541 {
542 _strFragmentShaderOut->push_back(strCode.substr(curPos, newLinePos - curPos + 1));
543 curPos = newLinePos + 1;
544 newLinePos = strCode.find_first_of('\n', curPos);
545 }
546 }
547 }
548 else // wireframe:
549 _strFragmentShaderOut->push_back(" vec4 color = vColor;\n");
550
551 for (unsigned int i = 0; i < sizeof(szFragmentShaderEnd) / sizeof(char*); ++i)
552 {
553 std::string str = szFragmentShaderEnd[i];
554 str += "\n";
555 _strFragmentShaderOut->push_back(str);
556 }
557
558
559 // geometry shader:
560 if (_flatShaded)
561 {
562 for (unsigned int i = 0; i < sizeof(szGeometryShaderStart) / sizeof(char*); ++i)
563 {
564 std::string str = szGeometryShaderStart[i];
565 str += "\n";
566 _strGeometryShaderOut->push_back(str);
567 }
568
569 // lighting code:
570 std::string::size_type curPos = 0;
571 std::string::size_type newLinePos = strCode.find_first_of('\n');
572 while (newLinePos != std::string::npos)
573 {
574 _strGeometryShaderOut->push_back(strCode.substr(curPos, newLinePos - curPos + 1));
575 curPos = newLinePos + 1;
576 newLinePos = strCode.find_first_of('\n', curPos);
577 }
578
579 for (unsigned int i = 0; i < sizeof(szGeometryShaderEnd) / sizeof(char*); ++i)
580 {
581 std::string str = szGeometryShaderEnd[i];
582 str += "\n";
583 _strGeometryShaderOut->push_back(str);
584 }
585 }
586
587
588 // debug output:
589#ifdef DEPTHPEELING_SHADER_EXPORT
590 FILE* pShaderOut = fopen("peel_vertex.glsl", "wt");
591 for (GLSL::StringList::iterator it = _strVertexShaderOut->begin(); it != _strVertexShaderOut->end(); ++it)
592 fprintf(pShaderOut, it->c_str());
593 fclose(pShaderOut);
594
595
596 pShaderOut = fopen("peel_frag.glsl", "wt");
597 for (GLSL::StringList::iterator it = _strFragmentShaderOut->begin(); it != _strFragmentShaderOut->end(); ++it)
598 fprintf(pShaderOut, it->c_str());
599 fclose(pShaderOut);
600
601 if (_flatShaded)
602 {
603 pShaderOut = fopen("peel_geom.glsl", "wt");
604 for (GLSL::StringList::iterator it = _strGeometryShaderOut->begin(); it != _strGeometryShaderOut->end(); ++it)
605 fprintf(pShaderOut, it->c_str());
606 fclose(pShaderOut);
607 }
608#endif
609}
610
612
613template <class Action>
614bool
615DepthPeelingPlugin::traverseDrawApplyAction( BaseNode* _node, Action& _action, ACG::SceneGraph::DrawModes::DrawMode _globalDrawMode, int _pass, int _peelPass)
616{
617 bool ret = true; // process_children flag returned
618
619 // use nodes drawmode to grab a peeler program with correct shading
621 dm = dmSave;
622
623 if (!dm) return ret;
624
626 dm = _globalDrawMode;
627/*
628 if (dm & ACG::SceneGraph::DrawModes::HIDDENLINE)
629 {
630 // hiddenline is accomplished with wireframe in first peel layer only
631 dm &= ~ACG::SceneGraph::DrawModes::HIDDENLINE;
632 dm |= ACG::SceneGraph::DrawModes::WIREFRAME;
633 if (_peelPass > 2)
634 return ret;
635 _node->drawMode(dm);
636 }
637*/
639 {
641 dmShaded &= ~ACG::SceneGraph::DrawModes::WIREFRAME;
642 dmShaded &= ~ACG::SceneGraph::DrawModes::HIDDENLINE;
643
644 // polygon only draw
645 if (dmShaded)
646 {
647 _node->drawMode(dmShaded); // evil method: change nodes drawmode here, restore it later
648 ret &= traverseDrawApplyAction(_node, _action, _globalDrawMode, _pass, _peelPass);
649 }
650
651 // wireframe only follows
652 dm &= (~dmShaded);
653 _node->drawMode(dm);
654 }
655
656 unsigned int shaderIndex = getPeelShaderIndex(dm);
657
658 // do hiddenline algorithmus manually here
659 GLenum prev_depth = glStateTmp_->depthFunc();
661 {
662 // manual hiddenline
663
664 // First:
665 // Render all faces in background color to initialize z-buffer
667
668 GLSL::Program* peelProg = peelProgs_[PEEL_SHADER_HIDDENLINE];
669 peelProg->use();
670 peelProg->setUniform("DepthBlenderTex", 4);
671 peelProg->setUniform("FrontBlenderTex", 5);
672 peelProg->setUniform("ObjectColor", glStateTmp_->clear_color());
673
674 ACG::GLState::depthRange(0.01, 1.0);
677 ret &= _action(_node);
680 ACG::GLState::depthRange(0.0, 1.0);
681
682 // Second
683 // Render the lines. All lines not on the front will be skipped in z-test
685
686 ACG::GLState::depthFunc(GL_LEQUAL);
687 ACG::GLState::lockDepthFunc();
688
689 // use wireframe shader now
690 shaderIndex = PEEL_SHADER_WIREFRAME;
691 }
692
693 GLSL::Program* peelProg = peelProgs_[shaderIndex];
694 peelProg->use();
695 peelProg->setUniform("DepthBlenderTex", 4);
696 peelProg->setUniform("FrontBlenderTex", 5);
697
698 if (shaderIndex & PEEL_SHADER_FLAT)
699 {
700 // set geomtry shader constants
701 peelProg->setGeometryInputType(GL_TRIANGLES);
702 peelProg->setGeometryOutputType(GL_TRIANGLE_STRIP);
703 peelProg->setGeometryVertexCount(3);
704 }
705 peelProg->setUniform("DiffuseTex", 0);
706
708 ret &= _action(_node);
710
711 // restore state
712 _node->drawMode(dmSave);
713
715 {
716 ACG::GLState::unlockDepthFunc();
717
718 //restore depth buffer comparison function
719 ACG::GLState::depthFunc(prev_depth);
720 }
721
722 return ret;
723}
724
726
727template <class Action>
728void
729DepthPeelingPlugin::traverseDraw( BaseNode* _node, Action& _action, ACG::SceneGraph::DrawModes::DrawMode _globalDrawMode, int _pass, int _peelPass)
730{
731
732 // Process node if it exists
733 if (_node) {
734 BaseNode::StatusMode status(_node->status());
735
736 // If the subtree is hidden, ignore this node and its children while rendering
737 if (status != BaseNode::HideSubtree) {
738
739 bool process_children(status != BaseNode::HideChildren);
740
741 // Executes this nodes enter function (if available and active in multipass)
742 if ( _node->multipassStatusActive(_pass) ) {
743 if_has_enter(_action, _node);
744 }
745
746 // If the node itself is hidden, don't call the action on it.
747 // Additionally check if rendering order is node first. otherwise, we will call it after the children.
748 // And check if it should be called in this rendering pass.
749 if ( (_node->status() != BaseNode::HideNode ) && ( _node->traverseMode() & BaseNode::NodeFirst ) && _node->multipassNodeActive(_pass))
750 process_children &= traverseDrawApplyAction(_node, _action, _globalDrawMode, _pass, _peelPass);
751
752 if (process_children) {
753
754 BaseNode::ChildIter cIt, cEnd(_node->childrenEnd());
755
756 // Process all children
757 for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
758 if (~(*cIt)->traverseMode() & BaseNode::SecondPass)
759 traverseDraw(*cIt, _action, _globalDrawMode, _pass, _peelPass);
760
761 // Process all children which are second pass
762 for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
763 if ((*cIt)->traverseMode() & BaseNode::SecondPass)
764 traverseDraw(*cIt, _action, _globalDrawMode, _pass, _peelPass);
765
766 }
767
768
769 // If we are in childrenfirst node, the children have been painted andwe now check, if we can draw this node.
770 // If its hidden, ignore it.
771 // If it should not be rendered in this pass, ignore it too.
772 if ( (_node->traverseMode() & BaseNode::ChildrenFirst ) && (_node->status() != BaseNode::HideNode) && _node->multipassNodeActive(_pass) )
773 traverseDrawApplyAction(_node, _action, _globalDrawMode, _pass, _peelPass);
774
775 // Call the leave function of the node (if available and active in multipass).
776 if ( _node->multipassStatusActive(_pass) )
777 if_has_leave(_action, _node);
778
779 } // if (status != BaseNode::HideSubtree)
780 } // if(node_)
781}
782
783void DepthPeelingPlugin::drawScenePeelPass(ACG::GLState* _glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, BaseNode* _sceneGraphRoot, int _peelPass)
784{
785 ACG::SceneGraph::DrawAction action(_drawMode, *_glState, false);
786// traverseDraw(_sceneGraphRoot, action, *_glState, _drawMode);
787
788 // Reset render pass counter
789 _glState->reset_render_pass();
790
791 // Get max render passes
792 unsigned int max_passes = _glState->max_render_passes();
793
794 // Render all passes
795 for(unsigned int pass = BaseNode::PASS_1; pass <= (BaseNode::PASS_1 + max_passes); ++pass) {
796
797 // Traverse scenegraph
798 traverseDraw (_sceneGraphRoot, action, _drawMode, pass, _peelPass);
799 // Increment render pass counter by 1
800 _glState->next_render_pass();
801 }
802
803 // Reset render pass counter
804 _glState->reset_render_pass();
805}
806
808
810{
811 ACG::SceneGraph::DrawAction action(_drawMode, *_glState, false);
812 traverse_multipass(_sceneGraphRoot, action, *_glState, _drawMode);
813}
814
816
818{
819 bool rebuildShaders = false;
820
822
823 // peel shader is rebuilt, if a new light is added or a light type changed
824
825 LightType prevLights[8];
826 unsigned int prevIDs[8];
827 unsigned int prevNum = numLights_;
828
829 memcpy(prevLights, lightTypes_, sizeof(LightType) * numLights_);
830 memcpy(prevIDs, glLightIDs_, sizeof(unsigned int) * numLights_);
831
832 numLights_ = 0;
833 traverseLightNodes(sceneGraphRoot);
834
835 // test for necessary shader recompilation
836 if (numLights_ == prevNum)
837 {
838 // look for any light node changes
839 if (memcmp(prevLights, lightTypes_, sizeof(LightType) * numLights_) ||
840 memcmp(prevIDs, glLightIDs_, sizeof(unsigned int) * numLights_))
841 rebuildShaders = true;
842 }
843 else rebuildShaders = true;
844
845 if (rebuildShaders)
846 {
847 // delete old shaders and programs
848 for (unsigned int i = 0; i < sizeof(peelShaders_) / sizeof(peelShaders_[0]); ++i)
849 {
850 delete peelShaders_[i]; peelShaders_[i] = 0;
851 }
852
853 for (unsigned int i = 0; i < sizeof(peelProgs_) / sizeof(peelProgs_[0]); ++i)
854 {
855 delete peelProgs_[i]; peelProgs_[i] = 0;
856 }
857
858 for (unsigned int i = 0; i < PEEL_NUM_COMBINATIONS; ++i)
859 {
860 GLuint texturedDrawMode = 0, flatDrawMode = 0, phongDrawMode = 0, vertexColorDrawMode = 0, gouraudDrawMode = 0;
861
862 texturedDrawMode = i & PEEL_SHADER_TEXTURED;
863 flatDrawMode = i & PEEL_SHADER_FLAT;
864 phongDrawMode = i & PEEL_SHADER_PHONG;
865 vertexColorDrawMode = i & PEEL_SHADER_VERTEXCOLORS;
866 gouraudDrawMode = i & PEEL_SHADER_GOURAUD;
867
868 if (i != PEEL_SHADER_WIREFRAME)
869 {
870 // filter nonsense
871 if (flatDrawMode && phongDrawMode) continue;
872 if (flatDrawMode && gouraudDrawMode) continue;
873 if (phongDrawMode && gouraudDrawMode) continue;
874
875 if (phongDrawMode + flatDrawMode + gouraudDrawMode == 0) continue;
876 }
877
878 if (flatDrawMode)
879 {
880 // replace flat shading with gouraud, if geometry shaders are not supported
881 if (!ACG::checkExtensionSupported("GL_ARB_geometry_shader4") && !ACG::checkExtensionSupported("GL_EXT_geometry_shader4"))
882 {
883 flatDrawMode = 0;
884 gouraudDrawMode = 1;
885 }
886 }
887
888 GLSL::StringList strVertexShader, strFragmentShader, strGeometryShader;
889 generatePeelingShaders(&strVertexShader, &strFragmentShader, &strGeometryShader, texturedDrawMode != 0, flatDrawMode != 0, phongDrawMode != 0, vertexColorDrawMode != 0, i == PEEL_SHADER_WIREFRAME);
890
891 peelProgs_[i] = new GLSL::Program();
892
893
894 GLSL::VertexShader* pVertexSh = new GLSL::VertexShader();
895 pVertexSh->setSource(strVertexShader);
896 pVertexSh->compile();
897 peelShaders_[i*3 + 0] = pVertexSh;
898 peelProgs_[i]->attach(pVertexSh);
899
900 if (flatDrawMode)
901 {
903 pGeomSh->setSource(strGeometryShader);
904 pGeomSh->compile();
905 peelShaders_[i*3 + 1] = pGeomSh;
906 peelProgs_[i]->attach(pGeomSh);
907 }
908
910 pFragSh->setSource(strFragmentShader);
911 pFragSh->compile();
912 peelShaders_[i*3 + 2] = pFragSh;
913 peelProgs_[i]->attach(pFragSh);
914
915 peelProgs_[i]->link();
917
918
919#ifdef DEPTHPEELING_SHADER_EXPORT
920 char szFileName[256];
921 sprintf(szFileName, "peel_vertex_%02u.glsl", i);
922 FILE* pShaderOut = fopen(szFileName, "wt");
923 for (GLSL::StringList::iterator it = strVertexShader.begin(); it != strVertexShader.end(); ++it)
924 fprintf(pShaderOut, it->c_str());
925 fclose(pShaderOut);
926
927
928 sprintf(szFileName, "peel_frag%02u.glsl", i);
929 pShaderOut = fopen(szFileName, "wt");
930 for (GLSL::StringList::iterator it = strFragmentShader.begin(); it != strFragmentShader.end(); ++it)
931 fprintf(pShaderOut, it->c_str());
932 fclose(pShaderOut);
933
934 if (flatDrawMode)
935 {
936 sprintf(szFileName, "peel_geom%02u.glsl", i);
937 pShaderOut = fopen(szFileName, "wt");
938 for (GLSL::StringList::iterator it = strGeometryShader.begin(); it != strGeometryShader.end(); ++it)
939 fprintf(pShaderOut, it->c_str());
940 fclose(pShaderOut);
941 }
942#endif
943 }
944 }
945
946
947 // create a special shader for hiddenline
948 // hiddenline = wireframe + early z cull
949 // the special shader is needed for the z buffer pass
950
951 const char* szVertexShader[] = {
952 "void main(void)",
953 "{",
954 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;",
955 "}"};
956
957 const char* szFragmentShader[] = {
958 "uniform vec4 ObjectColor;",
959 "uniform sampler2DRect DepthBlenderTex;",
960 "uniform sampler2DRect FrontBlenderTex;",
961 "",
962 "#define MAX_DEPTH 1.0",
963 "",
964 "",
965 "void main(void)",
966 "{",
967 " // window-space depth interpolated linearly in screen space",
968 " float fragDepth = gl_FragCoord.z;",
969 "",
970 " vec2 depthBlender = texture2DRect(DepthBlenderTex, gl_FragCoord.xy).xy;",
971 " vec4 forwardTemp = texture2DRect(FrontBlenderTex, gl_FragCoord.xy);",
972 " ",
973 " // Depths and 1.0-alphaMult always increase",
974 " // so we can use pass-through by default with MAX blending",
975 " gl_FragData[0].xy = depthBlender;",
976 " ",
977 " // Front colors always increase (DST += SRC*ALPHA_MULT)",
978 " // so we can use pass-through by default with MAX blending",
979 " gl_FragData[1] = forwardTemp;",
980 " ",
981 " // Because over blending makes color increase or decrease,",
982 " // we cannot pass-through by default.",
983 " // Each pass, only one fragment writes a color greater than 0",
984 " gl_FragData[2] = vec4(0.0);",
985 "",
986 " float nearestDepth = -depthBlender.x;",
987 " float farthestDepth = depthBlender.y;",
988 " float alphaMultiplier = 1.0 - forwardTemp.w;",
989 "",
990 " if (fragDepth < nearestDepth || fragDepth > farthestDepth) {",
991 " // Skip this depth in the peeling algorithm",
992 " gl_FragData[0].xy = vec2(-MAX_DEPTH);",
993 " return;",
994 " }",
995 " ",
996 " if (fragDepth > nearestDepth && fragDepth < farthestDepth) {",
997 " // This fragment needs to be peeled again",
998 " gl_FragData[0].xy = vec2(-fragDepth, fragDepth);",
999 " return;",
1000 " }",
1001 " ",
1002 " // If we made it here, this fragment is on the peeled layer from last pass",
1003 " // therefore, we need to shade it, and make sure it is not peeled any farther",
1004 " vec4 color = ObjectColor;",
1005 " gl_FragData[0].xy = vec2(-MAX_DEPTH);",
1006 " ",
1007 " if (fragDepth == nearestDepth) {",
1008 " gl_FragData[1].xyz += color.rgb * color.a * alphaMultiplier;",
1009 " gl_FragData[1].w = 1.0 - alphaMultiplier * (1.0 - color.a);",
1010 " } else {",
1011 " gl_FragData[2] += color;",
1012 " }",
1013 "}"};
1014
1015 GLSL::StringList strVertexShader, strFragmentShader;
1016 for (unsigned int i = 0; i < sizeof(szVertexShader) / sizeof(char*); ++i)
1017 {
1018 std::string str = szVertexShader[i];
1019 str += "\n";
1020 strVertexShader.push_back(str);
1021 }
1022
1023 for (unsigned int i = 0; i < sizeof(szFragmentShader) / sizeof(char*); ++i)
1024 {
1025 std::string str = szFragmentShader[i];
1026 str += "\n";
1027 strFragmentShader.push_back(str);
1028 }
1029
1030 GLSL::Program* peelHiddenLine = peelProgs_[PEEL_SHADER_HIDDENLINE] = new GLSL::Program();
1031
1032 GLSL::VertexShader* pVertexSh = new GLSL::VertexShader();
1033 pVertexSh->setSource(strVertexShader);
1034 pVertexSh->compile();
1035 peelShaders_[PEEL_SHADER_HIDDENLINE*3 + 0] = pVertexSh;
1036 peelHiddenLine->attach(pVertexSh);
1037
1039 pFragSh->setSource(strFragmentShader);
1040 pFragSh->compile();
1041 peelShaders_[PEEL_SHADER_HIDDENLINE*3 + 2] = pFragSh;
1042 peelHiddenLine->attach(pFragSh);
1043
1044 peelHiddenLine->link();
1046}
1047
1049
1051{
1052 if (_drawMode & ACG::SceneGraph::DrawModes::WIREFRAME ||
1054 return PEEL_SHADER_WIREFRAME;
1055
1057 bool flat = _drawMode & ACG::SceneGraph::DrawModes::SOLID_FLAT_SHADED;
1058 bool phong = _drawMode & ACG::SceneGraph::DrawModes::SOLID_PHONG_SHADED;
1061
1062 bool gouraud = _drawMode & ACG::SceneGraph::DrawModes::SOLID_SMOOTH_SHADED;
1063
1064 // fix illegal combinations
1065 if (phong && flat) flat = false;
1066 if (flat && gouraud) gouraud = false;
1067 if (gouraud && phong) phong = false;
1068
1069 // wireframe, point, etc use gouraud shading
1070 if ((!phong) && (!gouraud) && (!flat)) gouraud = true;
1071
1072 unsigned int idx = 0;
1073
1074 if (flat) idx |= PEEL_SHADER_FLAT;
1075 if (gouraud) idx |= PEEL_SHADER_GOURAUD;
1076 if (phong) idx |= PEEL_SHADER_PHONG;
1077 if (vertexColor) idx |= PEEL_SHADER_VERTEXCOLORS;
1078 if (textured) idx |= PEEL_SHADER_TEXTURED;
1079
1080 return idx;
1081}
1082
1083QString DepthPeelingPlugin::checkOpenGL() {
1085 return QString("Classic depth peeling Rendering-plugin is not compatible with core contexts.");
1086 if (!ACG::openGLVersion(2, 0))
1087 return QString("Insufficient OpenGL Version! OpenGL 2.0 or higher required");
1088
1089 // Collect missing extension
1090 QString missing = "";
1091
1092 if ( !ACG::checkExtensionSupported("GL_ARB_geometry_shader4") )
1093 missing += "Missing Extension GL_ARB_geometry_shader4\n";
1094
1095 if ( !ACG::checkExtensionSupported("GL_ARB_vertex_program") )
1096 missing += "Missing Extension GL_ARB_vertex_program\n";
1097
1098 return missing;
1099}
1100
1101
1102
static void lockProgram()
lock the program
Definition GLState.hh:654
static void lockDepthRange()
lock depth range
Definition GLState.hh:406
unsigned int max_render_passes() const
get maximum number of render passes
Definition GLState.hh:1018
static void depthRange(GLclampd _zNear, GLclampd _zFar)
replaces glDepthRange, supports locking
Definition GLState.cc:1757
static void unlockDepthRange()
unlock depth range
Definition GLState.hh:408
const Vec4f & clear_color() const
get background color
Definition GLState.hh:946
static void unlockProgram()
unlock the program
Definition GLState.hh:656
void reset_render_pass()
reset render pass counter
Definition GLState.hh:1012
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition GLState.cc:941
void next_render_pass()
increment render pass counter
Definition GLState.hh:1015
ChildIter childrenBegin()
Returns: begin-iterator of children.
Definition BaseNode.hh:294
ChildIter childrenEnd()
Returns: end-iterator of children.
Definition BaseNode.hh:298
DrawModes::DrawMode drawMode() const
Return the own draw modes of this node.
Definition BaseNode.hh:430
unsigned int traverseMode() const
Return how the node should be traversed.
Definition BaseNode.hh:449
bool multipassStatusActive(const unsigned int _i) const
Get multipass status to traverse in a specific pass.
Definition BaseNode.cc:215
@ HideNode
Hide this node, but draw children.
Definition BaseNode.hh:394
@ HideChildren
Draw this node, but hide children.
Definition BaseNode.hh:396
@ HideSubtree
Hide this node and its children.
Definition BaseNode.hh:398
@ ChildrenFirst
Execute action the children first and then on this node.
Definition BaseNode.hh:443
@ NodeFirst
Execute action on node first and then on its children.
Definition BaseNode.hh:441
@ SecondPass
Draw node in second pass.
Definition BaseNode.hh:445
bool multipassNodeActive(const unsigned int _i) const
Get Node status to traverse in a specific pass.
Definition BaseNode.cc:248
std::vector< BaseNode * >::iterator ChildIter
allows to iterate over children
Definition BaseNode.hh:286
StatusMode status() const
Get node's status.
Definition BaseNode.hh:401
void getLightSource(LightSource *_light) const
Get the light source parameters.
Definition LightNode.cc:253
Structure to hold options for one LightSource.
Definition LightNode.hh:86
bool directional() const
Check if the light source is a directional light source.
Definition LightNode.cc:127
void drawQuadProj(float _x0=-1.0f, float _y0=1.0f, float _w=2.0f, float _h=2.0f)
draw a quad in projection space (only positions)
GLSL::Program * peelProgs_[PEEL_NUM_COMBINATIONS]
generates shader programs
void traverseLightNodes(BaseNode *_node)
find all light nodes in the scene
void destroyResources()
free all gl resources
void updatePeelingShaderSet()
regenerates peeling shaders based on light nodes in scenegraph
LightType
light type enumeration
GLuint numLights_
number of used lights in the scene
GLSL::Shader * blendShaders_[8]
shader resources
ACG::GLState * glStateTmp_
current glState ptr for hiddenline rendering
GLuint glLightIDs_[16]
matching GL light id
GLSL::Program * blendDualPeelProg_[4]
depth peeling programs
void drawScenePass(ACG::GLState *_glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, BaseNode *_sceneGraphRoot)
draw the current scene
LightType lightTypes_[16]
registered lights in the scene
void generatePeelingShaders(GLSL::StringList *_strVertexShaderOut, GLSL::StringList *_strFragmentShaderOut, GLSL::StringList *_strGeometryShaderOut, bool _textured, bool _flatShaded, bool _phong, bool _vertexColor, bool _wireFrame)
peel shader generator based on lights and texture mode
unsigned int getPeelShaderIndex(ACG::SceneGraph::DrawModes::DrawMode _drawMode)
converts a drawmode to the correct shading program index
GLSL::Shader * peelShaders_[PEEL_NUM_COMBINATIONS *3]
generated shader set
GLuint blendQueryID_
fragment query
GLSL fragment shader.
GLSL geometry shader.
GLSL program class.
void setGeometryVertexCount(GLint _numVerticesOut)
Sets the maximum vertex output of the geometry shader.
void setGeometryOutputType(GLint _type)
Set output type of geometry.
void link()
Links the shader objects to the program.
void use()
Enables the program object for using.
void setGeometryInputType(GLint _type)
Set Type of Geometry.
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
void attach(PtrConstShader _shader)
Attaches a shader object to the program object.
bool compile(bool verbose=true)
Compile the shader object.
void setSource(const StringList &source)
Upload the source of the shader.
GLSL vertex shader.
Definition GLSLShader.hh:95
DrawMode SOLID_SMOOTH_SHADED
draw smooth shaded (Gouraud shaded) faces (requires halfedge normals)
Definition DrawModes.cc:82
DrawMode SOLID_PHONG_SHADED
draw phong shaded faces
Definition DrawModes.cc:83
DrawMode SOLID_FACES_COLORED_SMOOTH_SHADED
draw smooth shaded and colored faces (requires vertex normals and face colors)
Definition DrawModes.cc:95
DrawMode POINTS_COLORED
draw colored, but not lighted points (requires point colors)
Definition DrawModes.cc:74
DrawMode SOLID_TEXTURED_SHADED
draw smooth shaded textured faces
Definition DrawModes.cc:89
DrawMode SOLID_FACES_COLORED
draw colored, but not lighted faces using face colors
Definition DrawModes.cc:84
DrawMode DEFAULT
use the default (global) draw mode and not the node's own.
Definition DrawModes.cc:72
DrawMode SOLID_FACES_COLORED_FLAT_SHADED
draw flat shaded and colored faces (requires face normals and colors)
Definition DrawModes.cc:94
DrawMode WIREFRAME
draw wireframe
Definition DrawModes.cc:78
DrawMode HIDDENLINE
draw hidden line (2 rendering passes needed)
Definition DrawModes.cc:80
DrawMode SOLID_POINTS_COLORED
draw colored, but not lighted faces using interpolated vertex colors
Definition DrawModes.cc:85
DrawMode SOLID_TEXTURED
draw textured faces
Definition DrawModes.cc:88
DrawMode SOLID_FLAT_SHADED
draw flat shaded faces (requires face normals)
Definition DrawModes.cc:81
Namespace providing different geometric functions concerning angles.
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
bool compatibilityProfile()
get opengl core profile setting
Definition gl.cc:171
ACG::SceneGraph::BaseNode * getSceneGraphRootNode()
get scenegraph root node
unsigned int glWidth_
viewer window width
unsigned int rtWidth_
render target width
GLuint blendDualPeelTexID_[7]
render target textures: {depth0, depth1, front_blend0, front_blend1, back_temp0, back_temp1,...
unsigned int glHeight_
viewer window height
unsigned int rtHeight_
render target height