I am trying to simulate an omnidirectional light source in a 2D room. I would like to set up a room and have "light" propagate from a point source, stopping only when it reaches a wall. The result is shadows will be cast where the light cannot reach. The below picture shows the problem with several point sources
I am implementing this in D3 JS as part of a game based around the art gallery problem.
I am struggling to come up with a data structure suitable for allowing this simulation and animation. I imagine a circle radiates out from the source, splitting into arcs whenever it encounters a wall? Is there a way to do this without simulating lots of individual light beams?
I don't really think d3 will help here, besides drawing the SVG. On the theoretical side, <circle> elements have defined radii, which means that they will curve at the circumference. Arcs will do the same. The art gallery problem deals with polygonal spaces and circles are (arguably) not polygons.
On the practical side, if you are going to use d3, I would instead recommend making <polygon> elements. From your picture, it looks as though each 'light' covers at least one room, and the points of a polygon can match the coordinates of the walls. Where the lights extend out into other rooms, they look to be, from the dotted lines, triangles in most cases. Where the colors overlap, d3 can help because SVG elements are allowed fill properties with alpha components.
d3.select('svg').append('polygon')
.attr('fill', 'rgba(255, 0, 0, 0.5)')
.attr('d', foo);
That will draw a polygon with a semi-transparent red color.
However, d3 won't help you figure out the coordinates of these lights. IMHO you could do this with a search algorithm which starts at a 'light source' and emanates out in a linear fashion checking for walls. When it finds a wall, it takes the coordinates of that 'stop' point and adds it to the path of the polygon. When the polygon draws, the colors will overlap and appear to be light sources.
Related
Suppose you're trying to render a user's freehand drawings using a 2D triangular mesh. Start with a plain regular mesh of triangles and color their edges to match the drawing as closely as possible. To improve the results, you can move the vertices of the mesh slightly, but keep them within a certain distance of where they would be in a regular mesh so the mesh doesn't become a mess. Let's say that 1/4 of the length of an edge is a fair distance, giving the vertices room to move while keeping them out of each other's personal space.
Here is a hand-made representation of roughly what we're trying to do. Since the drawing is coming freehand from the user, it's a series of line segments taken from mouse movements.
The regular mesh is slightly distorted to allow the user's drawing to be better represented by the edges of the mesh. Unfortunately the end result looks quite bad, but perhaps we could have somehow distorted the drawing to better fit the mesh, and the combination of the two distortions would have created something far more recognizable as the original drawing.
The important thing is to preserve angles, so if the user draws a 90-degree corner it ends up looking close to a 90-degree corner, and if the user draws a straight line it doesn't end up looking like a zigzag. Aside from that, there's no reason why we shouldn't change the drawing in other ways, like translating it, scaling it and so on, because we don't need to exactly preserve distances.
One tricky test case is a perfectly vertical line. The triangular mesh in the image above can easily handle horizontal lines, but a naive approach would turn a vertical line into a jagged mess. The best technique seems to be to horizontally translate the line until it passes through each horizontal edge alternating between 1/4 and 3/4 of the way along the edge. That way we can nudge the vertices to the left or right by 1/4 and get a perfect vertical line. That's obvious to a person, but how can an algorithm be made to see that? It involves moving the line further away from vertices, which is the opposite of what we usually want.
Is there some trick to doing this? Does anyone know of a simple algorithm that gives excellent results?
I'd like to add "flying" (3D) arcs to my orthographic projection, as shown here, but with clipping instead of the fade effect. This seems difficult since the arcs are created independently of the projection. (Each arc is defined by three points obtained from the projection--the start, end, and great circle midpoint extended along a line from the center of the canvas--but the arc itself is drawn using "2D" cardinal interpolation on the corresponding points on the svg canvas.)
My first thought was that I might need to do some spherical geometry to get the coordinates where the clipping happens, but now I'm wondering if there's a more straightforward way to accomplish this (I'm new to D3).
This is what my map looks like without clipping:
I'm also very green to d3, but fortunately I'm also fresh from my own search for a decent solution for clipping flight lines in orthographic. The demo you link to is clever in more ways than one:
The arc is drawn from three points interpolated with a Catmull-Rom curve in the projected 2D coordinates that happens to visually approximate a true circular curve in 3D nicely
The line fades with proximity of either of its points to the clipping plane, as you've pointed out
Drawing the spline in the projected, 2D coordinates eliminates any option to split the line before projection and get visual smoothness for cheap, even if d3 had the functionality natively (which I haven't been able to find anyways). That means that interpolation will have to be a lot more manual.
My first thought was that I might need to do some spherical geometry to get the coordinates where the clipping happens, but now I'm wondering if there's a more straightforward way to accomplish this
I eventually settled with what I consider the most obvious option, which unfortunately you're aiming precisely to avoid:
Obtain the coordinates of the clipping point by the cross product of the current globe center with the normal to the great circle plane of the arc. Given your origin and destination Po and Pd respectively and the globe center C, you're looking for C x (Po x Pd) normalized
Interpolate coordinates between your origin and destination using something like d3.geoInterpolate
Project interpolated point at the right scale (read: elevation) above the ground for that fraction of the flight line
Draw one [smoothed] line from the origin to the clipping point along the interpolated points in between, and another from the clipping point to the destination, moving one accordingly to the background. Watch the cases where the whole line is in front or behind the clipping plane.
To figure out where in the flight path you need to splice your clipped point, you will probably need to compare the great angles of your clipping point to one end vs. end-to-end. Note also that performance takes a hit, but you may still be satisfied with the number of flight lines you've drawn in your example.
I want to create a shader to outline 2D geometry. I'm using OpenGL ES2.0. I don't want to use a convolution filter, as the outline is not dependent on the texture, and it is too slow (I tried rendering the textured geometry to another texture, and then drawing that with the convolution shader). I've also tried doing 2 passes, the first being single colorded overscaled geometry to represent an oultine, and then normal drawing on top, but this results in different thicknesses or unaligned outlines. I've looking into how silhouette's in cel-shading are done but they are all calculated using normals and lights, which I don't use at all.
I'm using Box2D for physics, and have "destructable" objects with multiple fixtures. At any point an object can be broken down (fixtures deleted), and I want to the outline to follow the new outter counter.
I'm doing the drawing with a vertex buffer that matches the vertices of the fixtures, preset texture coordinates, and indices to draw triangles. When a fixture is removed, it's associated indices in the index buffer are set to 0, so no triangles are drawn there anymore.
The following image shows what this looks like for one object when it is fully intact.
The red points are the vertex positions (texturing isn't shown), the black lines are the fixtures, and the blue lines show the seperation of how the triangles are drawn. The gray outline is what I would like the outline to look like in any case.
This image shows the same object with a few fixtures removed.
Is this possible to do this in a vertex shader (or in combination with other simple methods)? Any help would be appreciated.
Thanks :)
Assuming you're able to do something about those awkward points that are slightly inset from the corners (eg, if you numbered the points in English-reading order, with the first being '1', point 6 would be one)...
If a point is interior then if you list all the polygon edges connected to it in clockwise order, each pair of edges in sequence will have a polygon in common. If any two edges don't have a polygon in common then it's an exterior point.
Starting from any exterior point you can then get the whole outline by first walking in any direction and subsequently along any edge that connects to an exterior point you haven't visited yet (or, alternatively, that isn't the edge you walked along just now).
Starting from an existing outline and removing some parts, you can obviously start from either exterior point that used to connect to another but no longer does and just walk from there until you get to the other.
You can't handle this stuff in a shader under ES because you don't get connectivity information.
I think the best you could do in a shader is to expand the geometry by pushing vertices outward along their surface normals. Supposing that your data structure is a list of rectangles, each described by, say, a centre, a width and a height, you could achieve the same thing by drawing each with the same centre but with a small amount added to the width and height.
To be completely general you'd need to store normals at vertices, but also to update them as geometry is removed. So there'd be some pushing of new information from the CPU but it'd be relatively limited.
I try to create a scene for physical simulation. The scene consists of rectangular floes floating in a rectangular pond. Something like this:
So I need to fill a rectangular area with non-intersecting rotated rectangles with widths and heights in a specified range. I don't need to find an optimal coverage of the area. The goal is just to generate floes of different size without intersections.
And I'd like to get a solution without any dynamics, only using collision detection algorithms.
You could consider simulating a collection of boxes falling into a square bucket and saving the positions of all the boxes once they come to rest.
box2d is an open source 2D physics library that can do this for you - you might recognise it as the physics engine behind Angry Birds and umpteen-million Flash games.
There is what I would do:
Suppose the length of the rectangles are between [MaxSize MinSize]
r <- MaxSize
do{
Trying adding non-intersecting circles to the area with radius r and random center (x,y). We use circle instead of rectangle because intersection detecting for circles are easier than rectangles. e.g. if distance(x,y,x',y')<r+r' then we are good.
If adding circle failed{
r--;
if r< MinSize break;
}
}
Now you will have a plane full of on intersecting squares. There will be gaps because we were using circles as intersection detection. If this is not good enough for you, grow the squares to rectangles. You can do this by checking all points against a certain border and decide how much you can grow it.
To model solid (ie non-intersecting) objects, you could use a physics engine. As it happens I just the other day read Farseer tutorial for the absolute beginners, which includes a video depicting almost exactly your requirement. Farseer is a .NET version of box2d, which you may have heard of.
Starting with a 3D mesh, how would you give a rounded appearance to the edges and corners between the polygons of that mesh?
Without wishing to discourage other approaches, here's how I'm currently approaching the problem:
Given the mesh for a regular polyhedron, I can give the mesh's edges a rounded appearance by scaling each polygon along its plane and connecting the edges using cylinder segments such that each cylinder is tangent to each polygon where it meets that polygon.
Here's an example involving a cube:
Here's the cube after scaling its polygons:
Here's the cube after connecting the polygons' edges using cylinders:
What I'm having trouble with is figuring out how to deal with the corners between polygons, especially in cases where more than three edges meet at each corner. I'd also like an algorithm that works for all closed polyhedra instead of just those that are regular.
I post this as an answer because I can't put images into comments.
Sattle point
Here's an image of two brothers camping:
They placed their simple tents right beside each other in the middle of a steep walley (that's one bad place for tents, but thats not the point), so one end of each tent points upwards. At the point where the four squares meet you have a sattle point. The two edges on top of each tent can be rounded normally as well as the two downward edges. But at the sattle point you have different curvature in both directions and therefore its not possible to use a sphere. This rules out Svante's solution.
Selfintersection
The following image shows some 3D polygons if viewed from the side. Its some sharp thing with a hole drilled into it from the other side. The left image shows it before, the right after rounding.
.
The mass thats get removed from the sharp edge containts the end of the drill hole.
There is someething else to see here. The drill holes sides might be very large polygons (lets say it's not a hole but a slit). Still you only get small radii at the top. you can't just scale your polygons, you have to take into account the neighboring polygon.
Convexity
You say you're only removing mass, this is only true if your geometry is convex. Look at the image you posted. But now assume that the viewer is inside the volume. The radii turn away from you and therefore add mass.
NURBS
I'm not a nurbs specialist my self. But the constraints would look something like this:
The corners of the nurbs patch must be at the same position as the corners of the scaled-down polygons. The normal vectors of the nurb surface at the corners must be equal to the normal of the polygon. This should be sufficent to gurarantee that the nurb edge will be a straight line following the polygon edge. The normals also ensure that no visible edges will result at the border between polygon and nurbs patch.
I'd just do the math myself. nurbs are just polygons. You'll have some unknown coefficients and your constraints. This gives you a system of equations (often linear) that you can solve.
Is there any upper bound on the number of faces, that meet at that corner?
You might you might employ concepts from CAGD, especially Non-Uniform Rational B-Splines (NURBS) might be of interest for you.
Your current approach - glueing some fixed geometrical primitives might be too inflexible to solve the problem. NURBS require some mathematical work to get used to, but might be more suitable for your needs.
Extrapolating your cylinder-edge approach, the corners should be spheres, resp. sphere segments, that have the same radius as the cylinders meeting there and the centre at the intersection of the cylinders' axes.
Here we have a single C++ header for generating triangulated rounded 3D boxes. The code is in C++ but also easy to transplant to other coding languages. Also it's easy to be modified for other primitives like quads.
https://github.com/nepluno/RoundCornerBox
As #Raymond suggests, I also think that the nepluno repo provides a very good implementation to solve this issue; efficient and simple.
To complete his answer, I just wrote a solution to this issue in JS, based on the BabylonJS 3D engine. This solution can be found here, and can be quite easily replaced by another 3D engine:
https://playground.babylonjs.com/#AY7B23