From dfc4c718e8870d4630ac534781f9d7105a00846f Mon Sep 17 00:00:00 2001 From: peri4 Date: Thu, 25 May 2023 15:50:07 +0300 Subject: [PATCH] version 1.2.1 spot light without shadows and with texture fix mesh information points width and points-only meshes support --- CMakeLists.txt | 2 +- src/core/core/glmesh.cpp | 26 +++++++-- src/core/render/renderer.cpp | 34 +++++++---- src/core/render/renderer.h | 1 + src/core/scene/globject.h | 2 +- src/core/view/qglview.cpp | 2 + src/icons/dialog-information.png | Bin 0 -> 36295 bytes src/widgets/materials_editor.cpp | 3 + src/widgets/scene_tree.cpp | 34 ++++++++++- src/widgets/scene_tree.h | 2 + src/widgets/scene_tree.ui | 25 +++++--- src/widgets/view_editor.cpp | 7 +++ src/widgets/view_editor.h | 1 + src/widgets/view_editor.ui | 96 ++++++++++++++++++++++--------- src/widgets/widgets.qrc | 1 + 15 files changed, 180 insertions(+), 56 deletions(-) create mode 100644 src/icons/dialog-information.png diff --git a/CMakeLists.txt b/CMakeLists.txt index 7612c35..80ff3cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ else() set(QGLEngine_MAJOR 1) set(QGLEngine_MINOR 2) - set(QGLEngine_REVISION 0) + set(QGLEngine_REVISION 1) set(QGLEngine_SUFFIX "rc") set(QGLEngine_COMPANY SHS) set(QGLEngine_DOMAIN org.SHS) diff --git a/src/core/core/glmesh.cpp b/src/core/core/glmesh.cpp index 585b7d7..64d591a 100644 --- a/src/core/core/glmesh.cpp +++ b/src/core/core/glmesh.cpp @@ -172,12 +172,24 @@ bool Mesh::rebuffer(QOpenGLExtraFunctions * f) { buffer_geom.load(f, data_.constData(), gsize); buffer_ind.bind(f); - if (geom_type == GL_TRIANGLES) { + switch (geom_type) { + case GL_TRIANGLES: buffer_ind.resize(f, tsize); buffer_ind.load(f, triangles_.constData(), tsize); - } else { + break; + case GL_LINES: buffer_ind.resize(f, lsize); buffer_ind.load(f, lines_.constData(), lsize); + break; + case GL_POINTS: { + QVector points; + points.resize(vertices_.size()); + for (int i = 0; i < vertices_.size(); ++i) + points[i] = i; + int psize = points.size() * sizeof(GLint); + buffer_ind.resize(f, psize); + buffer_ind.load(f, points.constData(), psize); + } break; } return !isEmpty(); @@ -192,10 +204,12 @@ void Mesh::draw(QOpenGLExtraFunctions * f, int count, int type) { VertexObject * vao = vaoByType(type); vao->bindBuffers(f, buffer_geom, buffer_ind); - if (geom_type == GL_TRIANGLES) - vao->draw(f, geom_type, triangles_.size() * 3, count); - else - vao->draw(f, geom_type, lines_.size() * 2, count); + switch (geom_type) { + case GL_TRIANGLES: vao->draw(f, geom_type, triangles_.size() * 3, count); break; + case GL_LINES: vao->draw(f, geom_type, lines_.size() * 2, count); break; + case GL_POINTS: vao->draw(f, geom_type, vertices_.size(), count); break; + default: break; + } } diff --git a/src/core/render/renderer.cpp b/src/core/render/renderer.cpp index c6fce3a..7bb0411 100644 --- a/src/core/render/renderer.cpp +++ b/src/core/render/renderer.cpp @@ -304,6 +304,24 @@ void Renderer::fillObjectsBuffer(const ObjectBaseList & ol, RenderPass pass) { } +void Renderer::setConeShadowMatrix() { + auto cone_ll = cur_lights.value(Light::Cone); + for (int i = 0; i < cone_ll.size(); ++i) { + Light * l = cone_ll[i]; + QMatrix4x4 pm = glMatrixPerspective(l->angle_end, 1., 0.1), om, vm; + om.translate(-l->worldAim()); + vm.translate(0., 0., -l->distance()); + // vm.rotate(-roll_, 0., 0., 1.); + QMatrix4x4 pmat = l->worldTransform(); + pmat(0, 3) = pmat(1, 3) = pmat(2, 3) = 0.; + vm *= pmat.inverted(); + auto vpm = pm * (vm * om); + l->view_proj_matrix = vpm; + l->shadow_matrix = mat_norm_to_tex_coord * vpm * mat_camera_fullview_inv; + } +} + + void Renderer::renderObjects(Scene & scene, RenderPass pass) { QOpenGLExtraFunctions * f = view; QMapIterator it(scene.geometries_used[pass]); @@ -403,20 +421,11 @@ void Renderer::renderConeShadows() { } depth_maps_cone.resize(f, view->shadow_map_size, cone_ll.size()); for (int i = 0; i < cone_ll.size(); ++i) { - Light * l = cone_ll[i]; - QMatrix4x4 pm = glMatrixPerspective(l->angle_end, 1., 0.1), om, vm; - om.translate(-l->worldAim()); - vm.translate(0., 0., -l->distance()); - // vm.rotate(-roll_, 0., 0., 1.); - QMatrix4x4 pmat = l->worldTransform(); - pmat(0, 3) = pmat(1, 3) = pmat(2, 3) = 0.; - vm *= pmat.inverted(); - auto vpm = pm * (vm * om); + Light * l = cone_ll[i]; if (l->isCastShadows()) { - prog->setUniformValue("qgl_ViewProjMatrix", vpm); + prog->setUniformValue("qgl_ViewProjMatrix", l->view_proj_matrix); renderConeShadow(i, l); } - l->shadow_matrix = mat_norm_to_tex_coord * vpm * mat_camera_fullview_inv; } } } @@ -533,6 +542,9 @@ void Renderer::renderScene() { } phase.end(); + /// setup cone lights matrices + setConeShadowMatrix(); + if (view->shadows()) { /// cone shadows and shadow matrix phase.begin("shadows cone"); diff --git a/src/core/render/renderer.h b/src/core/render/renderer.h index cf1dbc8..6f36c42 100644 --- a/src/core/render/renderer.h +++ b/src/core/render/renderer.h @@ -116,6 +116,7 @@ public: protected: void fillObjectsBuffer(const ObjectBaseList & ol, RenderPass pass); + void setConeShadowMatrix(); void renderObjects(Scene & scene, RenderPass pass); void renderLight(int first_wr_buff, bool clear_only); void renderConeShadows(); diff --git a/src/core/scene/globject.h b/src/core/scene/globject.h index de1050b..9cd6ed6 100644 --- a/src/core/scene/globject.h +++ b/src/core/scene/globject.h @@ -319,7 +319,7 @@ public: float size; Type light_type; Framebuffer shadow_map; - QMatrix4x4 shadow_matrix; + QMatrix4x4 shadow_matrix, view_proj_matrix; Map light_map; }; diff --git a/src/core/view/qglview.cpp b/src/core/view/qglview.cpp index a7d82e2..a0a41cf 100644 --- a/src/core/view/qglview.cpp +++ b/src/core/view/qglview.cpp @@ -163,6 +163,8 @@ void QGLView::render() { if (!framebuffer_size.isEmpty()) render_size = framebuffer_size; resizeGL(render_size.width(), render_size.height()); emit glBeginPaint(); + glPointSize(lineWidth_); + glLineWidth(lineWidth_); QSizeF fbo_sz = renderer_.fbo_ds.size(); renderer_.rend_selection.size_coeff = {double(fbo_sz.width()) / pixelWidth(), double(fbo_sz.height()) / pixelHeight()}; renderer_.mouse_pos = mapFromGlobal(QCursor::pos()) * devicePixelRatio(); diff --git a/src/icons/dialog-information.png b/src/icons/dialog-information.png new file mode 100644 index 0000000000000000000000000000000000000000..dfe70b992a47ab17ca33f5851f59edce5f083177 GIT binary patch literal 36295 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 IM6N<$fcomboMaterial->blockSignals(true); ui->comboMaterial->clear(); if (!view) return; QVector mats = view->scene()->getMaterials(); @@ -128,6 +129,8 @@ void MaterialsEditor::materialsChanged() { ui->comboMaterial->setItemIcon(i, QIcon(QPixmap::fromImage(view->materialThumbnail(m)))); if (cm == m) ui->comboMaterial->setCurrentIndex(i); } + ui->comboMaterial->blockSignals(false); + if (currentMaterial() != cm) on_comboMaterial_currentIndexChanged(ui->comboMaterial->currentIndex()); } diff --git a/src/widgets/scene_tree.cpp b/src/widgets/scene_tree.cpp index 2c450e1..559ee88 100644 --- a/src/widgets/scene_tree.cpp +++ b/src/widgets/scene_tree.cpp @@ -19,11 +19,13 @@ #include "scene_tree.h" #include "glcamera.h" +#include "glmesh.h" #include "qglview.h" #include "ui_scene_tree.h" #include #include +#include #include #include #include @@ -110,9 +112,9 @@ QList SceneTree::actionsAdd() { QList SceneTree::actionsSelection() { QList ret; ret << ui->actionFocus << newSeparator() << ui->actionGroup << ui->actionClone << newSeparator() << ui->actionSelect_parent - << ui->actionSelect_by_mesh << ui->actionSelect_by_material << newSeparator() << ui->actionMove_to_parent - << ui->actionTransfer_transform_to_children << newSeparator() << ui->actionActive_camera << ui->actionDefault_camera - << newSeparator() << ui->actionRemove; + << ui->actionSelect_by_mesh << ui->actionSelect_by_material << newSeparator() << ui->actionMesh_info << newSeparator() + << ui->actionMove_to_parent << ui->actionTransfer_transform_to_children << newSeparator() << ui->actionActive_camera + << ui->actionDefault_camera << newSeparator() << ui->actionRemove; return ret; } @@ -310,6 +312,7 @@ void SceneTree::checkActions() { ui->actionSelect_parent->setEnabled(has_1); ui->actionSelect_by_mesh->setEnabled(has_mesh); ui->actionSelect_by_material->setEnabled(has_mesh); + ui->actionMesh_info->setEnabled(has_mesh); ui->actionActive_camera->setEnabled(has_cam); ui->actionDefault_camera->setEnabled(!is_def_cam); } @@ -507,6 +510,31 @@ void SceneTree::on_actionSelect_by_material_triggered() { } +void SceneTree::on_actionMesh_info_triggered() { + if (!view) return; + ObjectBaseList sol = view->scene()->selectedObjects(true); + for (auto o: sol) { + if (o->mesh()) { + auto m = o->mesh(); + int objects = 0; + ObjectBaseList aol = view->scene()->objects(true); + for (auto i: aol) + if (i->mesh() == m) ++objects; + + auto bb = o->mesh()->boundingBox(); + QString info; + QTextStream ts(&info); + ts << "Vertices: " << m->verticesCount() << "\n"; + ts << "Triangles: " << m->trianglesCount() << "\n"; + ts << "Bounding box: " << bb.length << "x" << bb.width << "x" << bb.height << "\n"; + ts << "Objects with this mesh: " << objects << "\n"; + QMessageBox::information(nullptr, tr("Mesh info"), info); + break; + } + } +} + + void SceneTree::removeObjects() { if (!view) return; QAD::CursorOverrider curov; diff --git a/src/widgets/scene_tree.h b/src/widgets/scene_tree.h index 8375d27..4ff7dff 100644 --- a/src/widgets/scene_tree.h +++ b/src/widgets/scene_tree.h @@ -88,6 +88,8 @@ private slots: void on_actionSelect_by_mesh_triggered(); void on_actionSelect_by_material_triggered(); + void on_actionMesh_info_triggered(); + void objectsTreeChanged(); void selectionChanged(); void materialsChanged(); diff --git a/src/widgets/scene_tree.ui b/src/widgets/scene_tree.ui index 238752a..4a5549b 100644 --- a/src/widgets/scene_tree.ui +++ b/src/widgets/scene_tree.ui @@ -130,7 +130,7 @@ - + :/icons/type-camera.png:/icons/type-camera.png @@ -175,7 +175,7 @@ - + :/icons/type-geo.png:/icons/type-geo.png @@ -235,7 +235,7 @@ true - + :/icons/type-geo.png:/icons/type-geo.png @@ -247,7 +247,7 @@ true - + :/icons/type-light.png:/icons/type-light.png @@ -259,7 +259,7 @@ true - + :/icons/type-camera.png:/icons/type-camera.png @@ -273,7 +273,7 @@ - + :/icons/type-camera.png:/icons/type-camera.png @@ -282,7 +282,7 @@ - + :/icons/type-camera.png:/icons/type-camera.png @@ -298,6 +298,15 @@ Move to parent + + + + :/icons/dialog-information.png:/icons/dialog-information.png + + + Mesh info ... + + @@ -312,9 +321,9 @@ + - diff --git a/src/widgets/view_editor.cpp b/src/widgets/view_editor.cpp index 4714b4f..7ad305e 100644 --- a/src/widgets/view_editor.cpp +++ b/src/widgets/view_editor.cpp @@ -70,6 +70,7 @@ void ViewEditor::assignQGLView(QGLView * v) { ui->checkSoftShadows->setChecked(view->softShadows()); ui->spinSoftShadowSamples->setValue(view->softShadowsSamples()); ui->spinSoftShadowQuality->setValue(view->softShadowsQuality()); + ui->spinLineWidth->setValue(view->lineWidth()); auto setMapSize = [](QComboBox * combo, QSize sz) { for (int i = 0; i < combo->count(); ++i) { if (combo->itemData(i).toSize() == sz) { @@ -268,6 +269,12 @@ void ViewEditor::on_spinSoftShadowQuality_valueChanged(double arg1) { } +void ViewEditor::on_spinLineWidth_valueChanged(double v) { + if (!view || !active) return; + view->setLineWidth(v); +} + + void ViewEditor::on_checkVSync_clicked(bool val) { if (!view || !active) return; view->setVSync(val); diff --git a/src/widgets/view_editor.h b/src/widgets/view_editor.h index ffaa22f..2ad53c5 100644 --- a/src/widgets/view_editor.h +++ b/src/widgets/view_editor.h @@ -72,6 +72,7 @@ private slots: void on_checkSoftShadows_clicked(bool arg1); void on_spinSoftShadowSamples_valueChanged(double arg1); void on_spinSoftShadowQuality_valueChanged(double arg1); + void on_spinLineWidth_valueChanged(double v); }; #endif // VIEW_EDITOR_H diff --git a/src/widgets/view_editor.ui b/src/widgets/view_editor.ui index 2f39eb8..ab1029c 100644 --- a/src/widgets/view_editor.ui +++ b/src/widgets/view_editor.ui @@ -7,7 +7,7 @@ 0 0 479 - 897 + 976 @@ -37,7 +37,7 @@ 0 0 479 - 897 + 976 @@ -161,6 +161,30 @@ + + + + FXAA + + + + + + + VSync + + + true + + + + + + + Auto exposure + + + @@ -181,30 +205,6 @@ - - - - FXAA - - - - - - - Auto exposure - - - - - - - VSync - - - true - - - @@ -253,6 +253,50 @@ + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Line width: + + + + + + + 1 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + diff --git a/src/widgets/widgets.qrc b/src/widgets/widgets.qrc index 86c45f5..4fc665d 100644 --- a/src/widgets/widgets.qrc +++ b/src/widgets/widgets.qrc @@ -15,5 +15,6 @@ ../icons/group.png ../icons/legend.png ../icons/format-fill-color.png + ../icons/dialog-information.png