ComputerGraphik TU WIEN
ComputerGraphik TU WIEN

Table of Contents

Project Selektron 09.06.2015

The project was done for the course Visualisierung 2 VU - MSC.

Author
Adam Papp 1327381 066 932
Felix König 0917104 066 932

Description in the Paper

As current hardware allows people to utilize high-resolution displays that can portray a variety of small objects within a game or a visual simulation it becomes more and more difficult to select the elements via a mouse in such applications. It is a comprehensible thought to try to simplify the selection of small elements via adapting the speed of the mouse movement. The included user study confirms higher accuracy when semantic 3D pointing is used. The technique utilizes the information about the location and size of possible targets in the scene and their distance to the current cursor position in order to adapt the speed of mouse movement.

See also
http://dl.acm.org/citation.cfm?id=1375714.1375755 - Semantic Pointing for Object Picking in Complex 3D Environments

Implementation

Summary

The implementation sticks very close to the suggested method which was described in the paper but we also implemented an alternative solution. The idea in the paper was to calculate the distance of the nearest object to the mouse position using a spacial hierarchy data structure, a QuadTree to be precise. Every pickable object is rendered into a Id Buffer that is a separate texture in our case. The result is a screen space representation of all pickable objects. The task is now to determine the nearest pixel to the mouse that is nonzero, meaning it lies on the nearest pickable object. The paper suggests to represent the whole screen space texture in a quadtree and then query the quadtree for the distance information. In addition to using a quadtree, we also implemented a compute shader that calculates the distance on the GPU. The compute shader outperforms the quadtree approach. Please read the following sections for a more detailed describtion of our implemented methods.

Semantic Object Picking

The purpose of the class MouseSemantics is to

  1. draw a mouse cursor and scale its appearance and
  2. scale the movement according to the distance of the nearest object.

The draw method uses point sprites to render the picture of a mouse pointer onto the screen. The size of the cursor is then directly coupled to the distance of the nearest pickable object. The bigger the distance, the bigger the mouse will be rendered.

In addition to rendering, this class also implements the 2 scale functions which are presented in the paper. Important parameters are:

Standard scale function: (M - m) * (C / D) + M

Inverse scale function: (m - M) / (D + 1)^S + M where D is the actual distance to the nearest object and S is an empirically derived constant (0.1 in our case).

Using F10 one can toggle between the inverse and the standard scale function. Using J and K one can slow down or speed up the overall mouse speed.

The scale functions are depicted as follows:

linearscale.png
linear scale function
inversescale.png
inverse scale function
Author
Felix Koenig

Information Visualization

Design
The Legend uses the freetype class in order to support rendering of text. The freetype library allows loading of characters as textures that can be rendered. An additional class LegendBackground is defined and used by the legend in order to render the background. Since different shaders are needed for rendering textures and background, the background rendering is encapsulated in a seperate class.
Implementation
In the constructor of legend, images of all ascii characters are loaded and saved as textures on the gpu. This allows for selection of corresponding textures during the runtime instead of loading them at runtime, suffering hughe performance losses. Textures of characters are loaded with the FT_Library ft and are stored as FT_Face face. Each face defines the parameters with which a texture should be rendered. These parameters specify the offset from the base, its with and height. These parameters are contained in a FT_GlyphSlot. Therefore, the struct Glyph that corresponds to such a slot has been created. Here, the parameters are inserted and for each character a entry in the std::map<char,Glyph> charGlyphMap will be created. This map will be used together with std::map<char, GLuint charTexHandleMap to find corresponding glyphs and texture handles for each character during the runtime. If one want's to render additional lines of text, the draw function in legend.cpp must be modified. Currently, following crucial information is displayed:
  • Cursor speed: this is the computed scaling of the mouse that lies in the range [m,M] as defined in MouseSemantics
  • Scale factor: a scalar that is multiplied with the scale factor from above. The user can adjust this value if the mouse is too slow/fast
  • Scale function: the standard or inverse scale function from the paper can be used.
  • Selection mode: defines if a compute shader or a quad tree is used for calculating the distance.
  • Distance: the current distance between the mouse and the nearest object is displayed.
  • FPS: frames per second
Author
Felix

Random Bubble Cursors

The class BubbleCursor implements the rendering of circles (=bubbles in the paper) that are randomly placed on the screen with the radius as big as the distance to the nearest object.

In the method generateRandomPopulation() 50 points are generated at random that are distributed across the screen space. These 2d points are generated using two Gaussian distributions centered at windowWidth/2 and windowHeight/2 (middle of the screen), with a sigma value of windowWidth/5 and windowHeight/5. The objects used were:

std::default_random_engine generator(time(NULL));
std::normal_distribution<double> distributionY(height / 2.0f, height / 5.0f);
std::normal_distribution<double> distributionX(width / 2.0f, width / 5.0f);

for further details see the function generateRandomPopulation().

In the draw() function the positions of those points are then forwarded to the pickObject method in the class SelectorQuadTree where the distance to the closest object (for each point separately) is computed. A point sprite renderer is then used to draw a transparent circle onto the screen. The radius of the circle is scaled to conicide with the distance to the nearest object (in pixels).

The user can enable/disable the display of these bubbles with the key B, everytime the display of the bubbles is disabled and enabled another random population is created. Rendering all bubbles consumes a huge amount of CPU load since for each of the 50 points the quadtree needs to be queried.

The result looks like:

bubble1scaled.png
bubble cursor
bubble2scaled.png
bubble cursor
Author
Felix Koenig

QuadTree Based Solution of Object Selection

The SelectorQuadTree class implements a quadtree based approach based on http://dl.acm.org/citation.cfm?id=1375714.1375755 . In the scene there are objects that can be selected. These objects are rendered, in screen space, into a texture, which holds the semantic information. The datatype of this texture is 16bit integer, to store the render id of the objects. After rendering with the draw() function, the quadtree is built up by the update() function. In the first step, the complete texture is copied from GPU to CPU. Then each pixel, which contains an object id, is used to build up a quadtree. The quadtree is selected to be a fix size of 2048*2048 pixels. The SelectorQuadTree::Node objects store the childs as indices of the SelectorQuadTree::nodes vector container. The tree is built up from top to bottom, where an occupied pixel will be present in the bottom level. The following pseudocode demonstrates the build up process:

//the build up process of the quadtree
for(y to screensize.y)
for(x to screensize.x)
id = texture[x, y]
if(id == 0)
continue
//size = 2048
shift = 10
bitmask = 0x400
node = root;
do
//decide in which child the pixel should be placed to
//example: Assume x is 1024, then it's bitsample is 0x400.
// In the top level it is masked with 0x400 and the result will be 0x400,
// which is then shifted with 10 bits and will be 1, so the high child will be selected in the X axis.
// At level 9 it is masked with 0x200 and it will be zero, then the low child is selected.
// In this example all the lower levels will be placed in the low child.
childX = (x & bitmask) >> shift
childY = (y & bitmask) >> shift
child = node.child(childX, childY)
if child not in container
create new child and add to nodes
child.id = id
child.updateBB(x, y)
//move one level down
node = child
shift = shift - 1
bitmask = bitmask >> 1
while(bitmask != 0)

Since the scene contains only static objects, it is sufficient to build up the tree only when the camera is moved. The quadtree then enables the fast selection of these static objects using the pickObject() function. The following pseudocode demonstrates the travelsal of the quadtree:

//find closest object to mouse in quadtree
//initialization
id = 0xFFFF
minD = maxD = FLOAT_MAX
nextLevelQueue.push(ROOT)
while(!nextLevelQueue.empty())
//prepare loop on one level
queue = nextLevelQueue
nextLevelQueue.clear()
minD = maxD = FLOAT_MAX
while(!queue.empty())
Node = queue.pop();
for i 1..4
if(!node.hasChild(i))
continue
//get minimum and maxmimum distance between child node and mouse
//the distance is computed from the four corner points of the bounding box
[nodeMin nodeMax] = node.child[i].getDistance(mouse)
//minimum distance of node is larger then smallest maximum distance of this level
if(maxD < nodeMin)
continue;
//add child to next level loop
nextLevelQueue.push(node.child[i])
//update minimum distance
minD = std::min(nodeMin, minD);
//update smallest maximum distance
maxD = std::min(nodeMax, maxD);
//store id
if minD is updated
id = node.id
Author
Adam

Compte Shader Based Solution of Object Selection

The SelectorGPU class implements an alternative selection method. The selectable objects are rendered into a texture the same way as in the quadtree based method. After rendering a compute shader is executed on the texture, returning the id and the distance of the closest object to the mouse. This way memory transfer and cpu time can be saved. By selecting different count of kernels, the size of the screen ROI can be modified. The following pseudocode demonstrates the object selection by the compute shader:

//the compute shader, executed for each pixel
ivec2 pixel = compute pixel position from thread id
if pixel out of pick buffer bounds
return;
//load object id at pixel position
uint id = imageLoad(pickBuffer, pixel)
//no object at pixel
if id == 0
return;
//compute distance, pack id and store if less
uint dist = (distance(mouse, pixel) << 16) | id;
atomicMin(buffer, dist);
Author
Adam

Results

In this subsection, the results of the different selector algorithms are compared. The SelectorSimple was written to compare it's speed with the SelectorQuadTree::update(). It must be noted, that these tests were done separate from the main render loop and each function was executed 100 times. The SelectorGPU seems to be faster by this table then the SelectorSimple, but when running in the main loop in this application, there are more processing done on the GPU then on the CPU, it is slower with window size 256 x 256. For static objects the SelectorQuadTree has an impressive speed increase. The first table shows the speed results of the different functions separate from the rendering loop, the second table shows speed results of the selection methods in the rendering loop.

The implementation was tested on the following configuration: Intel Core i7-4700HQ 2.40 GHz * 4, RAM 8 GB, NVIDIA GTX 860M.

Pixel Count 256 x 256 512 x 512 1024 x 512 1920 x 1080(*) / 2048 x 1024(**)
Time Min (ms) Avg (ms) Max (ms) Min (ms) Avg (ms) Max (ms) Min (ms) Avg (ms) Max (ms) Min (ms) Avg (ms) Max (ms)
SelectorSimple::pickObject() ** 0.496078 0.578992 4.31417 0.710333 0.806508 4.38345 0.957944 1.055110 4.64175 2.066840 2.197720 6.86467
SelectorQuadTree::update() * 0.162508 0.176214 0.809546 0.620951 0.668921 2.419660 0.972053 1.031520 3.057290 4.439880 4.952960 12.06710
SelectorQuadTree::pickObject() * 0.087241 0.0921123 0.1552380 0.072701 0.0756049 0.0957944 0.183891 0.1924740 0.2416240 0.137704 0.1419980 0.2065570
SelectorGPU::pickObject() ** 0.0474696 0.053632 0.189451 0.0679969 0.0857317 0.41183 0.104347 0.140283 0.455879 0.32801 0.346553 0.488808
SelectorBase::draw() * N/A N/A N/A N/A N/A N/A N/A N/A N/A 0.0372059 0.0443006 0.217248
glGetTexture() ** 0.0115466 0.0130007 0.0534567 0.0363506 0.0380997 0.168496 0.0684246 0.0744374 0.34084 0.472985 0.520775 1.6037
Pixel Count 256 x 256 512 x 512 1024 x 512 1920 x 1080(*) / 2048 x 1024(**)
Frames Avg (FPS) Avg (FPS) Avg (FPS) Avg (FPS)
SelectorSimple::pickObject() ** 220 210 210 180
SelectorQuadTree::pickObject() * 256 256 256 256
SelectorGPU::pickObject() ** 210 205 205 198

Resources

Windows Binaries
Source Code

Project MiniKrieg 29.01.2015

The project was done for the course Echtzeitgraphik VU - MSC.

Author
Adam Papp 1327381 066 932
Felix König 0917104 066 932

Description

The project was to create a real-time animation with effects using at least OpenGL 3.3. In the demo scene, there is a tank placed in a museum room. The tank is moving forward and leaves a trail behind, here the ParticleSystemCPU is used. The Tank shoots bullets in 360 degrees. These bullets are moved by the ParticleSystemGPU and rendered using tessellated spheres with LOD and animation using displacement mapping with Tessellation. While the tank and it's effects are shown, Omni Direction Shadow Mapping is used. Afterwards, the shadows are rendered using Shadow Volumes. Then the Cube Mapping effect can be seen on the ellipsoid. Finally, the camera will look outside of the room showing the Volumetric Lighting effect. Before the demo is finished, the shadow of the tank is shown once more using Shadow Volumes.

Starting the Demo

The demo can be started in full screen mode in 1920 * 1080 with 60Hz refresh rate by double clicking on the exe. If it is started from command line, it must be started from the bin directory. In this case arguments can be used in the following format: 1920(w) 1080(h) 60(r) 0(windowed).

Note
CMake must be set on configuration either to Debug or Release. This can be done in the CMake-GUI at the CMAKE_CONFIGURATION_TYPES variable.

The shader and texture folders are placed next to the bin folder in the zip file. The exe finds files using the following structure:

Controls:

Project SteelWorms 27.06.2014

The project was done for the course Computergraphik UE - BSC.

Author
Adam Papp 1327381 066 932

Description

The project was to write a game, with effects using OpenGL 3.3. The game can be started in full screen mode with 60Hz refresh rate by double clicking on the exe. The resolution is always 800 * 600. If it is started from command line, it must be started from the bin directory. In this case a dummy argument like {windowed} can be used to start in windowed mode. The game is only a two-player version, but the algorithm can handle any number of player. The shader and texture folder are placed next to the bin folder. The exe finds files using the following structure:

Note
The Assimp Loader sometimes fails to load the Tiger model. Revision 340b94f9a54132f71f72331b3787b0c9cdf2de88 was used with MSVC10.

Game Play

The game is a turn-based artillery strategy game, with ShadowMap and ParticleSystemCPU effects. In one turn only one tank can be moved. A turn ends in one minute or when the bullet reaches the terrain. After the bullet is shot, the tank can not move. A bullet can be shot by holding the SPACE key. The longer it is hold the bigger power it will be used to shoot. There is water under and above the track. If a tank reaches water it's health will decrease. If a tank goes off track it dies. When only one tank lives, the game ends and the result is written out in the console. The user inputs are handled by the GLFW library. The camera can be moved either with the keyboard or with the mouse. The keyboard controls are the arrows for moving and 1 to zoom out and 2 to zoom in. The right mouse button can be used to move the camera, the left mouse button can be used to rotate the camera and the middle mouse button is to zoom. A tank can be moved with the WASD buttons. The turret and the gun can be moved by the IJKL buttons. A bullet can be shot with the SPACE button, the power of the shoot depends on the amount of SPACE. A turn can be ended with the ENTER key. The ESC key can be used to exit the game.

External Libraries