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[";
252 std::string strMaterial = "gl_FrontLightProduct[";
253 {
254 char szTmp[8];
255 sprintf(szTmp, "%u]", glLightIDs_[i]);
256
257 strLight += szTmp;
258 strMaterial += szTmp;
259 }
260
261 // light vector
262 if (lightTypes_[i] == LIGHTTYPE_DIRECTIONAL)
263 strCode += "vec3 vLightVS = " + strLight + ".position.xyz;\n";
264 else
265 strCode += "vec3 vLightVS = " + strLight + ".position.xyz - " + strFragPos + ".xyz;\n";
266
267 strCode += "vec3 vLightDir = normalize(vLightVS);\n";
268
269 // ambient
270 strCode += "vec4 colLight = " + strMaterial + ".ambient;\n";
271
272 // diffuse
273 strCode += "float ldotn = dot(vLightDir, " + strNormal + ");\n";
274 strCode += "ldotn = clamp(ldotn, 0.0, 1.0);\n";
275 strCode += "colLight += ldotn * ";
276 if (_textured && _phong)
277 strCode += "diffColor * ";
278
279 if (_vertexColor)
280 {
281 if (_flatShaded)
282 strCode += "vColor[2];\n";
283 else
284 strCode += "gl_Color;\n";
285 }
286 else
287 strCode += strMaterial + ".diffuse;\n";
288
289 //specular
290 strCode += "colLight += floor(ldotn + 0.9) * pow(ldotn, gl_FrontMaterial.shininess) * " + strMaterial + ".specular;\n";
291
292
293 if (lightTypes_[i] == LIGHTTYPE_DIRECTIONAL)
294 strCode += strColor + ".rgb += colLight.rgb;\n";
295 else
296 {
297 // attenuation
298 strCode += "float fLenSq = dot(vLightVS, vLightVS);\n";
299 strCode += "float atten = " + strLight + ".constantAttenuation + " +
300 strLight + ".linearAttenuation * sqrt(fLenSq) + " +
301 strLight + ".quadraticAttenuation * fLenSq;\n";
302
303 if (lightTypes_[i] == LIGHTTYPE_POINT)
304 strCode += strColor + ".rgb += colLight.rgb / atten;\n";
305 else
306 {
307 // spotlight
308 strCode += "float spot = -dot(vLightDir, " + strLight + ".spotDirection);\n";
309 strCode += "spot *= step(" + strLight + ".spotCosCutoff, spot);\n";
310 strCode += "spot *= pow(spot, " + strLight + ".spotExponent);\n";
311
312 strCode += strColor + ".rgb += " + "(spot / atten) * colLight.rgb;\n";
313 }
314 }
315
316 strCode += "}\n";
317 }
318
319 const char* szVertexShader[] = {"varying vec2 vTexCoord;",
320 "varying vec3 vNormal; // normal: view space",
321 "varying vec4 vPosVS; // position in view space",
322 "varying vec4 vColor; // used in gouraud / flat shading only",
323 "",
324 "void main(void)",
325 "{",
326 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;",
327 " ",
328 " vNormal = gl_NormalMatrix * gl_Normal; // gl_NormalMatrix : upper left 3x3 of WorldViewIT",
329 " vPosVS = (gl_ModelViewMatrix * gl_Vertex);",
330 " vTexCoord = gl_MultiTexCoord0.xy;",
331 ""};
332 // NOTE: this vertex shader code misses the ending '}' to append the lighting code later
333
334 // geometry shader for flat shading only
335 const char* szGeometryShaderStart[] = {
336 "#version 120",
337 "#extension GL_ARB_geometry_shader4 : enable",
338 "",
339 "varying vec2 vTexCoord[3];",
340 "varying vec4 vPosVS[3];",
341 "varying vec3 vNormal[3];",
342 "varying vec4 vColor[3];",
343 "",
344 "varying vec2 VTexCoord;",
345 "varying vec3 VNormal;",
346 "varying vec4 VPosVS;",
347 "varying vec4 VColor;",
348 "",
349 "",
350 "void main()",
351 "{",
352 " // recompute triangle normal",
353// " vec3 normal = cross(vNormal[2].xyz - vNormal[0].xyz, vNormal[1].xyz - vNormal[0].xyz);",
354 " vec3 normal = cross(gl_PositionIn[1].xyz - gl_PositionIn[0].xyz, gl_PositionIn[2].xyz - gl_PositionIn[0].xyz);",
355 " normal = normalize(normal);",
356 " normal = gl_NormalMatrix * normal;",
357// " normal = vNormal[2].xyz;",
358 " ",
359 " VPosVS = (gl_PositionIn[0] + gl_PositionIn[1] + gl_PositionIn[2]) / 3.0;",
360 " VPosVS = gl_ModelViewMatrix * VPosVS; // triangle center in view space needed for point and spot lights",
361 " vec4 color = vec4(gl_FrontMaterial.emission.rgb, gl_FrontMaterial.diffuse.a);",
362 ""};
363
364 const char* szGeometryShaderEnd[] = {
365 "",
366 " for(int i = 0; i < 3; i++)",
367 " {",
368 " gl_Position = gl_ModelViewProjectionMatrix * gl_PositionIn[i];",
369 " VTexCoord = vTexCoord[i];",
370 " VNormal = normal;",
371 " VPosVS = vPosVS[i];",
372// " VColor = (normal+vec3(0.5,0.5,0.5)).xyzz*0.5;",
373 " VColor = color;",
374 " EmitVertex();",
375 " }",
376 " EndPrimitive();",
377 " ",
378 "}"};
379
380 const char* szFragmentShaderStart[] = {"varying vec2 vTexCoord;",
381 "varying vec3 vNormal; ",
382 "varying vec4 vPosVS;",
383 "varying vec4 vColor;",
384 "",
385 "uniform sampler2D DiffuseTex;",
386 "uniform sampler2DRect DepthBlenderTex;",
387 "uniform sampler2DRect FrontBlenderTex;",
388 "",
389 "#define MAX_DEPTH 1.0",
390 "",
391 "",
392 "void main(void)",
393 "{",
394 " // window-space depth interpolated linearly in screen space",
395 " float fragDepth = gl_FragCoord.z;",
396 "",
397 " vec2 depthBlender = texture2DRect(DepthBlenderTex, gl_FragCoord.xy).xy;",
398 " vec4 forwardTemp = texture2DRect(FrontBlenderTex, gl_FragCoord.xy);",
399 " ",
400 " // Depths and 1.0-alphaMult always increase",
401 " // so we can use pass-through by default with MAX blending",
402 " gl_FragData[0].xy = depthBlender;",
403 " ",
404 " // Front colors always increase (DST += SRC*ALPHA_MULT)",
405 " // so we can use pass-through by default with MAX blending",
406 " gl_FragData[1] = forwardTemp;",
407 " ",
408 " // Because over blending makes color increase or decrease,",
409 " // we cannot pass-through by default.",
410 " // Each pass, only one fragment writes a color greater than 0",
411 " gl_FragData[2] = vec4(0.0);",
412 "",
413 " float nearestDepth = -depthBlender.x;",
414 " float farthestDepth = depthBlender.y;",
415 " float alphaMultiplier = 1.0 - forwardTemp.w;",
416 "",
417 " if (fragDepth < nearestDepth || fragDepth > farthestDepth) {",
418 " // Skip this depth in the peeling algorithm",
419 " gl_FragData[0].xy = vec2(-MAX_DEPTH);",
420 " return;",
421 " }",
422 " ",
423 " if (fragDepth > nearestDepth && fragDepth < farthestDepth) {",
424 " // This fragment needs to be peeled again",
425 " gl_FragData[0].xy = vec2(-fragDepth, fragDepth);",
426 " return;",
427 " }",
428 " ",
429 " // If we made it here, this fragment is on the peeled layer from last pass",
430 " // therefore, we need to shade it, and make sure it is not peeled any farther",
431 "",};
432
433 const char* szFragmentShaderEnd[] = {"",
434 " gl_FragData[0].xy = vec2(-MAX_DEPTH);",
435 " ",
436 " if (fragDepth == nearestDepth) {",
437 " gl_FragData[1].xyz += color.rgb * color.a * alphaMultiplier;",
438 " gl_FragData[1].w = 1.0 - alphaMultiplier * (1.0 - color.a);",
439 " } else {",
440 " gl_FragData[2] += color;",
441 " }",
442 "}"};
443
444 // assemble final shaders:
445
446 // vertex shader
447 for (unsigned int i = 0; i < sizeof(szVertexShader) / sizeof(char*); ++i)
448 {
449 std::string str = szVertexShader[i];
450 if (_phong)
451 {
452 if (!strncmp("varying vec4 vColor", str.c_str(), strlen("varying vec4 vColor")))
453 {
454// str.replace(str.begin(), str.begin() + 7, "flat out");
455 str += "\n";
456 continue;
457 }
458 }
459 str += "\n";
460 _strVertexShaderOut->push_back(str);
461 }
462
463 // finalize vertex shader
464 if (!_phong && !_flatShaded && !_wireFrame)
465 {
466 // lighting code:
467 _strVertexShaderOut->push_back("\nvec4 color = vec4(gl_FrontMaterial.emission.rgb, gl_FrontMaterial.diffuse.a);");
468 _strVertexShaderOut->push_back("\nvec3 normal = vNormal;\n");
469
470 std::string::size_type curPos = 0;
471 std::string::size_type newLinePos = strCode.find_first_of('\n');
472 while (newLinePos != std::string::npos)
473 {
474 _strVertexShaderOut->push_back(strCode.substr(curPos, newLinePos - curPos + 1));
475 curPos = newLinePos + 1;
476 newLinePos = strCode.find_first_of('\n', curPos);
477 }
478 _strVertexShaderOut->push_back("\nvColor = color;\n");
479 }
480 if (_flatShaded)
481 {
482 if (_vertexColor)
483 _strVertexShaderOut->push_back("vColor = gl_Color;\n");
484 _strVertexShaderOut->push_back("gl_Position = gl_Vertex;\n");
485 }
486
487 _strVertexShaderOut->push_back("\n}");
488
489 // fragment shader:
490 for (unsigned int i = 0; i < sizeof(szFragmentShaderStart) / sizeof(char*); ++i)
491 {
492 std::string str = szFragmentShaderStart[i];
493 if (_phong)
494 {
495 if (!strncmp("varying vec4 vColor", str.c_str(), strlen("varying vec4 vColor")))
496 {
497// str.replace(str.begin(), str.begin() + 7, "flat in");
498 str += "\n";
499 continue;
500 }
501 }
502 if (_flatShaded)
503 {
504 if (!strncmp("varying vec2 vTexCoord", str.c_str(), strlen("varying vec2 vTexCoord")))
505 str = "varying vec2 VTexCoord;";
506 if (!strncmp("varying vec3 vNormal", str.c_str(), strlen("varying vec3 vNormal")))
507 str = "varying vec3 VNormal;";
508 if (!strncmp("varying vec4 vPosVS", str.c_str(), strlen("varying vec4 vPosVS")))
509 str = "varying vec4 VPosVS;";
510 if (!strncmp("varying vec4 vColor", str.c_str(), strlen("varying vec4 vColor")))
511 str = "varying vec4 VColor;";
512 }
513 str += "\n";
514 _strFragmentShaderOut->push_back(str);
515 }
516
517 if (!_wireFrame)
518 {
519 if (!_flatShaded)
520 {
521 _strFragmentShaderOut->push_back(" vec3 normal = normalize(vNormal);\n");
522// _strFragmentShaderOut->push_back(" vec3 normal = normalize(cross(dFdx(vPosVS.xyz), dFdy(vPosVS.xyz)));\n");
523 _strFragmentShaderOut->push_back(" vec4 color = vec4(gl_FrontMaterial.emission.rgb, gl_FrontMaterial.diffuse.a);\n");
524 if (_textured)
525 _strFragmentShaderOut->push_back(" vec4 diffColor = texture2D(DiffuseTex, vTexCoord); color.a *= diffColor.a;\n");
526 }
527 else
528 {
529 _strFragmentShaderOut->push_back(" vec4 color = vec4(gl_FrontMaterial.emission.rgb, gl_FrontMaterial.diffuse.a);\n");
530 _strFragmentShaderOut->push_back(" vec4 vColor = VColor;\n");
531 if (_textured)
532 _strFragmentShaderOut->push_back(" vec4 diffColor = texture2D(DiffuseTex, VTexCoord); color.a *= diffColor.a;\n");
533 }
534
535 if (!_phong)
536 {
537 if (_textured)
538 _strFragmentShaderOut->push_back(" color = diffColor * vColor;\n");
539 else
540 _strFragmentShaderOut->push_back(" color = vColor;\n");
541 }
542 else
543 {
544 // lighting code:
545 std::string::size_type curPos = 0;
546 std::string::size_type newLinePos = strCode.find_first_of('\n');
547 while (newLinePos != std::string::npos)
548 {
549 _strFragmentShaderOut->push_back(strCode.substr(curPos, newLinePos - curPos + 1));
550 curPos = newLinePos + 1;
551 newLinePos = strCode.find_first_of('\n', curPos);
552 }
553 }
554 }
555 else // wireframe:
556 _strFragmentShaderOut->push_back(" vec4 color = vColor;\n");
557
558 for (unsigned int i = 0; i < sizeof(szFragmentShaderEnd) / sizeof(char*); ++i)
559 {
560 std::string str = szFragmentShaderEnd[i];
561 str += "\n";
562 _strFragmentShaderOut->push_back(str);
563 }
564
565
566 // geometry shader:
567 if (_flatShaded)
568 {
569 for (unsigned int i = 0; i < sizeof(szGeometryShaderStart) / sizeof(char*); ++i)
570 {
571 std::string str = szGeometryShaderStart[i];
572 str += "\n";
573 _strGeometryShaderOut->push_back(str);
574 }
575
576 // lighting code:
577 std::string::size_type curPos = 0;
578 std::string::size_type newLinePos = strCode.find_first_of('\n');
579 while (newLinePos != std::string::npos)
580 {
581 _strGeometryShaderOut->push_back(strCode.substr(curPos, newLinePos - curPos + 1));
582 curPos = newLinePos + 1;
583 newLinePos = strCode.find_first_of('\n', curPos);
584 }
585
586 for (unsigned int i = 0; i < sizeof(szGeometryShaderEnd) / sizeof(char*); ++i)
587 {
588 std::string str = szGeometryShaderEnd[i];
589 str += "\n";
590 _strGeometryShaderOut->push_back(str);
591 }
592 }
593
594
595 // debug output:
596#ifdef DEPTHPEELING_SHADER_EXPORT
597 FILE* pShaderOut = fopen("peel_vertex.glsl", "wt");
598 for (GLSL::StringList::iterator it = _strVertexShaderOut->begin(); it != _strVertexShaderOut->end(); ++it)
599 fprintf(pShaderOut, it->c_str());
600 fclose(pShaderOut);
601
602
603 pShaderOut = fopen("peel_frag.glsl", "wt");
604 for (GLSL::StringList::iterator it = _strFragmentShaderOut->begin(); it != _strFragmentShaderOut->end(); ++it)
605 fprintf(pShaderOut, it->c_str());
606 fclose(pShaderOut);
607
608 if (_flatShaded)
609 {
610 pShaderOut = fopen("peel_geom.glsl", "wt");
611 for (GLSL::StringList::iterator it = _strGeometryShaderOut->begin(); it != _strGeometryShaderOut->end(); ++it)
612 fprintf(pShaderOut, it->c_str());
613 fclose(pShaderOut);
614 }
615#endif
616}
617
619
620template <class Action>
621bool
622DepthPeelingPlugin::traverseDrawApplyAction( BaseNode* _node, Action& _action, ACG::SceneGraph::DrawModes::DrawMode _globalDrawMode, int _pass, int _peelPass)
623{
624 bool ret = true; // process_children flag returned
625
626 // use nodes drawmode to grab a peeler program with correct shading
628 dm = dmSave;
629
630 if (!dm) return ret;
631
633 dm = _globalDrawMode;
634/*
635 if (dm & ACG::SceneGraph::DrawModes::HIDDENLINE)
636 {
637 // hiddenline is accomplished with wireframe in first peel layer only
638 dm &= ~ACG::SceneGraph::DrawModes::HIDDENLINE;
639 dm |= ACG::SceneGraph::DrawModes::WIREFRAME;
640 if (_peelPass > 2)
641 return ret;
642 _node->drawMode(dm);
643 }
644*/
646 {
648 dmShaded &= ~ACG::SceneGraph::DrawModes::WIREFRAME;
649 dmShaded &= ~ACG::SceneGraph::DrawModes::HIDDENLINE;
650
651 // polygon only draw
652 if (dmShaded)
653 {
654 _node->drawMode(dmShaded); // evil method: change nodes drawmode here, restore it later
655 ret &= traverseDrawApplyAction(_node, _action, _globalDrawMode, _pass, _peelPass);
656 }
657
658 // wireframe only follows
659 dm &= (~dmShaded);
660 _node->drawMode(dm);
661 }
662
663 unsigned int shaderIndex = getPeelShaderIndex(dm);
664
665 // do hiddenline algorithmus manually here
666 GLenum prev_depth = glStateTmp_->depthFunc();
668 {
669 // manual hiddenline
670
671 // First:
672 // Render all faces in background color to initialize z-buffer
674
675 GLSL::Program* peelProg = peelProgs_[PEEL_SHADER_HIDDENLINE];
676 peelProg->use();
677 peelProg->setUniform("DepthBlenderTex", 4);
678 peelProg->setUniform("FrontBlenderTex", 5);
679 peelProg->setUniform("ObjectColor", glStateTmp_->clear_color());
680
681 ACG::GLState::depthRange(0.01, 1.0);
684 ret &= _action(_node);
687 ACG::GLState::depthRange(0.0, 1.0);
688
689 // Second
690 // Render the lines. All lines not on the front will be skipped in z-test
692
693 ACG::GLState::depthFunc(GL_LEQUAL);
694 ACG::GLState::lockDepthFunc();
695
696 // use wireframe shader now
697 shaderIndex = PEEL_SHADER_WIREFRAME;
698 }
699
700 GLSL::Program* peelProg = peelProgs_[shaderIndex];
701 peelProg->use();
702 peelProg->setUniform("DepthBlenderTex", 4);
703 peelProg->setUniform("FrontBlenderTex", 5);
704
705 if (shaderIndex & PEEL_SHADER_FLAT)
706 {
707 // set geomtry shader constants
708 peelProg->setGeometryInputType(GL_TRIANGLES);
709 peelProg->setGeometryOutputType(GL_TRIANGLE_STRIP);
710 peelProg->setGeometryVertexCount(3);
711 }
712 peelProg->setUniform("DiffuseTex", 0);
713
715 ret &= _action(_node);
717
718 // restore state
719 _node->drawMode(dmSave);
720
722 {
723 ACG::GLState::unlockDepthFunc();
724
725 //restore depth buffer comparison function
726 ACG::GLState::depthFunc(prev_depth);
727 }
728
729 return ret;
730}
731
733
734template <class Action>
735void
736DepthPeelingPlugin::traverseDraw( BaseNode* _node, Action& _action, ACG::SceneGraph::DrawModes::DrawMode _globalDrawMode, int _pass, int _peelPass)
737{
738
739 // Process node if it exists
740 if (_node) {
741 BaseNode::StatusMode status(_node->status());
742
743 // If the subtree is hidden, ignore this node and its children while rendering
744 if (status != BaseNode::HideSubtree) {
745
746 bool process_children(status != BaseNode::HideChildren);
747
748 // Executes this nodes enter function (if available and active in multipass)
749 if ( _node->multipassStatusActive(_pass) ) {
750 if_has_enter(_action, _node);
751 }
752
753 // If the node itself is hidden, don't call the action on it.
754 // Additionally check if rendering order is node first. otherwise, we will call it after the children.
755 // And check if it should be called in this rendering pass.
756 if ( (_node->status() != BaseNode::HideNode ) && ( _node->traverseMode() & BaseNode::NodeFirst ) && _node->multipassNodeActive(_pass))
757 process_children &= traverseDrawApplyAction(_node, _action, _globalDrawMode, _pass, _peelPass);
758
759 if (process_children) {
760
761 BaseNode::ChildIter cIt, cEnd(_node->childrenEnd());
762
763 // Process all children
764 for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
765 if (~(*cIt)->traverseMode() & BaseNode::SecondPass)
766 traverseDraw(*cIt, _action, _globalDrawMode, _pass, _peelPass);
767
768 // Process all children which are second pass
769 for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
770 if ((*cIt)->traverseMode() & BaseNode::SecondPass)
771 traverseDraw(*cIt, _action, _globalDrawMode, _pass, _peelPass);
772
773 }
774
775
776 // If we are in childrenfirst node, the children have been painted andwe now check, if we can draw this node.
777 // If its hidden, ignore it.
778 // If it should not be rendered in this pass, ignore it too.
779 if ( (_node->traverseMode() & BaseNode::ChildrenFirst ) && (_node->status() != BaseNode::HideNode) && _node->multipassNodeActive(_pass) )
780 traverseDrawApplyAction(_node, _action, _globalDrawMode, _pass, _peelPass);
781
782 // Call the leave function of the node (if available and active in multipass).
783 if ( _node->multipassStatusActive(_pass) )
784 if_has_leave(_action, _node);
785
786 } // if (status != BaseNode::HideSubtree)
787 } // if(node_)
788}
789
790void DepthPeelingPlugin::drawScenePeelPass(ACG::GLState* _glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, BaseNode* _sceneGraphRoot, int _peelPass)
791{
792 ACG::SceneGraph::DrawAction action(_drawMode, *_glState, false);
793// traverseDraw(_sceneGraphRoot, action, *_glState, _drawMode);
794
795 // Reset render pass counter
796 _glState->reset_render_pass();
797
798 // Get max render passes
799 unsigned int max_passes = _glState->max_render_passes();
800
801 // Render all passes
802 for(unsigned int pass = BaseNode::PASS_1; pass <= (BaseNode::PASS_1 + max_passes); ++pass) {
803
804 // Traverse scenegraph
805 traverseDraw (_sceneGraphRoot, action, _drawMode, pass, _peelPass);
806 // Increment render pass counter by 1
807 _glState->next_render_pass();
808 }
809
810 // Reset render pass counter
811 _glState->reset_render_pass();
812}
813
815
817{
818 ACG::SceneGraph::DrawAction action(_drawMode, *_glState, false);
819 traverse_multipass(_sceneGraphRoot, action, *_glState, _drawMode);
820}
821
823
825{
826 bool rebuildShaders = false;
827
829
830 // peel shader is rebuilt, if a new light is added or a light type changed
831
832 LightType prevLights[8];
833 unsigned int prevIDs[8];
834 unsigned int prevNum = numLights_;
835
836 memcpy(prevLights, lightTypes_, sizeof(LightType) * numLights_);
837 memcpy(prevIDs, glLightIDs_, sizeof(unsigned int) * numLights_);
838
839 numLights_ = 0;
840 traverseLightNodes(sceneGraphRoot);
841
842 // test for necessary shader recompilation
843 if (numLights_ == prevNum)
844 {
845 // look for any light node changes
846 if (memcmp(prevLights, lightTypes_, sizeof(LightType) * numLights_) ||
847 memcmp(prevIDs, glLightIDs_, sizeof(unsigned int) * numLights_))
848 rebuildShaders = true;
849 }
850 else rebuildShaders = true;
851
852 if (rebuildShaders)
853 {
854 // delete old shaders and programs
855 for (unsigned int i = 0; i < sizeof(peelShaders_) / sizeof(peelShaders_[0]); ++i)
856 {
857 delete peelShaders_[i]; peelShaders_[i] = 0;
858 }
859
860 for (unsigned int i = 0; i < sizeof(peelProgs_) / sizeof(peelProgs_[0]); ++i)
861 {
862 delete peelProgs_[i]; peelProgs_[i] = 0;
863 }
864
865 for (unsigned int i = 0; i < PEEL_NUM_COMBINATIONS; ++i)
866 {
867 GLuint texturedDrawMode = 0, flatDrawMode = 0, phongDrawMode = 0, vertexColorDrawMode = 0, gouraudDrawMode = 0;
868
869 texturedDrawMode = i & PEEL_SHADER_TEXTURED;
870 flatDrawMode = i & PEEL_SHADER_FLAT;
871 phongDrawMode = i & PEEL_SHADER_PHONG;
872 vertexColorDrawMode = i & PEEL_SHADER_VERTEXCOLORS;
873 gouraudDrawMode = i & PEEL_SHADER_GOURAUD;
874
875 if (i != PEEL_SHADER_WIREFRAME)
876 {
877 // filter nonsense
878 if (flatDrawMode && phongDrawMode) continue;
879 if (flatDrawMode && gouraudDrawMode) continue;
880 if (phongDrawMode && gouraudDrawMode) continue;
881
882 if (phongDrawMode + flatDrawMode + gouraudDrawMode == 0) continue;
883 }
884
885 if (flatDrawMode)
886 {
887 // replace flat shading with gouraud, if geometry shaders are not supported
888 if (!ACG::checkExtensionSupported("GL_ARB_geometry_shader4") && !ACG::checkExtensionSupported("GL_EXT_geometry_shader4"))
889 {
890 flatDrawMode = 0;
891 gouraudDrawMode = 1;
892 }
893 }
894
895 GLSL::StringList strVertexShader, strFragmentShader, strGeometryShader;
896 generatePeelingShaders(&strVertexShader, &strFragmentShader, &strGeometryShader, texturedDrawMode != 0, flatDrawMode != 0, phongDrawMode != 0, vertexColorDrawMode != 0, i == PEEL_SHADER_WIREFRAME);
897
898 peelProgs_[i] = new GLSL::Program();
899
900
901 GLSL::VertexShader* pVertexSh = new GLSL::VertexShader();
902 pVertexSh->setSource(strVertexShader);
903 pVertexSh->compile();
904 peelShaders_[i*3 + 0] = pVertexSh;
905 peelProgs_[i]->attach(pVertexSh);
906
907 if (flatDrawMode)
908 {
910 pGeomSh->setSource(strGeometryShader);
911 pGeomSh->compile();
912 peelShaders_[i*3 + 1] = pGeomSh;
913 peelProgs_[i]->attach(pGeomSh);
914 }
915
917 pFragSh->setSource(strFragmentShader);
918 pFragSh->compile();
919 peelShaders_[i*3 + 2] = pFragSh;
920 peelProgs_[i]->attach(pFragSh);
921
922 peelProgs_[i]->link();
924
925
926#ifdef DEPTHPEELING_SHADER_EXPORT
927 char szFileName[256];
928 sprintf(szFileName, "peel_vertex_%02u.glsl", i);
929 FILE* pShaderOut = fopen(szFileName, "wt");
930 for (GLSL::StringList::iterator it = strVertexShader.begin(); it != strVertexShader.end(); ++it)
931 fprintf(pShaderOut, it->c_str());
932 fclose(pShaderOut);
933
934
935 sprintf(szFileName, "peel_frag%02u.glsl", i);
936 pShaderOut = fopen(szFileName, "wt");
937 for (GLSL::StringList::iterator it = strFragmentShader.begin(); it != strFragmentShader.end(); ++it)
938 fprintf(pShaderOut, it->c_str());
939 fclose(pShaderOut);
940
941 if (flatDrawMode)
942 {
943 sprintf(szFileName, "peel_geom%02u.glsl", i);
944 pShaderOut = fopen(szFileName, "wt");
945 for (GLSL::StringList::iterator it = strGeometryShader.begin(); it != strGeometryShader.end(); ++it)
946 fprintf(pShaderOut, it->c_str());
947 fclose(pShaderOut);
948 }
949#endif
950 }
951 }
952
953
954 // create a special shader for hiddenline
955 // hiddenline = wireframe + early z cull
956 // the special shader is needed for the z buffer pass
957
958 const char* szVertexShader[] = {
959 "void main(void)",
960 "{",
961 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;",
962 "}"};
963
964 const char* szFragmentShader[] = {
965 "uniform vec4 ObjectColor;",
966 "uniform sampler2DRect DepthBlenderTex;",
967 "uniform sampler2DRect FrontBlenderTex;",
968 "",
969 "#define MAX_DEPTH 1.0",
970 "",
971 "",
972 "void main(void)",
973 "{",
974 " // window-space depth interpolated linearly in screen space",
975 " float fragDepth = gl_FragCoord.z;",
976 "",
977 " vec2 depthBlender = texture2DRect(DepthBlenderTex, gl_FragCoord.xy).xy;",
978 " vec4 forwardTemp = texture2DRect(FrontBlenderTex, gl_FragCoord.xy);",
979 " ",
980 " // Depths and 1.0-alphaMult always increase",
981 " // so we can use pass-through by default with MAX blending",
982 " gl_FragData[0].xy = depthBlender;",
983 " ",
984 " // Front colors always increase (DST += SRC*ALPHA_MULT)",
985 " // so we can use pass-through by default with MAX blending",
986 " gl_FragData[1] = forwardTemp;",
987 " ",
988 " // Because over blending makes color increase or decrease,",
989 " // we cannot pass-through by default.",
990 " // Each pass, only one fragment writes a color greater than 0",
991 " gl_FragData[2] = vec4(0.0);",
992 "",
993 " float nearestDepth = -depthBlender.x;",
994 " float farthestDepth = depthBlender.y;",
995 " float alphaMultiplier = 1.0 - forwardTemp.w;",
996 "",
997 " if (fragDepth < nearestDepth || fragDepth > farthestDepth) {",
998 " // Skip this depth in the peeling algorithm",
999 " gl_FragData[0].xy = vec2(-MAX_DEPTH);",
1000 " return;",
1001 " }",
1002 " ",
1003 " if (fragDepth > nearestDepth && fragDepth < farthestDepth) {",
1004 " // This fragment needs to be peeled again",
1005 " gl_FragData[0].xy = vec2(-fragDepth, fragDepth);",
1006 " return;",
1007 " }",
1008 " ",
1009 " // If we made it here, this fragment is on the peeled layer from last pass",
1010 " // therefore, we need to shade it, and make sure it is not peeled any farther",
1011 " vec4 color = ObjectColor;",
1012 " gl_FragData[0].xy = vec2(-MAX_DEPTH);",
1013 " ",
1014 " if (fragDepth == nearestDepth) {",
1015 " gl_FragData[1].xyz += color.rgb * color.a * alphaMultiplier;",
1016 " gl_FragData[1].w = 1.0 - alphaMultiplier * (1.0 - color.a);",
1017 " } else {",
1018 " gl_FragData[2] += color;",
1019 " }",
1020 "}"};
1021
1022 GLSL::StringList strVertexShader, strFragmentShader;
1023 for (unsigned int i = 0; i < sizeof(szVertexShader) / sizeof(char*); ++i)
1024 {
1025 std::string str = szVertexShader[i];
1026 str += "\n";
1027 strVertexShader.push_back(str);
1028 }
1029
1030 for (unsigned int i = 0; i < sizeof(szFragmentShader) / sizeof(char*); ++i)
1031 {
1032 std::string str = szFragmentShader[i];
1033 str += "\n";
1034 strFragmentShader.push_back(str);
1035 }
1036
1037 GLSL::Program* peelHiddenLine = peelProgs_[PEEL_SHADER_HIDDENLINE] = new GLSL::Program();
1038
1039 GLSL::VertexShader* pVertexSh = new GLSL::VertexShader();
1040 pVertexSh->setSource(strVertexShader);
1041 pVertexSh->compile();
1042 peelShaders_[PEEL_SHADER_HIDDENLINE*3 + 0] = pVertexSh;
1043 peelHiddenLine->attach(pVertexSh);
1044
1046 pFragSh->setSource(strFragmentShader);
1047 pFragSh->compile();
1048 peelShaders_[PEEL_SHADER_HIDDENLINE*3 + 2] = pFragSh;
1049 peelHiddenLine->attach(pFragSh);
1050
1051 peelHiddenLine->link();
1053}
1054
1056
1058{
1059 if (_drawMode & ACG::SceneGraph::DrawModes::WIREFRAME ||
1061 return PEEL_SHADER_WIREFRAME;
1062
1064 bool flat = _drawMode & ACG::SceneGraph::DrawModes::SOLID_FLAT_SHADED;
1065 bool phong = _drawMode & ACG::SceneGraph::DrawModes::SOLID_PHONG_SHADED;
1068
1069 bool gouraud = _drawMode & ACG::SceneGraph::DrawModes::SOLID_SMOOTH_SHADED;
1070
1071 // fix illegal combinations
1072 if (phong && flat) flat = false;
1073 if (flat && gouraud) gouraud = false;
1074 if (gouraud && phong) phong = false;
1075
1076 // wireframe, point, etc use gouraud shading
1077 if ((!phong) && (!gouraud) && (!flat)) gouraud = true;
1078
1079 unsigned int idx = 0;
1080
1081 if (flat) idx |= PEEL_SHADER_FLAT;
1082 if (gouraud) idx |= PEEL_SHADER_GOURAUD;
1083 if (phong) idx |= PEEL_SHADER_PHONG;
1084 if (vertexColor) idx |= PEEL_SHADER_VERTEXCOLORS;
1085 if (textured) idx |= PEEL_SHADER_TEXTURED;
1086
1087 return idx;
1088}
1089
1090QString DepthPeelingPlugin::checkOpenGL() {
1092 return QString("Classic depth peeling Rendering-plugin is not compatible with core contexts.");
1093 if (!ACG::openGLVersion(2, 0))
1094 return QString("Insufficient OpenGL Version! OpenGL 2.0 or higher required");
1095
1096 // Collect missing extension
1097 QString missing = "";
1098
1099 if ( !ACG::checkExtensionSupported("GL_ARB_geometry_shader4") )
1100 missing += "Missing Extension GL_ARB_geometry_shader4\n";
1101
1102 if ( !ACG::checkExtensionSupported("GL_ARB_vertex_program") )
1103 missing += "Missing Extension GL_ARB_vertex_program\n";
1104
1105 return missing;
1106}
1107
1108
1109
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