diff --git a/CMakeLists.txt b/CMakeLists.txt index d1b4ec83b..e027c7551 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,7 @@ option(WITH_AUDIO_EXAMPLE "Build audio example (requires Magnum Audio library)" option(WITH_BULLET_EXAMPLE "Build Bullet integration example (requires BulletIntegration library)" OFF) cmake_dependent_option(WITH_CUBEMAP_EXAMPLE "Build CubeMap example (requires JpegImporter plugin)" OFF "NOT MAGNUM_TARGET_GLES" OFF) cmake_dependent_option(WITH_MOTIONBLUR_EXAMPLE "Build MotionBlur example" OFF "NOT MAGNUM_TARGET_GLES" OFF) +option(WITH_OCTREE_EXAMPLE "Build Octree: example" OFF) option(WITH_OVR_EXAMPLE "Build OVR example" OFF) option(WITH_PICKING_EXAMPLE "Build Picking example" OFF) option(WITH_PRIMITIVES_EXAMPLE "Build Primitives example" OFF) diff --git a/modules/FindMagnumExtras.cmake b/modules/FindMagnumExtras.cmake new file mode 100644 index 000000000..838850b71 --- /dev/null +++ b/modules/FindMagnumExtras.cmake @@ -0,0 +1,210 @@ +#.rst: +# Find Magnum extras +# ------------------ +# +# Finds Magnum extras. Basic usage:: +# +# find_package(MagnumExtras REQUIRED) +# +# This command tries to find Magnum extras and then defines the following: +# +# MagnumExtras_FOUND - Whether Magnum extras were found +# +# This command alone is useless without specifying the components: +# +# Octree - Octree BSP structure for Magnum::SceneGraph +# +# Example usage with specifying additional components is: +# +# find_package(MagnumExtras REQUIRED SomeLibraryThatDoesntExistYet) +# +# For each component is then defined: +# +# MagnumExtras_*_FOUND - Whether the component was found +# MagnumExtras::* - Component imported target +# +# The package is found if either debug or release version of each requested +# library is found. If both debug and release libraries are found, proper +# version is chosen based on actual build configuration of the project (i.e. +# Debug build is linked to debug libraries, Release build to release +# libraries). +# +# Additionally these variables are defined for internal usage: +# +# MAGNUMEXTRAS_INCLUDE_DIR - Magnum extras include dir (w/o +# dependencies) +# MAGNUMEXTRAS_*_LIBRARY_DEBUG - Debug version of given library, if found +# MAGNUMEXTRAS_*_LIBRARY_RELEASE - Release version of given library, if +# found +# + +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016 +# Vladimír Vondruš +# Copyright © 2016 Jonathan Hale +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +# Corrade library dependencies +set(_MAGNUMEXTRAS_CORRADE_DEPENDENCIES ) + +foreach(_component ${MagnumExtras_FIND_COMPONENTS}) + string(TOUPPER ${_component} _COMPONENT) + + # (none yet) + + list(APPEND _MAGNUMEXTRAS_CORRADE_DEPENDENCIES ${_MAGNUMEXTRAS_${_COMPONENT}_CORRADE_DEPENDENCIES}) +endforeach() +find_package(Corrade REQUIRED ${_MAGNUMEXTRAS_CORRADE_DEPENDENCIES}) + +# Magnum library dependencies +set(_MAGNUMEXTRAS_MAGNUM_DEPENDENCIES ) +foreach(_component ${MagnumExtras_FIND_COMPONENTS}) + string(TOUPPER ${_component} _COMPONENT) + + if(_component MATCHES Octree) + set(_MAGNUMEXTRAS_${_COMPONENT}_MAGNUM_DEPENDENCIES Shapes) + endif() + + if(_component MATCHES SceneGraph) + set(_MAGNUMEXTRAS_${_COMPONENT}_MAGNUM_DEPENDENCIES SceneGraph) + endif() + + list(APPEND _MAGNUMEXTRAS_MAGNUM_DEPENDENCIES ${_MAGNUMEXTRAS_${_COMPONENT}_MAGNUM_DEPENDENCIES}) +endforeach() +find_package(Magnum REQUIRED ${_MAGNUMEXTRAS_MAGNUM_DEPENDENCIES}) + +# Global integration include dir +find_path(MAGNUMEXTRAS_INCLUDE_DIR Magnum + HINTS ${MAGNUM_INCLUDE_DIR}) +mark_as_advanced(MAGNUMEXTRAS_INCLUDE_DIR) + +# Ensure that all inter-component dependencies are specified as well +set(_MAGNUMEXTRAS_ADDITIONAL_COMPONENTS ) +foreach(_component ${MagnumExtras_FIND_COMPONENTS}) + string(TOUPPER ${_component} _COMPONENT) + + # (no inter-component dependencies yet) + if(_component MATCHES SceneGraph) + set(_MAGNUMEXTRAS_${_COMPONENT}_DEPENDENCIES Octree) + endif() + + # Mark the dependencies as required if the component is also required + if(MagnumExtras_FIND_REQUIRED_${_component}) + foreach(_dependency ${}) + set(MagnumExtras_FIND_REQUIRED_${_dependency} TRUE) + endforeach() + endif() + + list(APPEND _MAGNUMEXTRAS_ADDITIONAL_COMPONENTS ${_MAGNUMEXTRAS_${_COMPONENT}_DEPENDENCIES}) +endforeach() + +# Join the lists, remove duplicate components +if(_MAGNUMEXTRAS_ADDITIONAL_COMPONENTS) + list(INSERT MagnumExtras_FIND_COMPONENTS 0 ${_MAGNUMEXTRAS_ADDITIONAL_COMPONENTS}) +endif() +if(MagnumExtras_FIND_COMPONENTS) + list(REMOVE_DUPLICATES MagnumExtras_FIND_COMPONENTS) +endif() + +# Component distinction (listing them explicitly to avoid mistakes with finding +# components from other repositories) +set(_MAGNUMEXTRAS_LIBRARY_COMPONENTS "(Octree|SceneGraph)") + +# Additional components +foreach(_component ${MagnumExtras_FIND_COMPONENTS}) + string(TOUPPER ${_component} _COMPONENT) + + # Create imported target in case the library is found. If the project is + # added as subproject to CMake, the target already exists and all the + # required setup is already done from the build tree. + if(TARGET MagnumExtras::${_component}) + set(MagnumExtras_${_component}_FOUND TRUE) + else() + # Library components + if(_component MATCHES ${_MAGNUMEXTRAS_LIBRARY_COMPONENTS}) + add_library(MagnumExtras::${_component} UNKNOWN IMPORTED) + + # Try to find both debug and release version + find_library(MAGNUMEXTRAS_${_COMPONENT}_LIBRARY_DEBUG Magnum${_component}-d) + find_library(MAGNUMEXTRAS_${_COMPONENT}_LIBRARY_RELEASE Magnum${_component}) + mark_as_advanced(MAGNUMEXTRAS_${_COMPONENT}_LIBRARY_DEBUG + MAGNUMEXTRAS_${_COMPONENT}_LIBRARY_RELEASE) + + if(MAGNUMEXTRAS_${_COMPONENT}_LIBRARY_RELEASE) + set_property(TARGET MagnumExtras::${_component} APPEND PROPERTY + IMPORTED_CONFIGURATIONS RELEASE) + set_property(TARGET MagnumExtras::${_component} PROPERTY + IMPORTED_LOCATION_RELEASE ${MAGNUMEXTRAS_${_COMPONENT}_LIBRARY_RELEASE}) + endif() + + if(MAGNUMEXTRAS_${_COMPONENT}_LIBRARY_DEBUG) + set_property(TARGET MagnumExtras::${_component} APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_property(TARGET MagnumExtras::${_component} PROPERTY + IMPORTED_LOCATION_DEBUG ${MAGNUMEXTRAS_${_COMPONENT}_LIBRARY_DEBUG}) + endif() + endif() + + # (none yet) + + # Find library includes + if(_component MATCHES ${_MAGNUMEXTRAS_LIBRARY_COMPONENTS}) + find_path(_MAGNUMEXTRAS_${_COMPONENT}_INCLUDE_DIR + NAMES ${_component}.h + HINTS ${MAGNUMEXTRAS_INCLUDE_DIR}/Magnum/${_component}) + endif() + + if(_component MATCHES ${_MAGNUMEXTRAS_LIBRARY_COMPONENTS}) + # Link to Corrade dependencies, link to core Magnum library and + # other Magnum dependencies + foreach(_dependency ${_MAGNUMEXTRAS_${_COMPONENT}_CORRADE_DEPENDENCIES}) + set_property(TARGET MagnumExtras::${_component} APPEND PROPERTY + INTERFACE_LINK_LIBRARIES Corrade::${_dependency}) + endforeach() + set_property(TARGET MagnumExtras::${_component} APPEND PROPERTY + INTERFACE_LINK_LIBRARIES Magnum::Magnum) + foreach(_dependency ${_MAGNUMEXTRAS_${_COMPONENT}_MAGNUM_DEPENDENCIES}) + set_property(TARGET MagnumExtras::${_component} APPEND PROPERTY + INTERFACE_LINK_LIBRARIES Magnum::${_dependency}) + endforeach() + + # Add inter-project dependencies + foreach(_dependency ${_MAGNUMEXTRAS_${_COMPONENT}_DEPENDENCIES}) + set_property(TARGET MagnumExtras::${_component} APPEND PROPERTY + INTERFACE_LINK_LIBRARIES MagnumExtras::${_dependency}) + endforeach() + endif() + + # Decide if the library was found + if(_component MATCHES ${_MAGNUMEXTRAS_LIBRARY_COMPONENTS} AND _MAGNUMEXTRAS_${_COMPONENT}_INCLUDE_DIR AND (MAGNUMEXTRAS_${_COMPONENT}_LIBRARY_DEBUG OR MAGNUMEXTRAS_${_COMPONENT}_LIBRARY_RELEASE)) + set(MagnumExtras_${_component}_FOUND TRUE) + else() + set(MagnumExtras_${_component}_FOUND FALSE) + endif() + endif() +endforeach() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MagnumExtras + REQUIRED_VARS MAGNUMEXTRAS_INCLUDE_DIR + HANDLE_COMPONENTS) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 21db93b44..9549f8afc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,6 +58,10 @@ if(WITH_MOTIONBLUR_EXAMPLE) add_subdirectory(motionblur) endif() +if(WITH_OCTREE_EXAMPLE) + add_subdirectory(octree) +endif() + if(WITH_OVR_EXAMPLE) add_subdirectory(ovr) endif() diff --git a/src/octree/CMakeLists.txt b/src/octree/CMakeLists.txt new file mode 100644 index 000000000..9202856d4 --- /dev/null +++ b/src/octree/CMakeLists.txt @@ -0,0 +1,65 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013, 2014, 2015 +# Vladimír Vondruš +# Copyright © 2015 Jonathan Hale +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +cmake_minimum_required(VERSION 2.8.12) +project(MagnumOctreeExample) + +# CMake policies: enable MACOSX_RPATH by default +if(POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) +endif() +# Don't treat imported targets with :: as files +if(POLICY CMP0028) + cmake_policy(SET CMP0028 NEW) +endif() + +find_package(Magnum REQUIRED + SceneGraph + Shaders + Primitives + Sdl2Application) + +find_package(MagnumExtras REQUIRED + Octree + SceneGraph) + + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CORRADE_CXX_FLAGS}") + +add_executable(magnum-octree OctreeExample.cpp) +target_link_libraries(magnum-octree + Magnum::Shaders + Magnum::SceneGraph + Magnum::Primitives + Magnum::Application + MagnumExtras::Octree + MagnumExtras::SceneGraph + Magnum::Magnum) + +target_compile_features(magnum-octree PRIVATE cxx_range_for) + +install(TARGETS magnum-octree DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}) +install(FILES README.md DESTINATION ${MAGNUM_DATA_INSTALL_DIR}/examples RENAME README-octree.md) diff --git a/src/octree/OctreeExample.cpp b/src/octree/OctreeExample.cpp new file mode 100644 index 000000000..ce8f6645d --- /dev/null +++ b/src/octree/OctreeExample.cpp @@ -0,0 +1,259 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015 + Vladimír Vondruš + Copyright © 2015 Andrea Capobianco + Copyright © 2015 Jonathan Hale + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Magnum { namespace Examples { + +typedef SceneGraph::Scene Scene3D; +typedef SceneGraph::Object Object3D; + +const Color3 PINK{1.0f, 0.0f, 1.0f}; +const Color3 WHITE{1.0f, 1.0f, 1.0f}; +const Color3 LIGHT_GREY{0.5f, 0.5f, 0.5f}; +const Color3 GREEN{0.0f, 0.2f, 0.0f}; + +class WireframeDrawable: public Object3D, public SceneGraph::Drawable3D { + public: + explicit WireframeDrawable(Object3D* parent, SceneGraph::DrawableGroup3D* group, Mesh& mesh, Shaders::Flat3D& shader): + Object3D{parent}, SceneGraph::Drawable3D{*this, group}, _mesh(mesh), _shader{shader} + { + } + + WireframeDrawable& setColor(const Color3& color) { + _color = color; + return *this; + } + + private: + void draw(const Matrix4& transformationMatrix, SceneGraph::Camera3D& camera) override { + _shader.setColor(_color) + .setTransformationProjectionMatrix(camera.projectionMatrix()*transformationMatrix); + _mesh.draw(_shader); + } + + Mesh& _mesh; + Shaders::Flat3D& _shader; + Color3 _color; +}; + +class OctreeExample: public Platform::Application { + public: + explicit OctreeExample(const Arguments& arguments); + + private: + void drawEvent() override; + void keyPressEvent(KeyEvent& event) override; + + void addBox(const Range3D& box); + Vector3 calculateIntersection(const Vector4& v1, const Vector4& v2, const Vector4& v3); + + void addDrawableForOctree(Octree::Octree*>& octree); + + Scene3D _scene; + Object3D _cameraObject; + Object3D _viewerObject; + Object3D _octreeObject; + SceneGraph::Camera3D _camera; /* Camera which will be culled for */ + SceneGraph::Camera3D _viewer; /* External camera */ + SceneGraph::Camera3D* _activeCamera; /* Camera from which we will render */ + + SceneGraph::OctreeDrawableGroup _culledDrawables; + SceneGraph::DrawableGroup3D _drawables; + SceneGraph::DrawableGroup3D _octreeVisualization; + + Buffer _buffer; + Mesh _mesh; + + Buffer _cubeBuffer; + Buffer _cubeIndexBuffer; + Mesh _cubeMesh; + + Shaders::Flat3D _flatShader; + + bool _visualizeOctree = true; +}; + +OctreeExample::OctreeExample(const Arguments& arguments): + Platform::Application{arguments, Configuration{}.setTitle("Magnum Octree View Frustrum Culling Example").setSampleCount(8)}, + _cameraObject(&_scene), + _viewerObject(&_scene), + _octreeObject{&_scene}, + _camera(_cameraObject), + _viewer(_viewerObject), + _activeCamera(&_viewer) +{ + Renderer::enable(Renderer::Feature::DepthTest); + + _camera.setProjectionMatrix(Matrix4::perspectiveProjection(75.0_degf, Vector2{defaultFramebuffer.viewport().size()}.aspectRatio(), 0.5f, 75.0f)); + _viewer.setProjectionMatrix(Matrix4::perspectiveProjection(75.0_degf, Vector2{defaultFramebuffer.viewport().size()}.aspectRatio(), 0.01f, 150.0f)); + + /* Setup _camera and _viewer transformation */ + _viewerObject.translate({0.0f, 10.0f, 50.0f}); + _viewerObject.rotateXLocal(Deg(-10.0f)); + + /* Create visualisation of _camera view frustum */ + const Matrix4 mvp = Matrix4(_camera.projectionMatrix()); + + // TODO: Use Frustum::fromMatrix() + const Vector4 left{mvp.row(3) + mvp.row(0)}; + const Vector4 right{mvp.row(3) - mvp.row(0)}; + const Vector4 bottom{mvp.row(3) + mvp.row(1)}; + const Vector4 top{mvp.row(3) - mvp.row(1)}; + const Vector4 near{mvp.row(3) + mvp.row(2)}; + const Vector4 far{mvp.row(3) - mvp.row(2)}; + + const Vector3 rbn = calculateIntersection(right, bottom, near); + const Vector3 lbn = calculateIntersection(left, bottom, near); + const Vector3 rtn = calculateIntersection(right, top, near); + const Vector3 ltn = calculateIntersection(left, top, near); + + const Vector3 rbf = calculateIntersection(right, bottom, far); + const Vector3 lbf = calculateIntersection(left, bottom, far); + const Vector3 rtf = calculateIntersection(right, top, far); + const Vector3 ltf = calculateIntersection(left, top, far); + + const Vector3 data[] = { + rbn, lbn, ltn, rtn, + rbn, rbf, rtf, rtn, + rtf, ltf, ltn, ltf, + lbf, lbn, lbf, rbf + }; + + _buffer.setData(data, BufferUsage::StaticDraw); + _mesh.setPrimitive(MeshPrimitive::LineStrip) + .setCount(16) + .addVertexBuffer(_buffer, 0, Shaders::Flat3D::Position{}); + + (new WireframeDrawable(&_cameraObject, &_drawables, _mesh, _flatShader))->setColor(WHITE); + + Trade::MeshData3D cubeData = Primitives::Cube::wireframe(); + _cubeBuffer.setData(cubeData.positions(0), BufferUsage::StaticDraw); + _cubeIndexBuffer.setData(cubeData.indices(), BufferUsage::StaticDraw); + _cubeMesh.setPrimitive(cubeData.primitive()) + .addVertexBuffer(_cubeBuffer, 0, Shaders::Flat3D::Position{}) + .setIndexBuffer(_cubeIndexBuffer, 0, Mesh::IndexType::UnsignedInt) + .setCount(cubeData.indices().size()); + + const float RAND_MAX_RANGE = float(RAND_MAX/60); + for(int i = 0; i < 10000; ++i) { + const Vector3 randomVector{float(std::rand()), float(std::rand()), float(std::rand())}; + const Vector3 min = randomVector/RAND_MAX_RANGE - Vector3{30.0f}; + auto box = Range3D(min, min + Vector3{1.0f}); + addBox(box); + } + + _culledDrawables.buildOctree(4); + + addDrawableForOctree(*_culledDrawables.octree()); +} + +Vector3 OctreeExample::calculateIntersection(const Vector4 &v1, const Vector4 &v2, const Vector4 &v3) { + const Float det = Matrix3(v1.xyz(), v2.xyz(), v3.xyz()).determinant(); + + const Float x = Matrix3({v1.w(), v2.w(), v3.w()}, {v1.y(), v2.y(), v3.y()}, {v1.z(), v2.z(), v3.z()}).determinant()/det; + const Float y = Matrix3({v1.x(), v2.x(), v3.x()}, {v1.w(), v2.w(), v3.w()}, {v1.z(), v2.z(), v3.z()}).determinant()/det; + const Float z = Matrix3({v1.x(), v2.x(), v3.x()}, {v1.y(), v2.y(), v3.y()}, {v1.w(), v2.w(), v3.w()}).determinant()/det; + + return Vector3{x, y, -z}; +} + +void OctreeExample::addBox(const Range3D& aabox) { + const Matrix4 transformationMatrix = Matrix4::translation(aabox.center()) * Matrix4::scaling(aabox.size()/2); + + Object3D* box = new Object3D{&_scene}; + box->setTransformation(transformationMatrix); + + (new WireframeDrawable(box, &_drawables, _cubeMesh, _flatShader))->setColor(LIGHT_GREY); + + WireframeDrawable* renderer = new WireframeDrawable(box, nullptr, _cubeMesh, _flatShader); + renderer->setColor(PINK); + + _culledDrawables.add(*renderer, aabox); +} + +void OctreeExample::addDrawableForOctree(Octree::Octree*>& octree) { + if(octree.isLeafNode(0)) { + //const Matrix4 transformationMatrix = Matrix4::translation(octree.center())*Matrix4::scaling(Vector3{octree.radius()*0.999f}); + + //Object3D* box = new Object3D{&_octreeObject}; + //box->setTransformation(transformationMatrix); + + //(new WireframeDrawable(box, &_octreeVisualization, _cubeMesh, _flatShader))->setColor(GREEN * float(octree.depth())); + } else { + for(int i = 0; i < 8; ++i) { + //addDrawableForOctree(*octree.child(i)); + } + } +} + +void OctreeExample::drawEvent() { + defaultFramebuffer.clear(FramebufferClear::Color | FramebufferClear::Depth); + + /* cull for _camera */ + _culledDrawables.cull(_camera); + + _activeCamera->draw(_culledDrawables); + + if(_activeCamera == &_viewer) _activeCamera->draw(_drawables); + if(_visualizeOctree) _activeCamera->draw(_octreeVisualization); + + swapBuffers(); + + /* Rotate _camera to change cull result */ + _cameraObject.rotateYLocal(Deg(0.5f)); + + redraw(); +} + +void OctreeExample::keyPressEvent(KeyEvent& event) { + if(event.key() == KeyEvent::Key::S) { + /* Toggle view */ + _activeCamera = (_activeCamera == &_viewer) ? &_camera : &_viewer; + } else if(event.key() == KeyEvent::Key::V) { + _visualizeOctree = !_visualizeOctree; + } else if(event.key() == KeyEvent::Key::Esc) { + exit(); + } +} + +}} + +MAGNUM_APPLICATION_MAIN(Magnum::Examples::OctreeExample) diff --git a/src/octree/README.md b/src/octree/README.md new file mode 100644 index 000000000..7cac2ec05 --- /dev/null +++ b/src/octree/README.md @@ -0,0 +1,2 @@ +This example shows how to use octree view frustum culling in magnum. +![Octree](octree.png)