git-svn-id: svn://db.shs.com.ru/libs@626 a8b55f48-bf90-11e4-a774-851b48703e85
This commit is contained in:
389
qglengine/renderer.cpp
Normal file
389
qglengine/renderer.cpp
Normal file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
QGLView
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include "renderer.h"
|
||||
#include "qglview.h"
|
||||
#include "glmesh.h"
|
||||
#include "gltexture_manager.h"
|
||||
#include <qad_types.h>
|
||||
|
||||
using namespace QGLEngineShaders;
|
||||
|
||||
|
||||
Renderer::Renderer(QGLView * view_): RendererBase(view_),
|
||||
fbo_selection(view_, 4),
|
||||
fbo_ds (view_, 5, true , GL_RGBA16F),
|
||||
fbo_out (view_, 3, false, GL_RGBA16F),
|
||||
fbo_hsmall (view_, 1, false, GL_RGB16F ),
|
||||
rend_mat(this), rend_service(this) {
|
||||
quad = Primitive::plane(2., 2.);
|
||||
sel_frame = quad->clone();
|
||||
cam_light = new Light();
|
||||
cam_light->intensity = 0.75;
|
||||
cam_light->setName("Camera_Light");
|
||||
line_thick_ = 2.;
|
||||
id_hover = 0;
|
||||
|
||||
shader_files[srSelectionFill ] = "selection.glsl";
|
||||
shader_files[srSelectionHalo ] = "selection_halo.glsl";
|
||||
shader_files[srSelectionApply] = "selection_apply.glsl";
|
||||
shader_files[srSelectionFrame] = "selection_frame.glsl";
|
||||
|
||||
shader_files[srService] = "service.glsl";
|
||||
|
||||
shader_files[srGeometryPass] = "ds_geom.glsl";
|
||||
shader_files[srLightingPass] = "ds_light.glsl";
|
||||
shader_files[srFinalPass ] = "ds_final.glsl";
|
||||
|
||||
/*shaders << ShaderPair("FXAA", &shader_fxaa)
|
||||
<< ShaderPair("dsl_pass_0", &shader_ds_0)
|
||||
<< ShaderPair("dsl_pass_1", &shader_ds_1)
|
||||
<< ShaderPair("hdr", &shader_hdr)
|
||||
<< ShaderPair("downscale", &shader_small)
|
||||
<< ShaderPair("bloom_pass_0", &shader_bloom_0)
|
||||
<< ShaderPair("bloom_pass_1", &shader_bloom_1)
|
||||
<< ShaderPair("fbo_add", &shader_fbo_add)
|
||||
<< ShaderPair("motion_blur", &shader_motion_blur)
|
||||
<< ShaderPair("shadow", &shader_shadow)
|
||||
<< ShaderPair("ssr", &shader_ssr)
|
||||
<< ShaderPair("ssr_blur", &shader_ssr_blur)
|
||||
<< ShaderPair("ssr_merge", &shader_ssr_merge)
|
||||
<< ShaderPair("ssao_blur", &shader_ssao_blur)
|
||||
<< ShaderPair("ssao_merge", &shader_ssao_merge)
|
||||
<< ShaderPair("dof", &shader_dof);*/
|
||||
exposure_ = 1.;
|
||||
edit_mode = need_init_shaders = is_camera_light = true;
|
||||
proc_sel_pbo = false;
|
||||
}
|
||||
|
||||
|
||||
Renderer::~Renderer() {
|
||||
delete quad;
|
||||
delete sel_frame;
|
||||
delete cam_light;
|
||||
qDeleteAll(shaders.values());
|
||||
}
|
||||
|
||||
|
||||
void Renderer::init(int width, int height) {
|
||||
resize(width, height);
|
||||
rend_mat.init(width, height);
|
||||
rend_service.init(width, height);
|
||||
initQuad(quad);
|
||||
initTextureArrays();
|
||||
need_init_shaders = true;
|
||||
}
|
||||
|
||||
|
||||
void Renderer::resize(int width, int height) {
|
||||
rend_mat.resize(width, height);
|
||||
rend_service.resize(width, height);
|
||||
fbo_selection.enablePixelBuffer();
|
||||
fbo_selection.resize(width, height);
|
||||
fbo_ds .resize(width, height);
|
||||
fbo_out .resize(width, height);
|
||||
fbo_hsmall .resize(width / 16, height / 16);
|
||||
line_thick_ = lineThickness() + 1.;
|
||||
}
|
||||
|
||||
|
||||
void Renderer::reloadShaders() {
|
||||
QMapIterator<ShaderRole, QString> it(shader_files);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
loadShadersMulti(shaders[it.key()], "shaders/" + it.value());
|
||||
}
|
||||
need_init_shaders = true;
|
||||
}
|
||||
|
||||
|
||||
bool Renderer::bindShader(Renderer::ShaderRole role, QOpenGLShaderProgram ** ret) {
|
||||
QOpenGLShaderProgram * prog = shaders.value(role);
|
||||
if (ret) *ret = prog;
|
||||
if (!prog) return false;
|
||||
if (!prog->isLinked()) return false;
|
||||
prog->bind();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Renderer::initShaders() {
|
||||
if (!need_init_shaders) return;
|
||||
need_init_shaders = false;
|
||||
initUniformBuffer(shaders.value(srGeometryPass), &buffer_materials , bpMaterials , "QGLMaterialData" );
|
||||
initUniformBuffer(shaders.value(srLightingPass), &buffer_materials , bpMaterials , "QGLMaterialData" );
|
||||
initUniformBuffer(shaders.value(srLightingPass), &buffer_lights , bpLightParameters, "QGLLightParameterData");
|
||||
initUniformBuffer(shaders.value(srLightingPass), &buffer_lights_pos, bpLightPositions , "QGLLightPositionData" );
|
||||
}
|
||||
|
||||
|
||||
void Renderer::releaseShader() {
|
||||
view->glUseProgram(0);
|
||||
}
|
||||
|
||||
|
||||
void Renderer::generateObjectsID(Scene & scene) {
|
||||
ids.clear();
|
||||
QMapIterator<Mesh*, QList<ObjectBase*> > it(scene.geometries_used);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
foreach (ObjectBase * o, it.value()) {
|
||||
uint id = qHash(o);
|
||||
ids[id] = o;
|
||||
o->id_ = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Renderer::fillSelectionsBuffer(const QList<ObjectBase *> & ol) {
|
||||
cur_selections_.resize(ol.size());
|
||||
for (int i = 0; i < ol.size(); ++i) {
|
||||
cur_selections_[i] = (ol[i]->isSelected(true) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Renderer::fillObjectsBuffer(const QList<ObjectBase *> & ol, RenderPass pass) {
|
||||
cur_objects_.resize(ol.size());
|
||||
for (int i = 0; i < ol.size(); ++i) {
|
||||
Object & so(cur_objects_[i]);
|
||||
ObjectBase * o = ol[i];
|
||||
if (o->material()) {
|
||||
so.material = o->material()->_index;
|
||||
so.color = QVector4D(1,1,1,1);
|
||||
} else {
|
||||
so.material = 0;
|
||||
so.color = QColor2QVector(o->color_);
|
||||
}
|
||||
so.object_id = o->id_;
|
||||
o->worldTransform().transposed().copyDataTo(so.modelmatrix);
|
||||
//qDebug() << "load obj" << o->name() << o->worldTransform();
|
||||
}
|
||||
//qDebug() << "fillObjectsBuffer" << ol.size();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Renderer::renderObjects(Scene & scene, RenderPass pass) {
|
||||
QOpenGLExtraFunctions * f = view;
|
||||
QMapIterator<Mesh*, QList<ObjectBase*> > it(scene.geometries_used);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
Mesh * mesh = it.key();
|
||||
if (mesh->objects_changed) {
|
||||
mesh->objects_changed = false;
|
||||
fillObjectsBuffer(it.value(), pass);
|
||||
mesh->loadObjects(f, cur_objects_);
|
||||
}
|
||||
if (mesh->selected_changed && edit_mode) {
|
||||
mesh->selected_changed = false;
|
||||
fillSelectionsBuffer(it.value());
|
||||
mesh->loadSelections(f, cur_selections_);
|
||||
}
|
||||
mesh->draw(f, it.value().size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Renderer::renderSelection(Scene & scene) {
|
||||
QOpenGLShaderProgram * prog = 0;
|
||||
if (bindShader(srSelectionFill, &prog)) {
|
||||
view->hov_objects.clear();
|
||||
id_hover = 0;
|
||||
if (fbo_selection.queriedPoints() > 0) {
|
||||
if (fbo_selection.queriedPoints() == 1) {
|
||||
id_hover = fbo_selection.getPoint();
|
||||
view->hov_objects.resize(1);
|
||||
view->hov_objects[0] = ids.value(id_hover);
|
||||
//qDebug() << id_hover;
|
||||
} else {
|
||||
QVector<uint> points = fbo_selection.getPoints();
|
||||
QSet<uint> ids_hover;
|
||||
foreach (uint i, points)
|
||||
ids_hover << i;
|
||||
view->hov_objects.clear();
|
||||
foreach (uint i, ids_hover)
|
||||
view->hov_objects << ids.value(i);
|
||||
//qDebug() << ids_hover;
|
||||
}
|
||||
}
|
||||
|
||||
fbo_selection.bind();
|
||||
|
||||
fbo_selection.setWriteBuffers();
|
||||
glEnableDepth();
|
||||
glClearFramebuffer(QColor(0,0,0,0));
|
||||
setUniformCamera(prog, view->camera());
|
||||
renderObjects(scene, rpSelection);
|
||||
//mouse_rect = fbo_selection.rect();
|
||||
if (mouse_rect.isNull())
|
||||
fbo_selection.queryPoint(0, mouse_pos);
|
||||
else
|
||||
fbo_selection.queryPoints(0, mouse_rect);
|
||||
|
||||
//qDebug() << id_hover;
|
||||
fbo_selection.bindColorTextures();
|
||||
fbo_selection.setWriteBuffers();
|
||||
if (!view->hoverHalo_ && !view->selectionHalo_)
|
||||
glClearFramebuffer(QColor(0,0,0,0), false);
|
||||
else {
|
||||
bindShader(srSelectionHalo, &prog);
|
||||
setUniformHalo(prog, "hover" , view->hoverHaloColor() , view->hoverHaloFillAlpha());
|
||||
setUniformHalo(prog, "selection", view->selectionHaloColor(), view->selectionHaloFillAlpha());
|
||||
prog->setUniformValue("has_hover" , view->hoverHalo_ && (id_hover > 0) ? 1.f : 0.f);
|
||||
prog->setUniformValue("has_selection", view->selectionHalo_ ? 1.f : 0.f);
|
||||
prog->setUniformValue("fb_hover" , (int)sbrSrcHover);
|
||||
prog->setUniformValue("fb_selection", (int)sbrSrcSelect);
|
||||
prog->setUniformValue("hover_id", QVector4D(float( id_hover & 0xFF) / 255.f,
|
||||
float((id_hover >> 8 ) & 0xFF) / 255.f,
|
||||
float((id_hover >> 16) & 0xFF) / 255.f,
|
||||
float((id_hover >> 24) & 0xFF) / 255.f));
|
||||
renderQuad(prog, quad, view->camera());
|
||||
}
|
||||
|
||||
fbo_selection.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Renderer::renderSelectionFrame() {
|
||||
QOpenGLShaderProgram * prog = 0;
|
||||
if (bindShader(srSelectionFrame, &prog)) {
|
||||
QMatrix4x4 mat;
|
||||
double mrx = mouse_rect.x(), mrw = mouse_rect.width() , vw = view->width();
|
||||
double mry = mouse_rect.y(), mrh = mouse_rect.height(), vh = view->height();
|
||||
mat.translate(-1. + (mrw + mrx*2) / vw, 1. - (mrh + mry*2) / vh, 0.);
|
||||
mat.scale(mrw / vw, mrh / vh, 0.);
|
||||
initQuad(sel_frame, mat);
|
||||
prog->setUniformValue("size", QVector2D(mrw / vw, mrh / vh));
|
||||
prog->setUniformValue("thickness", line_thick_);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
renderQuad(prog, sel_frame);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Renderer::renderScene() {
|
||||
initShaders();
|
||||
QOpenGLExtraFunctions * f = view;
|
||||
Scene & scene(*(view->scene_));
|
||||
Camera * cam = view->camera();
|
||||
QOpenGLShaderProgram * prog = 0;
|
||||
bool scene_changed = scene.prepare();
|
||||
|
||||
/// reload materials on change
|
||||
if (scene_changed || scene.need_reload_materials) {
|
||||
if (scene.need_reload_materials)
|
||||
maps_hash = 0;
|
||||
generateObjectsID(scene);
|
||||
reloadMaterials(scene);
|
||||
if (edit_mode)
|
||||
recreateMaterialThumbnails();
|
||||
emit view->materialsChanged();
|
||||
}
|
||||
|
||||
/// material thumbnails
|
||||
if (edit_mode && !scene_changed) {
|
||||
rend_mat.procQueue();
|
||||
}
|
||||
|
||||
/// lights
|
||||
QList<Light*> ll = scene.lights_used;
|
||||
if (is_camera_light) {
|
||||
ll << cam_light;
|
||||
cam_light->setPos(cam->pos());
|
||||
}
|
||||
if (scene.lights_changed) {
|
||||
scene.lights_changed = false;
|
||||
reloadLightsParameters(ll);
|
||||
}
|
||||
reloadLightsPositions(ll, cam);
|
||||
|
||||
/// selection
|
||||
if (edit_mode) {
|
||||
renderSelection(scene);
|
||||
}
|
||||
|
||||
/// geometry pass
|
||||
fbo_ds.bind();
|
||||
glEnableDepth();
|
||||
glClearFramebuffer();
|
||||
if (bindShader(srGeometryPass, &prog)) {
|
||||
setUniformMaps(prog);
|
||||
setUniformCamera(prog, cam);
|
||||
textures_empty.bind(f, tarEmpty);
|
||||
textures_maps .bind(f, tarMaps );
|
||||
renderObjects(scene, rpSolid);
|
||||
}
|
||||
fbo_ds.release();
|
||||
|
||||
/// lighting pass
|
||||
fbo_ds.bindColorTextures();
|
||||
fbo_ds.bindDepthTexture(5);
|
||||
fbo_out.bind();
|
||||
if (bindShader(srLightingPass, &prog)) {
|
||||
setUniformCamera(prog, cam);
|
||||
setUniformViewCorners(prog, cam);
|
||||
for (int i = 0; i < 5; ++i)
|
||||
prog->setUniformValue(QString("tex_%1").arg(i).toLatin1().constData(), i);
|
||||
prog->setUniformValue("tex_d", 5);
|
||||
prog->setUniformValue("lights_count", ll.size());
|
||||
glClearFramebuffer(view->backColor(), false);
|
||||
renderQuad(prog, quad, cam);
|
||||
/*QVector<float> _fb = fbo_out.grabF(0);
|
||||
if (!_fb.isEmpty()) {
|
||||
double sum = 0.;
|
||||
foreach (float f, _fb) sum += f;
|
||||
sum /= _fb.size();
|
||||
qDebug() << "sum =" << sum;
|
||||
}*/
|
||||
}
|
||||
fbo_out.release();
|
||||
|
||||
/// apply hovers and selection frame
|
||||
if (edit_mode) {
|
||||
if (bindShader(srSelectionApply, &prog)) {
|
||||
fbo_selection.bindColorTextures();
|
||||
fbo_out.bindColorTexture(0);
|
||||
prog->setUniformValue("fb_out" , 0);
|
||||
prog->setUniformValue("fb_hover" , (int)sbrHovered );
|
||||
prog->setUniformValue("fb_select", (int)sbrSelected);
|
||||
renderQuad(prog, quad, cam);
|
||||
|
||||
if (!mouse_rect.isNull()) {
|
||||
renderSelectionFrame();
|
||||
}
|
||||
|
||||
rend_service.renderService();
|
||||
}
|
||||
} else {
|
||||
fbo_out.blit(0, 0, 0, fbo_out.rect(), QRect(QPoint(), view->size()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Renderer::setCameraLightOn(bool on) {
|
||||
is_camera_light = on;
|
||||
view->scene()->setLightsChanged();
|
||||
}
|
||||
Reference in New Issue
Block a user