Giter Club home page Giter Club logo

cpuvox's Introduction

cpuvox

A C# implementation of realtime voxlap-style rendering, using Unity and their Burst compiler

img (^ picture is the powerplant model consisting of 36 869 210 voxels in a 2048^3 world; renders at 10-60 fps at 1080p depending on view on an intel i5-4670k)

Implementation mostly based on the paper named "Research on Improving Methods for Visualizing Common Elements in Video Game Applications" by Sven Forstmann, which can be found here: http://svenforstmann.com/pdf/Ph.D.Thesis.Sven.Forstmann.pdf (page 84 and on)

Summary of the implemented algorithm:

  • Compute the 'vanishing point' (VP), where the near plane intersects with the player Y (vertical) line
  • Divide the screen into 4 sections when the VP is visible (looking down/up-ish), where each section is a quarter of the world in XZ space
  • Get a raybuffer texture, where we can render our semi-2d semi-3d results of phase 1 to (one column per ray)

Phase 1:

  1. Make a bitmask to keep track of which pixels we have written to in this raybuffer column
  2. Cast a ray through the XZ world for every column of pixels in each segment, drawing into the ray-buffer
  3. For every XZ world column of voxels:

3.1) Adjust the LOD level & world we trace through based on distance

3.2) Define a quad 'Q' that is the intersection of the XZ ray with the maximum voxel column at this position

3.3) Project the 4 corners of Q to homogeneous camera space

3.4) Frustum cull these 2 lines (the 'near' and the 'far' vertical lines Q) to find a min/max world Y of the voxels to render - if fully culled, early out to skybox

3.5) Project these to the screen to find a min/max pixel we may write to for this column - if it does not overlap our written pixel bounds, early out to skybox

3.6) Iterate the run-length compressed list of solid voxels; top->bottom if the camera points down, bottom->top if the camera points up (to maintain front-to-back rendering)

3.7) For every voxel run in the column:

3.7.1) Check if it is within the desired world bounds (if not, early out)

3.7.2) Interpolate the projected corners of Q to get the homogeneous camera space coordinates of the voxel run corners that we need

3.7.3) Draw the side/top/bottom lines; since we draw voxel runs in one go, use perspective correct texturing for coloring the side

3.7.4) Adjust the written pixel bounds based on the pixel we draw here - if min >= max we won't write more pixels, early out to skybox; The bitmask is essential here to extend the written pixel bounds to be narrower after we've closed a 'gap' in the column

3.8) Adjust the frustum to be narrower based on the written pixel bounds

  1. Write the skybox to any pixel in the raybuffer column we didn't write to

Phase 2:

Project the semi-2d semi-3d raybuffer columns to the triangular screen segments, making it full 3d

Documentation/hints/general stuff about this project:

  • Made in Unity 2019.3.4f1, but any 2019.3 or future 2019.4 will probably load it without issues
  • The main segment setup code is in Assets/Code/RenderManager.cs
  • The main raybuffer rendering code is in Assets/Code/Rendering/DrawSegmentRayJob.cs
  • The raybuffer texture is divided into smaller textures and assembled into a full texture because of 2 reasons: -- 1) we don't want to upload the entire texture every frame (it can be 10-20 MB+, it's bigger than a 4-byte-per-pixel buffer) -- 2) this means we can start uploading the first textures on the main thread when they've been drawn to before we are fully done drawing.
  • There's lots of pointers everywhere because Burst does not (currently) support passing NativeArray's to functions at the point of writing (as they are considered managed objects). We can't use IJobs - which do support it - because we want to wake the main thread and tightly control scheduling around that
  • Models are not included in the git due to licensing concerns and because it's large binary data
  • There's no editing support because that was not the point of this project (it was to get the algorithm working and decently performant), there's no complex acceleration structure that prevents realtime edits
  • Writing a semi-decent multithreaded triangle mesh voxelizer was suprisingly hard
  • Special note about the algorithm losing a lot of precision when looking horizontal-ish if you don't clamp the segment triangles to a tight fit around the screen, which was not mentioned in the paper
  • The raybuffer is ARGB32 instead of RGB24 because it's assembled into a rendertexture which does not support 24-bit colors in unity - possibly we can work around this some other way to boost performance a bit, but it's a bit involved.
  • There's no depth buffer
  • The .obj importer only supports one model consisting only out of triangles and vertex colors (including normals/uvs etc will break it)
  • The output of the .obj importer is cached into a .dat file which is just a binary copy of the mesh from memory - it helps make things a lot easier (the powerplant.obj source is 800 MB and took 30 secs to parse)

cpuvox's People

Contributors

pipliz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

nongkris

cpuvox's Issues

Lines appears in Build

image

Weird Lines appear to only happen in Builds works fine in editor, Looking around changes it, if i look in just the right direction/angle they dissapear.

Wrong Lod?

Hard to reproduce, but in some cases it seems the wrong LOD is used.
image

Some cache usage improvement ideas

Hello! I've been working on my own raycaster very similar to this one, and I figured out some ideas to make cache hit rate and utilization much better, and thought they might help.

1 - If you store colors and rle segments separately, you won't pay the cost of pulling the colors into the cache, if it turns out that all of the column segments are not actually visible on-screen. I highly recommend this, because it means more runs will be in cache.

2 - When traversing the world, the most common case of traversal is probably an equal step in x and y directions. This means that if you store your world arrays contiguous in one access, like this

    01234567
    89ABCDEF

If you turn so your view goes across the rows, every grid sample will require a new cache line fetch!. So, I would recommend a simple tiling scheme, just 2x2 or 4x4 tiles should help utilize cache line fetches of the map data better. (If column rle segments and colors are stored together, this is likely not as effective)

If instead of doing (y*width)+x, or (x*height)+y indexing, you mix the bits of both axes, you can get some nice tiling

YYXXyx for example, will give you

01 45
23 67

89 CD
AB EF

The logical conclusion of a setup like this is full morton coding e.g. XyXyXyXy, there are diminishing returns above simple tiling, but it also might be worth a shot.

3 - This might not be applicable for your renderer, but it helped me to store a separate "column header" type data structure, which only has the heights of the top and bottom filled voxels in the column, and the number of runs. This allows me to pack as much important culling information (is the top below the screen? is the bottom above the screen? etc) into cache as possible. So, I have 3 main world arrays, column_headers, column_runs, and column_colors.

Hope these ideas help! My raycaster doesn't do lod or a lot of the fancy stuff yours does quite yet, but they improved performance for me by over 2x.

After some time it seems to randomly just Freeze

After what appears to be a random amount of time things just Freeze.
Happens in both Editor and Build, no Crash log or anything, Editor log appears to just Cut off without saying anything is wrong.
CPU Usage seems to continue going, however the editor or game itself just stops responding.

Small lines appear when in very specific viewing angles

How to Reproduce:
Create a Build use 1024 world size and go to Conference example model.
Don't click anything, just press Escape, it should snap your viewing angle this specific angle causes Three lines to appear in the model

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.