PeriDyno 1.0.0
Loading...
Searching...
No Matches
GLRenderEngine.cpp
Go to the documentation of this file.
1#include "GLRenderEngine.h"
2#include "GLRenderHelper.h"
3#include "GLVisualModule.h"
4
5#include "Utility.h"
6#include "ShadowMap.h"
7#include "SSAO.h"
8#include "FXAA.h"
9#include "Envmap.h"
10
11// dyno
12#include "SceneGraph.h"
13#include "Action.h"
14
15// GLM
16#define GLM_ENABLE_EXPERIMENTAL
17#include <glm/gtx/hash.hpp>
18#include <glm/gtc/type_ptr.hpp>
19#include <glm/gtc/matrix_transform.hpp>
20
21#include <glad/glad.h>
22
23#include <OrbitCamera.h>
24#include <TrackballCamera.h>
25#include <unordered_set>
26#include <memory>
27
28#include "screen.vert.h"
29#include "blend.frag.h"
30
31namespace dyno
32{
38
40 {
41 delete mShadowMap;
42 delete mEnvmap;
43 }
44
46 {
47 if (!gladLoadGL()) {
48 printf("Failed to load OpenGL context!");
49 exit(-1);
50 }
51
52 // some basic opengl settings
53 glEnable(GL_DEPTH_TEST);
54 glEnable(GL_PROGRAM_POINT_SIZE);
55 glDepthFunc(GL_LEQUAL);
56 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
57
59
60 // OIT
62
64
65 // create a screen quad
67
69 mFXAAFilter = new FXAA;
70
71 mShadowMap->initialize();
72 mEnvmap->initialize();
73
74 this->setDefaultEnvmap();
75 }
76
78 {
79 mShadowMap->release();
80 mEnvmap->release();
81
82 // release render modules
83 for (auto item : mRenderItems) {
84 item.visualModule->release();
85 }
86
87 // release framebuffer
88 mFramebuffer.release();
89 mColorTex.release();
90 mDepthTex.release();
91 mIndexTex.release();
92
93 mSelectIndexTex.release();
94 mSelectFramebuffer.release();
95
96 // release linked-list OIT objects
97 mFreeNodeIdx.release();
98 mLinkedListBuffer.release();
99 mHeadIndexTex.release();
100 mBlendProgram->release();
101 delete mBlendProgram;
102
103 // release other objects
104 mScreenQuad->release();
105 delete mScreenQuad;
106
107 delete mRenderHelper;
108 delete mFXAAFilter;
109
110 }
111
113 {
114 mFreeNodeIdx.create(GL_ATOMIC_COUNTER_BUFFER, GL_DYNAMIC_DRAW);
115 mFreeNodeIdx.allocate(sizeof(int));
116
117 mLinkedListBuffer.create(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_DRAW);
118 struct NodeType
119 {
120 glm::vec4 color;
121 float depth;
122 unsigned int next;
123 unsigned int idx0;
124 unsigned int idx1;
125 };
126 mLinkedListBuffer.allocate(sizeof(NodeType) * MAX_OIT_NODES);
127
128 // transparency
129 mHeadIndexTex.internalFormat = GL_R32UI;
130 mHeadIndexTex.format = GL_RED_INTEGER;
131 mHeadIndexTex.type = GL_UNSIGNED_INT;
132 mHeadIndexTex.create();
133 mHeadIndexTex.resize(1, 1, 1);
134
136 SCREEN_VERT, sizeof(SCREEN_VERT),
137 BLEND_FRAG, sizeof(BLEND_FRAG));
138 }
139
140
142 {
143 mShadowMap->setSize(size);
144 }
145
147 {
148 return mShadowMap->getSize();
149 }
150
152 {
153 mShadowMap->setNumBlurIterations(iters);
154 }
155
157 {
158 return mShadowMap->getNumBlurIterations();
159 }
160
162 {
163 setEnvmap(getAssetPath() + "textures/hdr/venice_dawn_1_4k.hdr");
164 }
165
166 void GLRenderEngine::setEnvmap(const std::string& file)
167 {
168 if (file.empty()) {
169 //bDrawEnvmap = false;
170 return;
171 }
172 else
173 {
174 //bDrawEnvmap = true;
175 mEnvmapFilePath = file;
176 mEnvmap->load(file.c_str());
177 }
178 }
179
181 {
182 envStyle = style;
183
184 if (style == EEnvStyle::Standard)
185 {
186 this->bgColor0 = glm::vec3(0.2f);
187 this->bgColor1 = glm::vec3(0.8f);
188
189 this->planeColor = { 0.3, 0.3, 0.3, 0.5 };
190 this->rulerColor = { 0.0, 0.0, 0.0, 0.5 };
191
192 this->setUseEnvmapBackground(false);
193 this->setEnvmapScale(0.0f);
194 }
195 else if (style == EEnvStyle::Studio)
196 {
197 this->bgColor0 = { 1, 1, 1 };
198 this->bgColor1 = { 1, 1, 1 };
199
200 this->planeColor = { 1,1,1,1 };
201 this->rulerColor = { 1,1,1,1 };
202
203 this->setUseEnvmapBackground(true);
204 this->setEnvmapScale(1.0f);
205 }
206 }
207
209 {
210 // create render textures
211 mColorTex.format = GL_RGBA;
212 mColorTex.internalFormat = GL_RGBA;
213 mColorTex.type = GL_BYTE;
214 mColorTex.create();
215 mColorTex.resize(1, 1, 1);
216
217 mDepthTex.internalFormat = GL_DEPTH_COMPONENT32;
218 mDepthTex.format = GL_DEPTH_COMPONENT;
219 mDepthTex.create();
220 mDepthTex.resize(1, 1, 1);
221
222 // index
223 mIndexTex.internalFormat = GL_RGBA32I;
224 mIndexTex.format = GL_RGBA_INTEGER;
225 mIndexTex.type = GL_INT;
226 //mIndexTex.wrapS = GL_CLAMP_TO_EDGE;
227 //mIndexTex.wrapT = GL_CLAMP_TO_EDGE;
228 mIndexTex.create();
229 mIndexTex.resize(1, 1, 1);
230
231 // create framebuffer
232 mFramebuffer.create();
233
234 // bind framebuffer texture
235 mFramebuffer.bind();
236 mFramebuffer.setTexture(GL_DEPTH_ATTACHMENT, &mDepthTex);
237 mFramebuffer.setTexture(GL_COLOR_ATTACHMENT0, &mColorTex);
238 mFramebuffer.setTexture(GL_COLOR_ATTACHMENT1, &mIndexTex);
239
240 const GLenum buffers[] = {
241 GL_COLOR_ATTACHMENT0,
242 GL_COLOR_ATTACHMENT1
243 };
244 mFramebuffer.drawBuffers(2, buffers);
245
246 mFramebuffer.checkStatus();
247 mFramebuffer.unbind();
248
249 // select framebuffer
250 mSelectIndexTex.internalFormat = GL_RGBA32I;
251 mSelectIndexTex.format = GL_RGBA_INTEGER;
252 mSelectIndexTex.type = GL_INT;
253 mSelectIndexTex.create();
254 mSelectIndexTex.resize(1, 1);
255
256 mSelectFramebuffer.create();
257 mSelectFramebuffer.bind();
258 mSelectFramebuffer.setTexture(GL_COLOR_ATTACHMENT0, &mSelectIndexTex);
259 mSelectFramebuffer.drawBuffers(1, buffers);
260 mSelectFramebuffer.checkStatus();
261 mSelectFramebuffer.unbind();
262
263 glCheckError();
264 }
265
267 {
268 std::vector<RenderItem> items;
269 for (auto iter = scene->begin(); iter != scene->end(); iter++) {
270 for (auto m : iter->graphicsPipeline()->activeModules()) {
271 if (auto vm = std::dynamic_pointer_cast<GLVisualModule>(m))
272 items.push_back({ iter.get(), vm });
273 }
274 }
275
276 // release GL resource for unreferenced visual module
277 for (auto item : mRenderItems) {
278 if (std::find(items.begin(), items.end(), item) == items.end())
279 item.visualModule->release();
280 }
281 mRenderItems = items;
282 }
283
285 {
287
288 // preserve current framebuffer
289 GLint fbo;
290 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
291
292 // resize internal framebuffer
293 GLint samples;
294 glGetFramebufferParameteriv(GL_FRAMEBUFFER, GL_SAMPLES, &samples);
295 if (bEnableFXAA) {
296 // if FXAA is enabled, we use 1 spp internal framebuffer
297 resizeFramebuffer(rparams.width, rparams.height, 1);
298 }
299 else if (samples > 0) {
300 // external framebuffer MSAA is enabled,
301 resizeFramebuffer(rparams.width, rparams.height, samples);
302 }
303 else {
304 // target framebuffer is non-multisample, and FXAA is disabled...
305 resizeFramebuffer(rparams.width, rparams.height, mMSAASamples);
306 }
307
308 // update shadow map
309 mShadowMap->update(scene, rparams);
310
311 // copy
312 RenderParams params = rparams;
313 // TODO: we might use world space
314 params.light.mainLightDirection = glm::normalize(glm::vec3(
315 params.transforms.view * glm::vec4(params.light.mainLightDirection, 0)));
316
317 // bind internal framebuffer for rendering
318 mFramebuffer.bind(GL_DRAW_FRAMEBUFFER);
319
320 // attachement 0: color, attachment 1: index
321 const unsigned int attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
322 mFramebuffer.drawBuffers(2, attachments);
323
324 // clear color and depth
325 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
326 glViewport(0, 0, rparams.width, rparams.height);
327
328 // Step 1: draw background color, it also clears index buffer...
329 {
330 mRenderHelper->drawBackground(
331 Vec3f(this->bgColor0.x, this->bgColor0.y, this->bgColor0.z),
332 Vec3f(this->bgColor1.x, this->bgColor1.y, this->bgColor1.z));
333 }
334
335 //
336 if(bDrawEnvmap) {
337 mEnvmap->draw(params);
338 }
339
340 // clear index buffer
341 GLint clearIndex[] = { -1, -1, -1, -1 };
342 glClearBufferiv(GL_COLOR, 1, clearIndex);
343 glCheckError();
344
345 mShadowMap->bind();
346
347 mEnvmap->setScale(enmapScale);
348 mEnvmap->bindIBL();
349
350 // Step 2: render opacity objects
351 {
352 params.mode = GLRenderMode::COLOR;
353
354 for (int i = 0; i < mRenderItems.size(); i++)
355 {
356 if (mRenderItems[i].node->isVisible() && !mRenderItems[i].visualModule->isTransparent())
357 {
358 params.index = i;
359 mRenderItems[i].visualModule->draw(params);
360 }
361 }
362 }
363
364 // Step 3: draw a ground grid (xy-plane)
365 // since the grid is transparent, we handle it between opacity and transparent objects
366 if (this->showGround)
367 {
368 float unitScale = rparams.unitScale;
369 // only draw to color buffer, so we can pick through
370 mFramebuffer.drawBuffers(1, attachments);
371 mRenderHelper->drawGround(params,
372 this->planeScale * unitScale, this->rulerScale * unitScale,
373 Vec4f(this->planeColor.r, this->planeColor.g, this->planeColor.b, this->planeColor.a),
374 Vec4f(this->rulerColor.r, this->rulerColor.g, this->rulerColor.b, this->rulerColor.a));
375 }
376
377 // Step 4: transparency objects
378 {
379 // reset free node index
380 const int zero = 0;
381 mFreeNodeIdx.load((void*)&zero, sizeof(int));
382
383 // reset head index
384 const int clear = 0xFFFFFFFF;
385 mHeadIndexTex.clear((void*)&clear);
386
387 // binding...
388 glBindImageTexture(0, mHeadIndexTex.id, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI);
389 mFreeNodeIdx.bindBufferBase(0);
390 mLinkedListBuffer.bindBufferBase(0);
391
392 // draw to no attachments
393 mFramebuffer.drawBuffers(0, 0);
394
395 // OIT: first pass
396 glDepthMask(false);
398 for (int i = 0; i < mRenderItems.size(); i++)
399 {
400 if (mRenderItems[i].node->isVisible() && mRenderItems[i].visualModule->isTransparent())
401 {
402 params.index = i;
403 mRenderItems[i].visualModule->draw(params);
404 }
405 }
406 glDepthMask(true);
407
408 // OIT: blend alpha
409 mFramebuffer.drawBuffers(2, attachments);
410 mBlendProgram->use();
411 glDisable(GL_DEPTH_TEST);
412 glEnable(GL_BLEND);
413 glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
414 mScreenQuad->draw();
415 glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
416 glDisable(GL_BLEND);
417 glEnable(GL_DEPTH_TEST);
418 }
419
420 // Step 5: scene bounding box
421 if (this->showSceneBounds && scene != 0)
422 {
423 mFramebuffer.drawBuffers(1, attachments);
424 // get bounding box of the scene
425 auto p0 = scene->getLowerBound();
426 auto p1 = scene->getUpperBound();
427 mRenderHelper->drawBBox(params, p0, p1);
428 }
429
430 // Step 6: draw to final framebuffer with fxaa filter
431 {
432 // restore previous framebuffer
433 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
434
435 if (bEnableFXAA)
436 {
437 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
438 glViewport(0, 0, rparams.width, rparams.height);
439
440 mColorTex.bind(GL_TEXTURE1);
441 mDepthTex.bind(GL_TEXTURE2);
442 mFXAAFilter->apply(rparams.width, rparams.height);
443 }
444 else
445 {
446 mFramebuffer.bind(GL_READ_FRAMEBUFFER);
447 glReadBuffer(GL_COLOR_ATTACHMENT0);
448 glBlitFramebuffer(
449 0, 0, rparams.width, rparams.height,
450 0, 0, rparams.width, rparams.height,
451 GL_COLOR_BUFFER_BIT, GL_LINEAR);
452 }
453 }
454
455 glCheckError();
456 }
457
458
459 void GLRenderEngine::resizeFramebuffer(int w, int h, int samples)
460 {
461 // resize internal framebuffer
462 mColorTex.resize(w, h, samples);
463 mDepthTex.resize(w, h, samples);
464 mIndexTex.resize(w, h, samples);
465 mHeadIndexTex.resize(w, h, samples);
466
467 mSelectIndexTex.resize(w, h);
468
469 glCheckError();
470 }
471
472 std::string GLRenderEngine::name() const
473 {
474 return std::string("Native OpenGL");
475 }
476
477 Selection GLRenderEngine::select(int x, int y, int w, int h)
478 {
479 // TODO: check valid input
480 w = std::max(1, w);
481 h = std::max(1, h);
482
483 // save current framebuffer binding
484 GLint fbo;
485 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
486
487 // blit multisample framebuffer to regular framebuffer
488 mFramebuffer.bind(GL_READ_FRAMEBUFFER);
489 mSelectFramebuffer.bind(GL_DRAW_FRAMEBUFFER);
490 glReadBuffer(GL_COLOR_ATTACHMENT1);
491 glDrawBuffer(GL_COLOR_ATTACHMENT0);
492 glBlitFramebuffer(x, y, x+w, y+h, x, y, x+w, y+h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
493
494 // read pixels
495 std::vector<glm::ivec4> indices(w * h);
496
497 mSelectFramebuffer.bind(GL_READ_FRAMEBUFFER);
498 glReadBuffer(GL_COLOR_ATTACHMENT0);
499 //glPixelStorei(GL_PACK_ALIGNMENT, 1);
500 glReadPixels(x, y, w, h, GL_RGBA_INTEGER, GL_INT, indices.data());
501
502 // restore current framebuffer binding
503 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
504
505 glCheckError();
506
507 // use unordered set to get unique id
508 std::unordered_set<glm::ivec4> uniqueIdx(indices.begin(), indices.end());
509
510 Selection result;
511 result.x = x;
512 result.y = y;
513 result.w = w;
514 result.h = h;
515
516 for (const auto& idx : uniqueIdx) {
517 const int nodeIdx = idx.x;
518 const int instIdx = idx.y;
519 const int primIdx = idx.z;
520
521 if (nodeIdx >= 0 && nodeIdx < mRenderItems.size()) {
522 result.items.push_back({mRenderItems[nodeIdx].node, instIdx, primIdx});
523 }
524 }
525
526 return result;
527 }
528
529 void GLRenderEngine::setMSAA(int samples)
530 {
531 // [0, 8]
532 if (samples < 0) samples = 0;
533 if (samples > 8) samples = 8;
534 mMSAASamples = samples;
535 }
536
538 {
539 return mMSAASamples;
540 }
541
543 {
544 bEnableFXAA = flag;
545 }
546
548 {
549 return bEnableFXAA;
550 }
551
552}
#define glCheckError()
GLRenderHelper * mRenderHelper
Texture2DMultiSample mColorTex
Texture2DMultiSample mHeadIndexTex
void setShadowBlurIters(int iters)
std::string mEnvmapFilePath
virtual void draw(dyno::SceneGraph *scene, const RenderParams &rparams) override
virtual void initialize() override
void setDefaultEnvmap() override
virtual void terminate() override
Framebuffer mSelectFramebuffer
void setMSAA(int samples)
void setEnvStyle(EEnvStyle style) override
Selection select(int x, int y, int w, int h) override
void setEnvmap(const std::string &path)
std::vector< RenderItem > mRenderItems
void resizeFramebuffer(int w, int h, int samples)
Texture2DMultiSample mIndexTex
void setFXAA(bool flag)
void updateRenderItems(dyno::SceneGraph *scene)
virtual std::string name() const override
void setShadowMapSize(int size)
Texture2DMultiSample mDepthTex
static Mesh * ScreenQuad()
Definition Mesh.cpp:134
static Program * createProgramSPIRV(const void *vs, size_t vs_len, const void *fs, size_t fs_len, const void *gs=0, size_t gs_len=0)
Definition Shader.cpp:202
void setUseEnvmapBackground(bool flag)
void setEnvmapScale(float scale)
This is an implementation of AdditiveCCD based on peridyno.
Definition Array.h:25
@ Standard
int scene
Definition GltfFunc.h:20
Vector< float, 4 > Vec4f
Definition Vector4D.h:86
Vector< float, 3 > Vec3f
Definition Vector3D.h:93
static const int COLOR
static const int TRANSPARENCY
struct dyno::RenderParams::Light light
struct dyno::RenderParams::Transform transforms
std::vector< Item > items