Best practice: Rendering volume (voxel) based data in WebGL - javascript

I´m searching for a (or more) best practice(s) for the following problem. I´ll try to describe it as abstract as possible, so the solution can be applied to scenarios i have not yet thought of.
Data available: Voxels (Volumetric Pixels), forming a cube, with coordinates x,y,z and a color attached.
Goal: Use OpenGL to display this data, as you move through it from different sides.
Question: Whats the best practice to render those voxels, depending on the viewpoint? How (which type of Object) can store the data?
Consider the following:
The cube of data can be considered as z layers of x y data. It should
be possible to view, in-between-layers, then the displayed color
should be interpolated from the closest matching voxels.
For my application, i have data sets of (x,y,z)=(512,512,128) and
more, containing medical data (scans of hearts, brains, ...).
What i´ve tried so far:
Evaluated different frameworks (PIXI.js, three.js) and worked through a few WebGL tutorials.
If something is not yet clear enough, please ask.

There are 2 major ways to represent / render 3D datasets. Rasterization and Ray-tracing.
One fair rasterization approach is a surface reconstruction technique by the use of algorithms such as Marching Cubes, Dual Contouring or Dual Marching Cubes.
Three.js have a Marching Cubes implementation in the examples section. You basically create polygons from your voxels for classical rasterization. It may be faster than it seems. Depending the level of detail you want to reach, the process can be fast enough to be done more than 60 times per second, for thousands of vertices.
Although, unless you want to simply represent cubes (I doubt) instead of a surface, you will also need more info associated to each of your voxels rather than only voxel positions and colors.
The other way is raycasting. Unless you find a really efficient raycasting algorithm, you will have serious performance hit with a naive implementation.
You can try to cast rays from your camera position through your data structure, find / stop marching through when you reach a surface and project your intersection point back to screen space with the desired color.
You may draw the resulting pixel in a texture buffer to map it on a full-screen quad with a simple shader.
In both cases, you need more information than just colors and cubes. For example, you need at least density values at each corners of your voxels for Marching cubes or intersection normals along voxels edges (hermite data) for Dual Contouring.
The same for ray-casting, you need at least some density information to figure out where the surface lies or not.
One of the keys is also in how you organize the data in your structure specially for out-of-core accesses.

Related

Bad rendering of ParticleSystems in Three.js with low graphic cards

I am trying to use particle systems to speed up the rendering of a system of stars, but I've noticed that the display is really bad on weak graphic cards (for example on Intel HD, which are pretty widespread). The particles, which should have a specific texture, are replaced by ugly squares with strange colors and transparency. For instance, this system of particles renders to :
This can be reproduced with any instance of THREE.ParticleSystem or THREE.Points (the more modern version). All the other THREE objects (Sphere, Cubes, Planes, etc.) are rendering well on my GPU, only particles bug.
Is there a way to avoid this effect? Otherwise, is there another method than particle systems to display a large number of objects without slowing down?
I'm not sure about your specific case but I've found that drawing a 'Point' primitives may be problematic for some GPUs, drivers and/or API versions.
They are just a primitive type and should work the same as Triangles and Lines, but for some GPUs - especially the low-end ones - they just don't work. And if the drawing Points works by itself - it doesn't support point sizes, or texturing, or something else...
In such case you may replace them with regular textured quad and it should be fine. You'll probably lose some performance this way so you may keep both approaches and select one based on GPU.

WebGL display loaded model without matrix

I'm learning webgl. I've managed to draw stuff and hopefully understood the pipeline. Now, every tutorial I see explains matrices before even loading a mesh. While it can be good for most, I think I need to concentrate on the process of loading external geometry, maybe through a json file. I've read that openGL by default displays things orthogonally, so I ask: is it possible to display a 3d mesh without any kind of transformation?
Now, every tutorial I see explains matrices before even loading a mesh.
Yes. Because understanding transformations is essential and you will need to work with them. They're not hard to understand and the sooner you wrap your head around them, the better. Actually in the case of OpenGL for the model-view transformation part it's actually rather simple:
The transformation matrix is just a bunch of vectors (in columns) placed within a "parent" coordinate system. The first the columns define how the X, Y and Z axes of the "embedded" coordinate system are aligned within the "parent", the W column moves it around. By varying the lengths of the base vectors you can stretc, i.e. scale things.
That's it, there's nothing more to it (in the modelview) than that. Learn the rules of matrix-matrix multiplication. Matrix-vector multiplication is just a special case of matrix-matrix multiplication.
The projection matrix is a little bit trickier, but I suggest you don't bother too much with it, just use GLM, Eigen::3D or linmath.h to build the matrix. The best analogy for the projection matrix is being the "lens" of OpenGL, i.e. this is where you apply zoom (aka field of view), tilt and shift. But the place of the "camera" is defined through the modelview.
is it possible to display a 3d mesh without any kind of transformation?
No. Because the mesh coordinates have to be transformed into screen coordinates. However a identity transform is perfectly possible, which, yes, looks like a dead on orthographic projection where the coordinate range [-1, 1] in either dimension is mapped to fill the viewport.

Marching Cubes Performance (2d)

I'm trying to implement a 2D version of the marching cubes algorithm (marching squares?), and one of the major roadblocks I've run into is the performance issues (using WebGL and three.js). I notice that there's a huge tradeoff between quality (voxel/square size) and performance, and I think that the culprit for this is the center (solid area) of the metaballs:
Obviously I don't care about the faces on the inside of the metaballs since that's a completely solid area anyways; but I'm not sure how to get around polyganizing the interior area without treating it the same as the rest of the surface. The problem becomes worse when I add more metaballs to the mix.
How can I get around this problem, to maintain a decent quality and be able to render many metaballs at a decent framerate?
If you are implementing the standard marching squares technique then the cases inside and outside the surface shouldn't be a problem. In fact they are the cheapest because you don't need to do any computation for them.
If you want to reduce the poly-count in areas where it is not needed (the central area of the circle), you need to look into using an adaptive sampling technique. In this case probably most adequate would be a quad-tree (2d octree).
The speed issue when decreasing the cell size would always be there because Marching Cubes is a O(n^3) algorithm (very slow), thus marching squares would be O(n^2) (still very slow). There is no way around that. (Using an adaptive sampling data-structure, as mentioned above, would speed things up.)
It seems to me you could improve on the quality at the lower resolution. The circle seems to be aliasing a lot (assuming this is not because it is actual low screen resolution). I would check again how you interpolate on the edges of the squares (i hope you don't just use the centres of the edges) - using a more appropriate interpolation will give you better approximation and you would get better results at lower resolution.
See Paul Bourke's article on marching cubes and checkout the interpolation if you are not doing it.
Here are some references for 3d isosurface extraction techniques, (mostly based on MC) but you could benefit from them, in your 2d case:
(Kazdan et al, 2007)
(Manson and Shaefer, 2010)
(Wilhelms and Gleder, 1992)
PS: also check out their references for many more similar and maybe foundation papers!

Classify lon/lat coordinate into geojson polygon using Javascript

I have a geojson object defining Neighborhoods in Los Angeles using lon/lat polygons. In my web application, the client has to process a live stream of spatial events, basically a list of lon/lat coordinates. How can I classify these coordinates into neighborhoods using Javascript on the client (in the browser)?
I am willing to assume neighborhoods are exclusive. So once a coordinate as been classified as neighborhood X, there is no need to further test it for other neighborhoods.
There's a great set of answers here on how to solve the general problem of determining whether a point is contained by a polygon. The two options there that sound the most interesting in your case:
As #Bubbles mentioned, do a bounding box check first. This is very fast, and I believe should work fine with either projected or unprotected coordinates. If you have SVG paths for the neighborhoods, you can use the native .getBBox() method to quickly get the bounding box.
the next thing I'd try for complex polygons, especially if you can use D3 v3, is rendering to an off-screen canvas and checking pixel color. D3 v3 offers a geo path helper that can produce canvas paths as well as SVG paths, and I suspect if you can pre-render the neighborhoods this could be very fast indeed.
Update: I thought this was an interesting problem, so I came up with a generalized raster-based plugin here: http://bl.ocks.org/4246925
This works with D3 and a canvas element to do raster-based geocoding. Once the features are drawn to the canvas, the actual geocoding is O(1), so it should be very fast - a quick in-browser test could geocode 1000 points in ~0.5 sec. If you were using this in practice, you'd need to deal with edge-cases better than I do here.
If you're not working in a browser, you may still be able to do this with node-canvas.
I've seen a few libraries out there that do this, but most of them are canvas libraries that may rely on approximations more than you'd want, and might be hard to adapt to a project which has no direct need to rely on them for intersections.
The only other half-decent option I can think of is implementing ray casting in javascript. This algorithm isn't technically perfect since it's for Euclidean geometry and lat/long coordinates are not (as they denote points on a curved surface), but for areas as small as a neighbourhood in a city I doubt this will matter.
Here's a google maps extension that essentially does this algorithm. You'd have to adapt it a bit, but the principles are quite similar. The big thing is you'd have to preprocess your coordinates into paths of just two coordinates, but that should be doable.*
This is by no means cheap - for every point you have to classify, you must test every line segment in the neighborhood polygons. If you expect a user to be reusing the same coordinates over and over between sessions, I'd be tempted to store their neighborhood as part of it's data. Otherwise, if you are testing against many, many neighborhoods, there are a few simple timesavers you can implement. For example, you can preprocess every neighborhoods extreme coordinates (get their northmost, eastmost, southmost, and westmost points), and use these to define a rectangle that inscribes the town. Then, you can first check the points for candidate neighborhoods by checking if it lies inside the rectangle, then run the full ray casting algorithm.
*If you decide to go this route and have any trouble adapting this code, I'd be happy to help

how to "sort" polygons 3d?

I am still working on my "javascript 3d engine" (link inside stackoverflow).
at First, all my polygons were faces of cubes, so sorting them by average Z was working fine.
but now I've "evolved" and I want to draw my polygons (which may contain more than 4 vertices)
in the right order, namely, those who are close to the camera will be drawn last.
basically,
I know how to rotate them and "perspective"-ize them into 2D,
but don't know how to draw them in the right order.
just to clarify:
//my 3d shape = array of polygons
//polygon = array of vertices
//vertex = point with x,y,z
//rotation is around (0,0,0) and my view point is (0,0,something) I guess.
can anyone help?
p.s: some "catch phrases" I came up with, looking for the solution: z-buffering, ray casting (?!), plane equations, view vector, and so on - guess I need a simple to understand answer so that's why I asked this one. thanks.
p.s2: i don't mind too much about overlapping or intersecting polygons... so maybe the painter's algorthm indeed might be good. but: what is it exactly? how do I decide the distance of a polygon?? a polygon has many points.
The approach of sorting polygons and then drawing them bottom-to-top is called the "Painter's algorithm". Unfortunately the sorting step is in general an unsolvable problem, because it's possible for 3 polygons to overlap each other:
Thus there is not necessarily any polygon that is "on top". Alternate approaches such as using a Z buffer or BSP tree (which involves splitting polygons) don't suffer from this problem.
how do I decide the distance of a polygon?? a polygon has many points.
Painter's algorithm is the simplest to implement, but it works only in very simple cases because it assumes that there is only a single "distance" or z-value for each polygon (which you could approximate to be the average of z-values of all points in the polygon). Of course, this will produce wrong results if two polygons intersect each other.
In reality, there isn't a single distance value for a polygon -- each point on the surface of a polygon can be at a different distance from the viewer, so each point has its own "distance" or depth.
You already mentioned Z-buffering, and that is one way of doing this. I don't think you can implement this efficiently on a HTML canvas, but here's the general idea:
You need to maintain an additional canvas, the "z-buffer", where each pixel's colour represents the z-depth of the corresponding pixel on the main canvas.
To draw a polygon, you go through each point on its surface and draw only those points which are closer to the viewer than any previous objects, as indicated by the z-buffer.
I think you will have some ideas by investigating BSP tree ( binary spaces partition tree ), even if the algo will require to split some of your polygon in two.
Some example could be find here http://www.devmaster.net/articles/bsp-trees/ or by google for BSP tree. Posting some code as a reply is, in my opinion, not serious since is a complex topic.

Categories

Resources