how to "sort" polygons 3d? - javascript

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.

Related

How to shrink polygon by a defined amount in centimetres using co-ordinates

I am trying to shrink a polygon by a specific amount where all edges in the new polygon are of equal distance to the old one. To explain better I have a picture here.
If the picture doesnt work I have a link here.
https://imgur.com/a/A27mVHs
This is a rough drawing.
I have a point array in ([x,y])
[[390,435], [388,430], [391,425], [425,428], [410,435]]
I am trying to shrink it so the new array
[[x1,y1], [x2,y2] ... [x5,y5]]
ensures that the distance between the new area and the original one is 2 at all sides of the area.
How can I do this by only manipulating the co-ordinates. I know I need some kind of scalar vector but I'm unsure how to do this. I am trying to implement this in javascript
In the general case this is indeed an arduous problem. But for a convex polygon, it is pretty easy.
At every angle, draw the bissector and find the point at distance of the vertex equal to d / sin α/2 where α is the measure of the angle.
Have you done some research because there is lots of topics in internet about that subject, the short answer is this is not easy because there is lots of edge cases (look this topic for exemple).
A good term if you want to look more and find nice libs to do this task for your is Polygon offsetting
Others good links :
An algorithm for inflating/deflating (offsetting, buffering) polygons
ClipperOffset
A Survey of Polygon Offseting Strategies
Javascript Clipper

How to determine if two concave/convex shapes are at particular distance?

I have to determine whether two concave/convex shapes are at distance d from each other . I know Separating Axis theorem might come handy in determining the distance , but that runs in O(n2) time , and I am looking for O(n) or O(nlogn) algorithm for any shape . I want to implement that for any two SVGs in javascript
This is a broad and arduous problem.
To handle the most difficult cases (like ellipse/Bezier distance), you will need to somehow flatten the outlines so I recommend to flatten in all cases, and solve the problem for two polygons only.
Amazingly, you find little resources on the Web for the distance between two polygons.
Assuming that you are dealing with the inside of the shapes (and not just the outline), you will first have to check the polygons for void intersection (otherwise the distance is 0). I guess that this can be done in time O(N.Log(N)).
Then, if I am right, the closest distance between two polygons is the shortest of the closest distances of all vertices to the other polygon. If you construct the Voronoi diagram of both polygons (which is doable in time O(N.Log(N))), you get two planar subdivision, in which you can solve the point-location problem in time Log(N) per point.
All put together should lead to an O(N.Log(N)) solution. You will need a specialized Computational Geometry library to achieve this.

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

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.

Getting the points of a filled ellipse in JavaScript

I was wondering if anyone could point me in the right direction as to how I would generate the points of a filled ellipse or circle.
I know of algorithms to draw the outline, but not the contents as well.
All I require are an array of points. But I have no idea where to start and can't seem to find my answer on Google.
Any help is much appreciated.
Thanks.
You know the points of the outline, so you could just sort them by line (i.e. by the y-coordinate). When the two y-coordinates are equal, sort them by x-coordinate.
Now, for two points with the same y-coordinate you know that all points between them must be in the ellipse.
You can generate the points by scanline. The equation of an ellipse is
ax2 + by2 + c = 0
So iterate over the values of y and solve for x. You'll get a quadratic equation in x with two solutions, giving you the points at the left and right end of the scanline. All the point in between are inside the ellipse.
If you want fast generation of the coordinates for the endpoints, see John Kennedy's paper, A fast Bresenham-type algorithm for drawing ellipses.
You may want to have a look at some graphics library like jsDraw2d
http://jsdraw2d.jsfiction.com/
A more efficient method though is probably to use Javascript to generate SVG images but unfortunately Internet Explorer up to version 8 does not support SVG.

Plotting mathematical functions without rendering artefacts

I don't think there's a good answer to this, but I'd like to find out if there's a better way to do this.
I need to plot a mathematical function, which is nearly flat at one end of the display, and nearly vertical at the other end. The bottom left quadrant of a circle would be a good model. I can auto-generate as many points as required.
The problem is, I can't do this without all sorts of artefacts.
I haven't tried Bezier fitting; I don't think this would be even close. My understanding is that Bezier is for one-off manually-constructed pretty graphics, and not for real curve-fitting.
That leaves polylines. There are only 2 things I can do with polylines - I can select the line length (in other words, the number of points I auto-generate), and I can disable anti-aliasing (setAttributeNS(null, "shape-rendering", "crisp-edges").
If I generate lots of points, then I get jaggies everywhere, and the result is unusable. It can also look very much like it's oscillating, which makes it appear that I've incorrectly calculated the function. The anti-aliasing doesn't make any difference, since it doesn't operate across point boundaries.
The only solution I've got is to draw fewer points, so that it's obvious that I'm drawing segments. It's no longer smooth, but at least there are no jaggies or oscillation. I draw this with the default anti-aliasing.
Any ideas?
Edit:
It seems like the only answer to this is actually Bezier curve fitting. You have to preprocess to find the parameters of the required segments, and then plot the results. Google comes up with a number of hits on curve fitting with Beziers.
You have the mathematical function, and can therefore generate as many points as you need.
I assume the problem is that because you do not know the output resolution (SVG is device independent) you do not know how many points to generate. Otherwise you could just create a polyline where each line is approximately 1 pixel long.
Fitting your mathematical function to a bezier curve is (probably) not going to get a perfect match - just like a circle cannot be matched perfectly by a cubic bezier curve. And I think the task of fitting your function to a bezier curve would not be trivial (I've never done this).
Could you rather output your mathematical function to a canvas element? Then you could write some javascript code to plot your mathematical function dependant on the output resolution. Similar to how a graphics system renders a Bezier curve.
Do you know how graphics systems render Bezier curves? They approximate the bezier curve with a polyline, and then measure the error difference between the polyline and the bezier curve. If the difference is greater than a certain tolerance - where the tolerance is determined by the output resolution - the bezier is subdivided and the process repeated for each bezier curve. When the difference between beziers and polylines is below the tolerance, the polylines are drawn. http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Computer_graphics
I suppose you want to draw y=f(x) over a certain interval [a,b]
A classical solution is to take N points uniformly distributed over [a,b], to compute f over these points and draw lines (or polynoms).
It of course doesn't work in your case, since y is nearly vertical in certain area. But why don't you take more points in these areas (and less points where the function is nearly horizontal) ?
You can compute the derivative of your function (or approximate this derivative with (f(x+h)-f(x))/h and h small) and determine the step between two successive points with this derivative

Categories

Resources