ThreeJs create object from another object - javascript

I have an object created from importing an .obj
I want to clone this object and give it it's own coordinates.
To be more precise, I have a wall, for which I attach another object (a window) as a child. It all works fine when dragging the window along the wall. Now, when I want to clone the wall and rotate it 180 degrees, dragging the child along it's parent goes exactly the opposite way from the mouse movement.
I would like to reuse the same obj wall for all sides of my building.

You are describing two problems.
One is how to clone an object and give it a different position:
var wallCopy = wall.clone();
scene.add(wallCopy);
wallCopy.position.set( 10,20,30 );
The other question is moving an object in Object space instead of World space.
I.e. if you change the position.x of an object (the window) that is a child of a rotated object, the object will move relative to its rotated parent.
If you are building some sort of editor, you can use SceneUtils to make this easier...
https://threejs.org/docs/#examples/utils/SceneUtils
At the start of your edit, you would detach the window and attach it to the scene, using SceneUtils.detach... then apply your edit movement, and when the movement is done, attach it back to the wall using SceneUtils.attach.
SceneUtils takes care of keeping the visual transform consistent between the detach and attach operations between different places on the scene hierarchy.
edit: So a way to handle the case you describe in comments, without doing anything fiddly, is to just use more intermediate nodes. You can always set up your scaling and stuff on the child nodes, (You can always update thier matrices and then set their matrixAutoUpdate = false; if you're paranoid about the performance impact.}
Here's what I mean:
{"root", scale:1, children:[anchor1, anchor2]}
{"anchor1" scale:1, children:[wall]} {"anchor2" scale:1, children:[wall2]}
Then you can just manipulate the anchors or root to move things around, and the scaling of "wall" will be isolated to its own little sub tree.

Related

how can i transform Object3D Coordinates with values based on world position Coordinates?

hello i have a spinning parent object containing a bunch of child objects. theese child objects are programmed to move on based on the cursor. however the x and y coordinates are completely relative to the spinning parent object. so whenever i want the child to move left-"-x relative to the world coordinates" it moves "-x relative to its parents coordinates"
image of what i have and want
i dont believe deataching the child from the parent will do in my situation...
i think the best approach is if its possible to calculate the direction i want from the objects local coordinates, but i dont really know hence im asking
picture of actual object / "chieldren"
I suggest you do the following:
Detach the child from its parent with scene.attach( child );
Perform the transformation in world space
Attach the object back to its parent via parent.attach( child );
The important bit here is the usage of Object3D.attach().
three.js R114

Bring new ThreeJS child element in a scene to front and center?

I have a web page that is based on the following ThreeJS sample:
http://threejs.org/examples/#css3d_molecules
I create new nodes (atoms) dynamically by attaching them to existing nodes (atoms). After creating it and adding it to the scene, I want to bring the new atom/child element to the forefront using the minimum number of rotate, pan, & zoom operations needed to do so. However, although I know how to do each of those operations, I don't know how to calculate the optimal sequence based on the current position/quaternion of the node (atom) where I created it in the scene, and its new position which will be (0, 0, ). I will be animating the change from the old place in the scene to the new so I don't want to just change the new element's position/quaternion to the new value via an assignment. I want animate the change over time, performing a slice of each operation (pan/zoom/rotate) each animation frame.
Are there any ThreeJS methods to help me do this?
See how to: get the global/world position of a child object to get world position of any mesh in your hierarchy. Then have your camera.lookAt() to that location.

css3 matrix3d value applied using jQuery not taking

I'm experimenting with rotating/animating an environment using CSS3 and javascript. So I have a cube object with faces, which lives inside a "rotator" object, which is the object that gets interacted with in the UI. I want to make it so that when you click a face, it appends it to a div outside of the rotator div, but applies the transformation matrices to the object from its parents, so that it appears with the same orientation on the outside of the "rotator" as it did inside, but can be animated and become independent of the rest of the objects in the "rotator" div.
Here is the function for the click event that should do this:
This depends on several custom functions, please see the fiddle for full code and reference to functions.
jQuery('#top').on('click',function(){
if(jQuery(this).parent().is('#cube')){ // only do this if it isn't already detached
M = jQuery(this).getTransMatrix(); // get the local transform of this
M = M.multiply(jQuery('#rotator').getTransMatrix()); // multiply it by the rotator's transform to get the final transform
jQuery(this).appendTo('#container'); // move this to the container div outside of the rotator
jQuery(this).css(CSS3.prefix+'transition','none'); // make sure that style changes, etc happen instantly
// wtf here
console.log(M.cssTransformString()); // just to check, we see the transform string before it is assigned. It's what it should be in my tests
jQuery(this).css(CSS3.prefix+'transform',M.cssTransformString()); // we apply the string. The wrong transformation results. If I double-check it from the console, it is NOT the string from the previous line
}
});
If you check out the fiddle, you will be able to drag around to rotate the cube. Clicking on the face will have some effect. The top face with the star is the one in question. When clicked, simply does not apply the transformation. Even if I log to console the transform string it's about to apply, the next operation does NOT result in that string being applied. It simply does not stick. HOWEVER, if I click and drag slightly, then release with the cursor still on the face, THEN the transform sticks. I have tried tracing virtually everything and I cannot figure out why the transform is only sticking if you click normally (without holding/moving at all)
Fiddle here:
http://jsfiddle.net/spaceboycoop/PWkB9/

Three.js constrain object drag to surface of another object

I want to be able to drag an object, but have it 'snap' to the surface of another.
I don't care if it only 'snaps' when I release the mouse, or if it updates live.
Ultimate goal: create a smooth shape in Blender, import it, and be able to snap drag to that shape. I know I can do this with procedurally generated surfaces with a bit of math, but I'm looking to use some non-procedurally generated surfaces.. or at least, the surfaces I'm wanting to use I haven't figured out how to generate procedurally yet.
I tried taking this example: http://stemkoski.github.io/Three.js/Mouse-Click.html and changing the 'click' effect to a 'drag' effect. Then I incorporated it with this example: http://mrdoob.github.io/three.js/examples/webgl_interactive_draggablecubes.html
The effect is working, in that I can drag any of the cubes across the sphere, and the face hilights.
Then I tried taking the dragged object, and snapping it to the face of the sphere using this flawed logic:
SELECTED.position.x = intersectsRay[ 0 ].face.normal.x;
SELECTED.position.y = intersectsRay[ 0 ].face.normal.y;
SELECTED.position.z = intersectsRay[ 0 ].face.normal.z;
The problem: the dragged objects always snap to the center of the sphere...
The reason being, (I think . . . ) is the face 'normal' is the center of the (sphere) in this case.
Does anyone know a way to find the x,y,z of the FACE (no matter what the shape), or any other way to implement this concept?
An easy solution would be to not use the local (and normalized) face normal, instead for example you could use the vertex index.
Something like:
intersectedOBJ.geometry.vertices[intersect.face.a]
This way, you would snap your dragged object to one of the face's vertices.
Also there is a face "centroid" that you can use or you could calculate the center of the face on your own.

Detect mouseover of certain points within an HTML canvas?

I've built an analytical data visualization engine for Canvas and have been requested to add tooltip-like hover over data elements to display detailed metrics for the data point under the cursor.
For simple bar & Gaant charts, tree graphs and node maps with simple square areas or specific points of interest, I was able to implement this by overlaying absolutely-positioned DIVs with :hover attributes, but there are some more complicated visualizations such as pie charts and a traffic flow rendering which has hundreds of separate areas defined by bezeir curves.
Is is possible to somehow attach an overlay, or trigger an event when the user mouses over a specific closed path?
Each area for which hover needs to be specified is defined as follows:
context.beginPath();
context.moveTo(segmentRight, prevTop);
context.bezierCurveTo(segmentRight, prevTop, segmentLeft, thisTop, segmentLeft, thisTop);
context.lineTo(segmentLeft, thisBottom);
context.bezierCurveTo(segmentLeft, thisBottom, segmentRight, prevBottom, segmentRight, prevBottom);
/*
* ...define additional segments...
*/
// <dream> Ideally I would like to attach to events on each path:
context.setMouseover(function(){/*Show hover content*/});
// </dream>
context.closePath();
Binding to an object like this is almost trivial to implement in Flash or Silverlight, since but the current Canvas implementation has the advantage of directly using our existing Javascript API and integrating with other Ajax elements, we are hoping to avoid putting Flash into the mix.
Any ideas?
You could handle the mousemove event and get the x,y coordinates from the event. Then you'll probably have to iterate over all your paths to test if the point is over the path. I had a similar problem that might have some code you could use.
Looping over things in this way can be slow, especially on IE. One way you could potentially speed it up - and this is a hack, but it would be quite effective - would be to change the color that each path is drawn with so that it is not noticeable by humans but so that each path is drawn in a different color. Have a table to look up colors to paths and just look up the color of the pixel under the mouse.
Shadow Canvas
The best method I have seen elsewhere for mouseover detection is to repeat the part of your drawing that you want to detect onto a hidden, cleared canvas. Then store the ImageData object. You can then check the ImageData array for the pixel of interest and return true if the alpha value is greater than 0.
// slow part
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillRect(100,100,canvas.width-100,canvas.height-100);
var pixels = ctx.getImageData(0,0,canvas.width,canvas.height).data;
// fast part
var idx = 4 * (mouse_x + mouse_y * canvas.width) + 3;
if (pixels[idx]) { // alpha > 0
...
}
Advantages
You can detect anything you want since you're just repeating the context methods. This works with PNG alpha, crazy compound shapes, text, etc.
If your image is fairly static, then you only need to do this one time per area of interest.
The "mask" is slow, but looking up the pixel is dirt cheap. So the "fast part" is great for mouseover detection.
Disadvantages
This is a memory hog. Each mask is W*H*4 values. If you have a small canvas area or few areas to mask, it's not that bad. Use chrome's task manager to monitor memory usage.
There is currently a known issue with getImageData in Chrome and Firefox. The results are not garbage collected right away if you nullify the variable, so if you do this too frequently, you will see memory rise rapidly. It does eventually get garbage collected and it shouldn't crash the browser, but it can be taxing on machines with small amounts of RAM.
A Hack to Save Memory
Rather than storing the whole ImageData array, we can just remember which pixels have alpha values. It saves a great deal of memory, but adds a loop to the mask process.
var mask = {};
var len = pixels.length;
for (var i=3;i<len;i+=4) if ( pixels[i] ) mask[i] = 1;
// this works the same way as the other method
var idx = 4 * (mouse_x + mouse_y * canvas.width) + 3;
if (mask[idx]) {
...
}
This could be done using the method ctx.isPointInPath, but it is not implemented in ExCanvas for IE.
But another solution would be to use HTML maps, like I did for this little library : http://phenxdesign.net/projects/phenx-web/graphics/example.htm you can get inspiration from it, but it is still a little buggy.
I needed to do detect mouse clicks for a grid of squares (like cells of an excel spreadsheet). To speed it up, I divided the grid into regions recursively halving until a small number of cells remained, for example for a 100x100 grid, the first 4 regions could be the 50x50 grids comprising the four quadrants.
Then these could be divided into another 4 each (hence giving 16 regions of 25x25 each).
This requires a small number of comparisons and finally the 25x25 grid could be tested for each cell (625 comparisons in this example).
There is a book by Eric Rowell named "HTML5 CANVAS COOKBOOK". In that book there is a chapter named "Interacting with the Canvas: Attaching Event Listeners to Shapes and Regions". mousedown, mouseup, mouseover, mouseout, mousemove, touchstart, touchend and touchmove events can be implemented. I highly suggest you read that.
This can't be done (well, at least not that easily), because objects you draw on the canvas (paths) are not represented as the same objects in the canvas. What I mean is that it is just a simple 2D context and once you drawn something on it, it completely forgets how it was drawn. It is just a set of pixels for it.
In order to watch mouseover and the likes for it, you need some kind of vector graphics canvas, that is SVG or implement your own on top of existing (which is what Sam Hasler suggested)
I would suggest overlaying an image map with proper coordinates set on the areas to match your canvas-drawn items. This way, you get tooltips AND a whole lot of other DOM/Browser functionality for free.

Categories

Resources