Three JS - Strange raycast behaviour when objects are moved - javascript

Version and info
THREE.ObjectLoader2: 2.4.1
THREE.LoaderSupport.MeshBuilder: 1.2.1
THREE.LoaderSupport.WorkerSupport: 2.2.0
THREE.WebGLRenderer: 93
THREE.REVISION: 93
The problem
When I raycast an object in my scene, I found that it worked perfectly down to the pixel, until I moved the object. In my program I expload the scene, so I move all the objects, and child objects away from the center of the scene.
To easily visualise the issue instead of raycasting a single point at a mouse click, I opted to raycast the entire screen, this is what I get (Figure 1)
(Figure 1)
The reason for the gaps is because it took to long to raycast every pixel, so instead I raycasted every fourth. The reason for the gap in the middle is because I zoomed away from the original position.
Now, see what happens when I expload the object (Figure 2),
(Figure 2)
As you can see, there is almost a circle. Why is this?
What I've tried
I've tried many things across the internet, and came here when I could find no more.
I've tried a range of different models, some work differently to others, strangely enough. The lamborghini-aventador which was created in Blender works the strangest.
To see if it was a problem with the exploading code, I moved the object to the right. This is where things get interesting (Figure 3).
(Figure 3)
It looks as if my outlining I put on the object (the outlines are an EdgesGeometry) is behind, the actual object is in the middle, and the raycasts are further.
What I speculate
I suspect the issue is to do with scaling. So I tried removing all scaling I did in the code, however I got the same result, unfortunately.
Apologies if this is some noobie mistake, though I do hope it is :)
The code
For those who are adventurous enough to delve into my terrible code base, here it is (the majority of the code is inside demo.js):
github
Testing it
Press G to shoot the raycasts (will freeze for a bit), press X to expload, press S to unexpload. Standard orbit controls.
What I've found
Here are some of the links I have already found and tried on this issue:
https://threejs.org/docs/#api/core/Raycaster
Three.js Raycaster not detecting scene mesh
https://github.com/mrdoob/three.js/issues/1325 (Updating the matrix)
http://barkofthebyte.azurewebsites.net/post/2014/05/05/three-js-projecting-mouse-clicks-to-a-3d-scene-how-to-do-it-and-how-it-works (Followed step by step)
... and many more ...
Any ideas?

I think that your model might not have proper bounding boxes/spheres generated.
The circular shape could result from the rays passing the bounding sphere check of a bounding sphere that is too small.
You mention resizing/processing your geometries in some way... After you do that, try calling geometry.computeBoundingBox() and geometry.computeBoundingSphere() to rebuild boxes and spheres, and see if that helps?
edit: Apparently this problem was due to bounding boxes and spheres not being recomputed...
the fix was to:
scene.traverse( (o)=>if(o.geometry){o.geometry.computeBoundingBox();o.geometry.computeBoundingSphere();} );

Related

Using ThreeJS StereoEffect and Raycaster

Has anybody used ThreeJS StereoEffect and Raycaster together for collision detection (in stereo view). In standard full screen view I can easily check if a Vector2 in the middle of the screen colides with an object in my scene. When I switch on the stereo effect I in effect get 2 scenes, and the collision detection stops working, but I am not really sure how to proceed. Should I create two new vector2d objects, one for each view - help :) ...
It's a bit late, but ...
I encountered a similar problem, I eventually found the reason. Actually in StereoEffect THREE.js displays the meshes on the two eyes, but in reality is actually adds only one mesh to the scene, exactly in the middle of the line left-eye-mesh <-> right-eye-mesh, hidden to the viewer.
So when you use the raycaster, you need to use it on the real mesh on the middle, not the illusion displayed on each eye !
I detailled here how to do it
Three.js StereoEffect displays meshes across 2 eyes
Hopes it solves your problem !
You can use my StereoEffect.js file in your project for resolving problem. See example of using.

Position resizable circles near each other

I am working on this browser-based experiment where i am given N specific circles (let's say they have a unique picture in them) and need to position them together, leaving as little space between them as possible. It doesn't have to be arranged in a circle, but they should be "clustered" together.
The circle sizes are customizable and a user will be able to change the sizes by dragging a javascript slider, changing some circles' sizes (for example, in 10% of the slider the circle 4 will have radius of 20px, circle 2 10px, circle 5 stays the same, etc...). As you may have already guessed, i will try to "transition" the resizing-repositioning smoothly when the slider is being moved.
The approach i have tried tried so far: instead of manually trying to position them i've tried to use a physics engine-
The idea:
place some kind of gravitational pull in the center of the screen
use a physics engine to take care of the balls collision
during the "drag the time" slider event i would just set different
ball sizes and let the engine take care of the rest
For this task i have used "box2Dweb". i placed a gravitational pull to the center of the screen, however, it took a really long time until the balls were placed in the center and they floated around. Then i put a small static piece of ball in the center so they would hit it and then stop. It looked like this:
The results were a bit better, but the circles still moved for some time before they went static. Even after playing around with variables like the ball friction and different gravitational pulls, the whole thing just floated around and felt very "wobbly", while i wanted the balls move only when i drag the time slider (when they change sizes). Plus, box2d doesn't allow to change the sizes of the objects and i would have to hack my way for a workaround.
So, the box2d approach made me realize that maybe to leave a physics engine to handle this isn't the best solution for the problem. Or maybe i have to include some other force i haven't thought of. I have found this similar question to mine on StackOverflow. However, the very important difference is that it just generates some n unspecific circles "at once" and doesn't allow for additional specific ball size and position manipulation.
I am really stuck now, does anyone have any ideas how to approach this problem?
update: it's been almost a year now and i totally forgot about this thread. what i did in the end is to stick to the physics model and reset forces/stop in almost idle conditions. the result can be seen here http://stateofwealth.net/
the triangles you see are inside those circles. the remaining lines are connected via "delaunay triangulation algorithm"
I recall seeing a d3.js demo that is very similar to what you're describing. It's written by Mike Bostock himself: http://bl.ocks.org/mbostock/1747543
It uses quadtrees for fast collision detection and uses a force based graph, which are both d3.js utilities.
In the tick function, you should be able to add a .attr("r", function(d) { return d.radius; }) which will update the radius each tick for when you change the nodes data. Just for starters you can set it to return random and the circles should jitter around like crazy.
(Not a comment because it wouldn't fit)
I'm impressed that you've brought in Box2D to help with the heavy-lifting, but it's true that unfortunately it is probably not well-suited to your requirements, as Box2D is at its best when you are after simulating rigid objects and their collision dynamics.
I think if you really consider what it is that you need, it isn't quite so much a rigid body dynamics problem at all. You actually want none of the complexity of box2d as all of your geometry consists of spheres (which I assure you are vastly simpler to model than arbitrary convex polygons, which is what IMO Box2D's complexity arises from), and like you mention, Box2D's inability to smoothly change the geometric parameters isn't helping as it will bog down the browser with unnecessary geometry allocations and deallocations and fail to apply any sort of smooth animation.
What you are probably looking for is an algorithm or method to evolve the positions of a set of coordinates (each with a radius that is also potentially changing) so that they stay separated by their radii and also minimize their distance to the center position. If this has to be smooth, you can't just apply the minimal solution every time, as you may get "warping" as the optimal configuration might shift dramatically at particular points along your slider's movement. Suffice it to say there is a lot of tweaking for you to do, but not really anything scarier than what one must contend with inside of Box2D.
How important is it that your circles do not overlap? I think you should just do a simple iterative "solver" that first tries to bring the circles toward their target (center of screen?), and then tries to separate them based on radii.
I believe if you try to come up with a simplified mathematical model for the motion that you want, it will be better than trying to get Box2D to do it. Box2D is magical, but it's only good at what it's good at.
At least for me, seems like the easiest solution is to first set up the circles in a cluster. So first set the largest circle in the center, put the second circle next to the first one. For the third one you can just put it next to the first circle, and then move it along the edge until it hits the second circle.
All the other circles can follow the same method: place it next to an arbitrary circle, and move it along the edge until it is touching, but not intersecting, another circle. Note that this won't make it the most efficient clustering, but it works. After that, when you expand, say, circle 1, you'd move all the adjacent circles outward, and shift them around to re-cluster.

HTML Canvas: mouse click hit test by using ghost canvas - anti-aliasing troubles

I'm writing an JavaScript application that is drawing arbitrarily shaped objects on a HTML canvas. The user should be able to select any of the objects by clicking on them.
To make this an O(1) operation I'm using a shadow canvas, i.e. a not displayed canvas that has exactly the same size, where each object drawn on the normal canvas is also drawn there - but with a color that represents it's ID.
So a simple ghostContex.getImageData() together with the mouse click coordinates gives me the color at that pixel and thus the ID of the clicked object.
All of that is working fine - except when I click on the exact border of an object.
As it's drawn with anti-aliasing on the ghost canvas I get a wrong color (as that color is a mixture between the correct ID and the ID of the object under it that was drawn before...). This wrong color is representing a wrong ID and thus I'm selecting a totally different object :(
How can I solve that problem?
Note #1: I'm already using the translate(0.5, 0.5) trick to prevent most anti-aliasing
Note #2: I was trying to write this application with SVG before, but especially this object selection was extremely slow as I guess it's been too many objects for the collision detection. That's the main reason why I want a O(1) approach now... Oh, and this way I can easily draw a much bigger line on the ghost canvas than the line is drawn on the normal canvas to make picking much easier.
Note #3: Relevant browsers are Firefox, Chrome, Android 2.3+ native and iOS native
The reason why I couldn't accept any answer here is quite easy and quite sad: it doesn't exist... :(
The antialiasing can not be switched of, the standard has no method for that. But the standard does have a hit test function (http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas_CR/#hit-regions) that would do exactly what is needed here. Even in a nice way that would hide the nasty details for the developer - but it's not implemented in any of the browsers right now.
And implementation was looking to be far away till impossible (see e.g. comment #6 at https://code.google.com/p/chromium/issues/detail?id=328961). But apparently it gained momentum during the last month...
So what can be done in the mean time? What did I do?
In my code I could implement for each shape a isPointInShape() method. So I use the ghost canvas trick to get a shape and verify with the isPointInShape() that I really selected the correct shape. This helps in the anti aliased pixels not to pick a wrong shape (just think of clicking on the border of shape #2 where we had a 50% antialias transparency - this would tell you wrongly a selection of shape #1...).
If implementing a generic isPointInShape() is quite hard for your shape you could try a trick that I was reading of somewhere else (I didn't try it tough, so I haven't tested it...):
Create an additional ghost canvas of size 1x1 pixel that is positioned exactly on the mouse position. Then draw the shape of interest - when the A of the RGBA is changed, this shape does belong to that pixel.
I know this is an old post, but recently I had a similar issue. The way I solved the "seam of two colors" problem was doing a 10x10 pixel sampling of the secondary canvas instead of a single pixel. I then stringified the RGB values and used these as keys in a map that mapped to the object that color represents. So initially with the 1 pixel sampling I used the map immediately to determine the associated object but antialiasing created halfway colors that didn't exist in the map. The 10x10 method solves this problem by looping through the 100 RGB values returned and creating a "counting map." This map uses the stringified colors and maps them to a count, but only includes valid colors from the first map in the count. So you end up with a map saying you counted 65 red pixels and 23 blue pixels (where the remaining 12 pixels were some weird anti-alias hybrid). In the same loop where I was counting the colors I also maintained a variable for current max count and current color associated with that max count (to avoid looping through this new map again). Now at the end you have the color that was counted the most in that 10x10 sampling and can use that to map back to the object associated with it. You will only get an undefined result if no valid colors were found in the 10x10 sample which you can reasonably assume means the "background" was clicked.
I made up the name ghost context! Are you using my old tutorial? :)
In that old tutorial I do not clear the ghost context after each object is drawn to it. In your case, to fix your issue, you may need to clear after testing each object on the ghost context.
Make sure of course that you are translating the ghost context and normal context by precisely the same amounts. (and translating them back, or resetting the transformation, afterwards).

three.js outer glow for sphere object?

I'm building some sort of planetary system in three.js and I spent couple of hours looking for a decent solution to get an outer glow on one planet - a sphere object with a texture.
I came across this example http://stemkoski.github.io/Three.js/Selective-Glow.html which kind of does the trick, but the thing is - this form of glow also affects the main 3D object resulting in color change (as seen there).
Another nice glow example can be found here http://bkcore.com/blog/3d/webgl-three-js-animated-selective-glow.html but again it glows the entire region, not only "outer" thing.
I've been reading some discussion thread about "overrideMaterial" property on GitHub but this seems experimental, unused and undocumented... not even sure if this could solve my problem.
Please share your ideas, thanks!
I've worked a bit on separating out the part of the WebGL Globe code (linked to above) that produces the atmospheric effect. A preliminary working version is here:
http://stemkoski.github.io/Three.js/Atmosphere.html
To the best of my understanding, there are a few interesting things going on in the original code to create the atmospheric effect. First, the glowing texture is placed on another sphere -- let's call it the Atmo Sphere :) -- that surrounds the sphere with the image of earth on it. The Atmosphere material is flipped so that the front side does not render, only the back side, thus it does not obscure the earth sphere even though it surrounds it. Second, the gradient lighting effect is achieved by using a fragment shader rather than a texture. However, the atmosphere will change its appearance if you zoom in and out; this was not evident in the WebGL Globe experiment because zooming was disabled.
[updated April 30th]
Next, similar to the source code from
http://stemkoski.github.io/Three.js/Selective-Glow.html
the sphere with the gradient lighting texture (and another black-textured sphere) are placed in a second scene, and then the results from that scene are composed with the original scene using an additive blender. And just so you can experiment with the parameters used to create the glow effect, I have included a couple of sliders so that you can change the values and see the different glow effects that result.
I hope this helps you get started. Good luck!
[updated June 11]
I have a new example which achieves the same effect in a much simpler way, rather than using post-processing and additively blending two scenes, I just changed some of the parameters in the customized material. (It seems obvious in retrospect.) For an updated example, check out:
http://stemkoski.github.io/Three.js/Shader-Halo.html
Still haven't figured out the pan/zoom issues though.
[Updated July 24]
I figured out the pan/zoom issues. It requires using a shader; for details about the complexities, see the related question Three.js - shader code for halo effect, normals need transformation and for the final working example, see:
http://stemkoski.github.io/Three.js/Shader-Glow.html.
I'm pretty happy with the final result, so I will not be updating this answer any more :)
In the example you are referring to, I used a blue glow with additive blending -- if you used a white color instead maybe that would produce the effect you want.

Canvas code not working in IE9 - probably alpha or globalCompositeOperation issue

I have a javascript routine which is designed to flickering sun rays. The routine creates 'numRays' rays, then begins to overwrite the rays using globalCompositeOperation = 'copy' and drawing a transparent ray over the oldest ray.
You can see the program here:Sun Ray Page
JSFiddle.net code located here:JSFiddle Sun Rays (I'm not sure how to make it work on JSFiddle, so if someone can fix my fiddle, I'd appreciate that, too.)
(Note: I have left a yellow stroke around the erased rays for diagnostic purposes, so you can see them executed.)
The code works in Chrome and Firefox, however, in IE9, the original rays are not drawn when I leave the erase section active. In other words, if I remark out the section that creates the erase stroke, the ray fills occur. If I do not, then only the erase strokes occur.
I have tested various fixed alpha values and IE9 seems to handle them perfectly. I've set both sections to globalCompositeOperation = 'source-over' and still do not get the original rays.
Can someone help me correct this code to work on IE9?
Thanks
It isn't working in jsfiddle because you never call init()
IE9 is probably breaking script execution on the line:
ctx.rotate(rayArray[currentRay]); // Rotate to the rayAngle
Because it throws an error the first 11 times it is called, because you keep trying to access a value that is undefined the first 10-11 times through.
So I moved your incrementing code down to after the ctx.rotate statement and added the init. It doesn't have errors in IE or FireFox, but I have no way of knowing if its what you intended:
http://jsfiddle.net/Y5Y48/18/

Categories

Resources