This repository contains the demo code for the research project Tessellation On Compute Shader. Requires OpenGL 4.5 min. Do not hesitate to contact me if you have any feedback, problem, remarks or questions about the code, by sending me a mail at jad.n.ky@gmail.com
Clone the repository and all its submodules using the following command:
git clone git clone --recurse-submodules https://github.com/jadkhoury/TessellationDemo.git
If you accidentally omitted the recurse-submodules
flag when cloning the repository you can retrieve the submodules like so:
git submodule update --init --recursive
Enter the following commands in the terminal
cd TessellationDemo
mkdir build
cd build
cmake ../
make
./demo
or
./demo <.obj file name>
or
./bench
The Bench subproject contains more or less the code from the demo, minus some late refratoring, and including some code measuring and outputting the performances of our pipeline in a Zoom-Dezoom setup.
├── CMakeLists.txt
├── common
│ ├── glad
│ │ └── ...
│ ├── imgui_impl
│ │ └── ...
│ ├── objs
│ │ ├── bigguy.obj
│ │ ├── bunny.obj
│ │ ├── cube.obj
│ │ ├── cube_quads.obj
│ │ ├── distancebased_regular.obj
│ │ ├── distancebased_warp.obj
│ │ ├── tangle_cube.obj
│ │ └── triangle.obj
│ └── submodules
│ └── ...
├── ComputeTess_bench
│ └── ...
├── ComputeTess_demo
│ ├── bintree.h
│ ├── commands.h
│ ├── common.h
│ ├── main.cpp
│ ├── mesh.h
│ ├── mesh_utils.h
│ ├── shaders
│ │ ├── bintree_compute.glsl
│ │ ├── bintree_copy.glsl
│ │ ├── bintree_render_common.glsl
│ │ ├── bintree_render_flat.glsl
│ │ ├── bintree_render_wireframe.glsl
│ │ ├── gpu_noise_lib.glsl
│ │ ├── LoD.glsl
│ │ ├── ltree_jk.glsl
│ │ ├── noise.glsl
│ │ ├── phong_interpolation.glsl
│ │ └── PN_interpolation.glsl
│ ├── transform.h
│ └── utility.h
└── README.md
- left-click + drag for camera rotation
- right-click + drag for camera panning
- Mouse wheel to advance on camera line of sight
- Mode: switch between terrain and mesh
- Advanced Mode: toggles additional GUI controls
- Render Projection: toggles the MVP Matrix
- FoV: Controls field of view of camera
- Reinit Cam: reinitialize the camera for current mode
- Wireframe: toggles the solid wireframe shading
- Flat Normal: toggles the flat normal computation in fragment shader, instead of procedural displaced normals (better performances and tessellation visualization)
- Displacement Mapping: Toggles the dislacement of the flat grid (TERRAIN mode only)
- Height factor: manipulates the height of the displacement map
- Rotate Mesh: rotates the mesh around the z axis
- Uniform: toggle uniform subdivision (with slider for level)
- Edge Length: slider for the target edge length, in px, as power of two (4 on the slider = 2^4 = 8px)
- Readback Node Count: Readbacks the number of nodes in the bintree, and the total number of rendered triangles (after culling). Slightly affect performances.
- Polygon Type: Switch between Triangles and Quads (TERRAIN mode only, auto defined for mesh)
- CPU LoD: Level of subdivision of the instanced triangle grid
- Interpolation type: Switch between linear, PN and Phong interpolation (MESH mode only)
- The rest is self-explanatory
Class containing the CPU side of the main work of this project: the bintree algorithm.
- Defines the
Settings
struct, containing all the parfameters of the bintrees, accessed by the GUI - Manages the 3 OpenGL programs corresponding to the 3 Passes to render one frame:
compute_program_
: implemented inbintree_compute.glsl
copy_program_
: implemented inbintree_copy.glsl
render_program_
: implemented inbintree_render_*.glsl
- More information in the code
- Manages the 3 buffers containing the nodes of the bintrees:
- Complete Bintree at frame t-1 (read)
- Complete Bintree at frame t (write)
- Culled Bintree at frame t (write)
- Generates the leaf geometry (aka the instanced triangle grid), and manages the buffers and vertex arrays storing them
- Recieves as parameter at initialization a pointer to the
Mesh_Data
structure containing all data for the mesh, a pointer to the uniform buffer containing the transforms (managed by theTransformsManager
intransform.h
), as well as a set of initialization settings stored in aBinTree::Settings
object. - Draws the mesh using our bintree implementation, by first updating the bintree once using the
compute_program_
, then copying the relevant parameters in the indirect command buffers in thecopy_program_
, and finally drawing the mesh in therender_program_
- Manages and binds the atomic counters keeping track of the number of primitives to instanciate.
- Manages and binds the indirect Draw and Dispatch buffers
Header file containging all the using & includes used across the project, along with:
struct BufferData
: Represents a bufferstruct BufferCombo
: Usefull data structure to manage geometry buffersstruct Vertex
: // Data structure representing a unique vertex as a set of a- 3D position
- 3D normal
- 2D UV coordinate
struct Mesh_Data
: Stores all data necessary to represent a mesh
Namespace for generating and managing meshes (grids, obj parsing and storing in mesh_data...)
- Class allowing the opaque use of our bintree algorithm for mesh rendering
- Relays the camera and frustum settings to the Transforms Manager
- Holds instances of the Bintree as well as the Transforms Manager
Header file containing both the CameraManager
and the TransformsManager
.
The CameraManager
is responsible for treating the mouse input and updating the current camera setup accordingly.
The TransformsManager
then updates the transforms matrices accordingly, and pushes them in an uniform buffer, accessed all along our render pipeline.
Header containing the utility namespace for small usefull functions used across the project, as well as some OpenGL debug callbacks
OpenGLApp
struct that stores a few render settings, the default filepath, some mouse related temp variables, the light position, and instances of the Mesh class and the Camera Manager classBenchStats
struct that contains and updates the benchmarking variables- Displays the GUI using the
imgui
API - Manages the mouse input, relay them to the
CameraManager
, notify theMesh
class accordingly (In particular: calls the relevant functions of the Camera Manager, notifies the Mesh class that it has to update the transforms, which then in turn relays the calls to the Transform Manager that updates the matrices) - Manages the resize callbacks.
- Launch and manages the render loop
- Handles arguments passed at the call of the program (
.obj
file path)
Holds the compute pass of the render pipeline, that updates the bintree data structure and performs the frustum culling
Holds the BatcherKernel program, in charge of preparing the indirect draw command buffer for the current pass, and the dispatch indirect command buffer for the compute pass of the next pass
Holds a few function common to both the standard render program and the wireframe render program
Holds the standard render program:
- Vertex Shader: takes as input the vertex of the instanced triangle grid to render, reads a key from the bintree data structure, compute the vertex bintree space position, interpolates in world space position using the relevant interpolation method (either Linear, Phong, or Curved PN Triangles). If displacement mapping is activated, performs the displacement
- Fragment Shader: use the world space position of the vertex to perform the shading. If displacement mapping is activated and flat normal is not, computes the vertex normal as gradient of the procedural displacement map
Similar to the bintree_render_flat
, with the addition of a Geometry stage that allows us to use solid wireframe.
GLSL library to generate procedural noise, used in our heightmap generation
Contains functions relative to the distance based LoD computation and culling. Also defines the Transforms uniform buffer, used accross the shaders
My own implementation of the bintree management functions (key generation for parent/children, level evaluation, mapping from one space to another). The keys are implemented as ulong int, simulated as a uvec2 concatenation, allowing 63 levels of subdivision.
Contains function for the procedural heightmap computation, relying on gpu_noise_lib
Performs Phong interpolation on the current Vertex instance by using the normals, uv and coordinates of the currently rendered mesh polygon.
Similar to Phong.glsl
, but for the Curved PN Triangles method.