Technical Report
Total Page:16
File Type:pdf, Size:1020Kb
Contents 1 Introduction 1 2 Design 2 2.1 Voxel...................................................... 2 2.2 Chunk . 2 2.3 Initial Architecture . 2 3 Implementation 3 3.1 Starting Point . 3 3.2 Result . 3 3.3 Architecture . 4 3.4 Block Structure . 5 3.5 Chunk Structure . 5 3.6 Physics . 5 3.7 Input & Controls . 5 3.8 Work Division . 6 3.9 Tools...................................................... 6 4 Performance & Bottlenecks 7 4.1 Reducing the Number of Blocks Drawn I . 7 4.2 Reducing the Number of Loaded Meshes . 8 4.3 Reducing Draw Calls . 8 4.4 Reducing the Number of Blocks Drawn II . 9 4.5 Only Recalculate Meshes When Changes Occur . 10 4.6 Physics Optimisation . 11 5 Discussion 12 6 Future Work 13 6.1 Frustum Culling . 13 6.2 Physics optimisation . 13 6.3 Procedural generation . 13 6.4 Serialisation . 13 7 Ludography 14 8 References 14 1. Introduction This report presents the end project for the course Game Programming (KGGAPRO1KU) at IT University of Copenhagen. For this course, we, Mads Engberg, Frans Peter Larsen and Sven Santema, have created and optimised a voxel game. The project is done in C++ and makes use of the Simple Render Engine (SRE) [1] by Morten Nobel. The focus of this project is on resource management, memory leaks, physics libraries. The Simple Render Engine project presents a good starting point for a game in C++. It has 3D capabilities using Simple DirectMedia Layer (SDL) [2], Box2D [3] or Bullet Physics [4], OpenGL Mathematics (GLM) [5]. Our project builds upon SRE and creates a basic voxel-based game much like Minecraft (Mojang, 2009). In Minecraft players move around in a world completely made out of blocks. Players can destroy and place blocks, thereby, making buildings and shaping the world to the players liking. Our project aims to create and implement our own version of a voxel-game very similar to Minecraft. In short, a game in which the player moves around in a world that exists out of blocks, and where players can place and destroy blocks. We have chosen for a voxel-based game since we think it presents many interesting challenges. First of all, the world exists out of many blocks that all have to be rendered. Secondly, what blocks are being displayed change during run-time since players can add and remove blocks as they like. These two challenges require a flexible and well-optimised game system, since meshes cannot be pre-generated or loaded from the disk, but have to be generated and modified during run-time. Lastly, the game is 3D which generally adds to the complexity of the implementation. The report will first go into the design, in which we will establish the requirements and ideas for the game. In the second chapter, the overall architecture of the implementation, in-depth information regarding class structures and implementations together with work division and tools used for the project. After this, a chapter is dedicated to the performance and bottlenecks we encountered during development. This chapter also goes into depth on how these bottlenecks were solved. Chapter five presents a discussion on the end result. Lastly, in chapter six, future work, we present ideas that we think would further optimise our project and add value to it. 1 2. Design The overall design goal is to get a proper voxel-based structure running in which you can add and remove blocks from the world in real-time without major performance issues. While the game could be represented in basic colours for the blocks we want to have per-block textures and several different types of blocks with different textures. The player needs to be able to move around freely in the world, interact with blocks such as colliding with the blocks, jumping on top of blocks, going underneath blocks (or into caves) and of course add and remove them to/from the world.In order to establish a greater understanding of the features of the design, one has to understand some terminology that is common for voxel-based engines: voxels and chunks. A. Voxel ame Programming (Autumn 2017) (KGGAPRO1KU-Autumn 2017 A voxel (also referred to as Block in the context of our project), which comes from Volumetric and Pixel is a single point in 3D space. Much like a Pixel, it has a colour (or type) and a position within the space [6]. Both are visualised in some way and all are uniform in their size but do not directly have a size as such. Of course, due to the nature of computer graphics, the voxel needs to have some sort of size but is in most cases always the same, or just 1 unit in width, height and depth, so by representation they are discrete and uniform [6]. B. Chunk In voxel games, a large number of voxels have to be rendered at the same time, while they are interactable and mutatable. Having all of these voxels being rendered and interactable at the same time can be a giant task for the CPU if the number of voxels is not restricted. To solve this issue many voxel engines split their voxels into larger structures: the chunk. A chunk is some amount of voxels often, but not always, arranged in a cube-like shape. By splitting voxels up like this it is possible to only make the chunks that the player is closest to interactable and rendered. This can severely improve the performance of the game depending on how the chunks are implemented. The size of chunk differs from game to game. For example; in Minecraft, [7] chunks are 16 blocks wide, 16 blocks long, and 256 blocks high, which is 65,536 blocks total. In this project, the dimensions of a chunk have changed often and been fitted to the optimisations that were implemented. C. Initial Architecture Using the mentioned design and its requirements we established an initial Unified Model Language (UML) diagram for the overall established architecture of the game. This formed a starting point when we started working on the project (See figure 1). The source code can be found at https://github.com/Jalict/voxel-game together with a build which can be found at https://github.com/Jalict/voxel-game/releases/tag/1.0. Fig. 1: Initial UML class diagram and relationships. 2 3. Implementation This chapter explains the implementation and the overall architecture of the project. Besides this, the tools that were used during the project are described in short. Furthermore, the chapter contains the work division between all the members of the team. A. Starting Point As a starting point for the project, we have used exercise 6 - Wolf3D. In this exercise, we worked on a very simplistic clone of Wolfenstein 3D (id Software, 1992) in SRE. In this exercise, we had to complete a first person controller. Load the map from a JSON file and create 3D boxes with textures on them. Since our project requires a first person controller and is 3D with textured cubes this exercise formed a good starting point. With that said, most of the code used in the exercise has been replaced over the course of the project. B. Result The result of the project is a game with basic mechanics of voxel-based games, such as Minecraft. The player can place, remove and replace blocks within the world. They are free to move around in the world. The player can switch between several types of blocks that can be placed in the world. Furthermore, they can mine every block in the world, except for bedrock, which forms the bottom layer of the world. The terrain is generated using a very simplistic procedural method. See figure 2, 3, 4 and 5 for screen captures of the game. The game performs well and runs stable, even in debug mode in Visual Studio a steady 60 frames per second is achieved. Fig. 2: Basic houses and a few blocks placed. Fig. 3: Block removal from terrain. Fig. 4: Blocks can be placed as the player wishes. Fig. 5: An overview of the game world. 3 C. Architecture The game uses a very basic class structure due to the scope of the project and the focus on optimisation. Most of the work have been spread out to to get basic Voxels working well together with basic interaction. This means that there is a only a few classes in the project (See figure 6): • Game : Handles instantiation, game-, render-loop, input and container for chunks, graphical user interface (GUI) • Chunk : Container for voxels and partial voxel handling • Block : Voxel data • FirstPersonController : Camera handling, player input & movement, world interaction • ParticleSystem : Container for particles and handling • Particle : Particle data • Physics : Holds the physics world, also serves as a wrapper for Bullet Physics Here is a description of the general instantiation and loop of the game. The game starts instantiating everything, this goes for physics, render, textures/materials, particle system and chunks, light and the player. It proceeds to subscribe four functions, one for updating, one for rendering, one for keyEvents and one for mouseEvents. After that, the rendering finally starts. All objects are instantiated before the game so that the least amount of objects have to be instantiated during run-time. Since instantiated during run-time can be quite costly to performance. Instead, the game uses flags for disabling objects whenever they should be inactive or destroyed, this gives much more responsive gameplay and stable frame rate. The drawback is memory usage can become quite high. When game loop starts physics is updated first.