Three.js - Using box3 to scale and translate an object - javascript

I'm currently working on a piece of code that loads up a 3D image which initially isn't visible. It is supposed to be visible, however, after scaling and translating it, but no matter what I do, the screen remains black and I cannot see the 3D image.
I won't post the entire code but here's the section about the scaling and translating (the code portions that I've commented out is what I tried to implement as the solution):
const box = new THREE.Box3().setFromObject(object);
// object.scale.set( 2, 2, 2 );
// box.getCenter(object.position);
// object.geometry.center();
scene.add( object );
I'm confused whether I'm misunderstanding Box3, whether it has to do with the order in which I'm scaling/centering, or if it's my values, or something trivial that I'm forgetting to add.
EDIT: I believe that I need to properly size the bounding box around the image, and use that to scale the tiger. I'm still confused about this, because I assumed this line already did that:
const box = new THREE.Box3().setFromObject(object);
So I'm not sure how I can change the size of the bounding box so it is correct, and then scale it to the size I want.

Related

Can I access Mask>Mask Path>Shape>BoundingBox properties via Extenscript?

I am wondering if there's a way to access the Bounding Box Gui properties of mask shapes so that I can see how to create perfect circle shape masks in After Effects?
My code is below:
maskpath = app.project.item(1).layer("Orange Solid 2").property("ADBE Mask Parade").property("ADBE Mask Atom").property("ADBE Mask Shape");
Not sure what you mean by "access the Bounding Box Gui properties of mask shapes", but I do think I know what you mean by "how to create perfect circle shape masks in After Effects".
See D. Ebberts' script code posted here: http://aenhancers.com/viewtopic.php?f=11&t=2084
I believe it does (or will lead you to do) what you want.
I found the answer from After-Effects-CS6-Scripting-Guide.pdf page 48
AVLayer sourceRectAtTime() method
Retrieves the rectangle bounds of the layer at the specified time index, corrected for text or shape layer content.
Use, for example, to write text that is properly aligned to the baseline.
app.project.item(index).layer(index).sourceRectAtTime(timeT, extents)
Returns
A JavaScript object with four attributes: [top, left, width, height].
I think you are talking about how to access Left Top Right Bottom values of this window.
This window appears when you click on shape of mask path
(position where pointing hand drown blue color arrow)
please any one can tell me how to access those values via Script

Circular canvas corners clickable in Chrome

I have two canvases. I have made them circular using border-radius. The 2nd is positioned inside the first one (using absolute position).
I have click events on both circles. If you click on inside canvas, the color at the point of the click is loaded in the outside canvas with opacity varying from white to the picked color and finally to black. If you click on outer canvas the exact color value at that point is loaded in the text-box at the bottom
I am unable to click in red zones (as shown in figure below) of the outer canvas when using chrome. I tried z-idex, arcs but nothing is helping me. But In Firefox everything is working fine.
Note: You can drag the picker object in the outer circle. But if you leave it in red zones, you would not be able to click it again in Chrome. Clicking in green zone will get you its control again
Code in this JSFiddle
Edit
I excluded all irrelevant code to make it easy. Now there is only a container having two canvas.
Filled simply with two distinct colors. Open following fiddle link in both chrome and firefox. Click on both cirles in different zones and see difference in chrome and firefox. I want them to behave in chrome as they do in firefox
Note I will ultimately draw an image in inner canvas.
Updated Fiddle Link
-
Your problem is because canvases currently are always rectangular, even if they don't look rectangular. Border radius makes the edges except the circle transparent, but it still doesn't stop events in Chrome on the corner areas. This is why you cannot click the bottom circle in those areas
I even tried putting it inside of a container that had a border-radius instead but the click event still goes through
With that being said, you have two options. You could either change your code to only use one canvas with the same type of layout, just drawing the background circle before the other each time. Essentially you'd draw a circle, draw your black to color to white gradient, use the xor operation to combine the two into one circle, then do the same with the rainbox gradient. You must draw the background circle first because canvas paints over the old layers every time
or
You could use javascript to only detect clicks in the circular area which takes just a little bit of math (: This solution is featured in edit below
In the future, CSS Shapes may allow canvases to be non-rectangular elements to be used, I'm actually not sure, but we don't have that capability yet at least
Edit
Alright, so after going through your code a bit it seems there are some things I should cover before I offer a solution
Setup all your finite variables outside of the functions that run every time. This means you don't put them (like radiuses, offsets, etc.) in the click function or something that runs often since they don't change
Your "radius"es are actually "diameter"s. The format of .rect goes .rect(x, y, width (diameter of circle), height (diameter of circle))
Almost always when overlaying canvases like you are you want to make them equal dimensions and starting position to prevent calculation error. In the end it makes it easier, doing all relative positioning with javascript instead of mixing it with CSS. In this case, however, since you're using border-radius instead of arc to make a circle, keep it like it is but position it using javascript ....
jQuery isn't needed for something this simple. If you're worried about any load speed I'd recommend doing it in vanilla javascript, essentially just changing the .click() functions into .onclick functions, but I left jQuery for now
You can declare multiple variables in a row without declaring var each time by using the following format:
var name1 = value1,
name2 = value2;
Variables with the same value you can declare like so:
var name1 = name2 = sameValue;
When children have position:absolute and you want it to be positioned relative to the parent, the parent can have position:relative, position:fixed, or position:absolute. I would think you'd want position:relative in this case
When you don't declare var for a variable it becomes global (unlessed chained with a comma like above). For more on that read this question
Now, onto the solution.
After talking with a friend I realized I could sort do the math calculation a lot easier than I originally thought. We can just calculate the center of the circles and use their radiuses and some if statements to make sure the clicks are in the bounds.
Here's the demo
After everything is set up correctly, you can use the following to detect whether or not it's in the bounds of each
function clickHandler(e, r) {
var ex = e.pageX,
ey = e.pageY,
// Distance from click to center
l = Math.sqrt(Math.pow(cx - ex, 2) + Math.pow(cy - ey, 2));
if(l > r) { // If the distance is greater than the radius
if(r === LARGE_RADIUS) { // Outside of the large
// Do nothing
} else { // The corner area you were having a problem with
clickHandler(e, LARGE_RADIUS);
}
} else {
if(r === LARGE_RADIUS) { // Inside the large cirle
alert('Outer canvas clicked x:' + ex + ',y:' + ey);
} else { // Inside the small circle
alert('Inner canvas clicked x:' + ex + ',y:' + ey);
}
}
}
// Just call the function with the appropriate radius on click
$(img_canvas).click(function(e) { clickHandler(e, SMALL_RADIUS); });
$(wheel_canvas).click(function(e) { clickHandler(e, LARGE_RADIUS); });
Hopefully the comments above and code make enough sense, I tried to clean it up as best as I could. If you have any questions don't hesitate to ask!

Reloading an image after zooming in KineticJS

I have a group, inside of which is an image. I've got code working so you can zoom with the mouse wheel. When the zooming stops, I reload the image, in a larger size. I add the new image to the group ( the old image is still part of the group ) and then I do this:
img.remove();
img.destroy();
imgNew.moveToTop();
imgNew.offsetX = offset.x;
imgNew.offsetY = offset.y;
At the end of this code, my old image disappears and the new one is not visible. It has a position that is sane, and it is the child of my group. It has exactly the size I expect it to have ( it's absolute position is 0,0 and it's size is bigger than my canvas ). I've turned off clipping, so if it was visible anywhere, I'd see it. I've changed the position in the debugger, and called draw() on the canvas, the layer and the group. I have dragging code and I've dragged the drag control ( which is still there ) every where I can. I've also changed my code to just add the new image to the top level layer instead of the lower down group.
I should mention in case it's relevant, the image is coming from a WebAPI RESTful service, and the size is passed in, so the image URLs are different for the two images.
I simply cannot find my image !!! What should I do next ?
This:
KineticJS - How to Change Image src on Button Click
answered my question. Short version: there's a setImage method so you can load a new image, call setImage() and it gets replaced.

Three.js custom geometry raycaster catches wrong object

I need to use my own gemetry since the default cube does not look like it should in wireframe mode (now it is made of triangles instead of squares).
So I made my own geometry and it looks ok, but the raycaster does not work as good with my own objects as it does with the built-in cubes.
var cube = new THREE.Line( getCube( 5,5, 5), new THREE.LineDashedMaterial( { color: 0x000000,dashSize: 1, gapSize: 0.1, linewidth: 2 } ),THREE.LinePieces );
where getCube() returns
var geometry = new THREE.Geometry()
See example:
http://jsfiddle.net/QHjSM/12/
6 colour filled box on the top are the defalt THREE.CubeGeometry boxes, and selecting them with raycaster works perfect, 6 wireframe are my custom geometry.
Issues:
If you try to click outside the box, but pretty close to it it will catch the box, and if you click inside the box (in the middle of it) it will not catch it neither.
But the most annoying thing is that if you click inside one box, but close to another one sometimes it catches not the wrong one.
I'm not sure can it be done better, tried all the geometry.compute... methods, but still no effect.
Good day, your custom cubes are not in fact cubes. They are just a stack of lines with no cooresponding faces. Your selection is not returning as expected due to the fact that your "cubes" indeed have gapping holes right threw them. What you can do is in your getCube function after you've built the vertices you can then build all your faces in a similar way.
Have a look at this example: Issue with custom geometry and face normal
Generally you'll need to carefully pattern out every 3 set of vertices so that when you build the faces there in a clock-wise direction so that the normals will be computerd correctly. Here's a basic example of adding a face.
geometry.faces.push(new THREE.Face3(1,2,3));
BUT! Note that this will result in the same aforementioned diagonal lines through your wireframe. So, for your use case why not simply use both the basic cube mesh with picking and remove the wireframe then overlay the line drawn boxes as your custom wireframe. Best of both worlds.
FYI, you probably already know but Face4 is gone, so you'll need to use Face3 and some sort of custom wireframe to do this anyway.
Edit:
I did a little test to your fiddle, noticed something strange. Using the CanvasRender, even with the wireframe off the default cube you still see the diagonal lines! I try WebGLRenderer and it's fine. I'll have to look into that one further.
CanvasRenderer
http://jsfiddle.net/QHjSM/13/
WebGLRenderer
http://jsfiddle.net/QHjSM/14/
Me again, hmm it appears those ghosted face lines are visible in all the CanvasRenderer examples that use a MeshBasicMaterial on the Three.js site. The only thing I was able to do was simply reduce the opacity of the cube mesh material to 0.1 to lessen the effect. I suppose the only other method is to switch to the WebGLRenderer but I look forward to being wrong on this :) Here's the last test
http://jsfiddle.net/QHjSM/16/

What is the most efficient way to reset the size of a shape after scaling in PaperJS

I am attempting to create a very simple beacon-like animation in Paper JS. The idea is that a circle starts off very small and totally opaque and then gets larger and more transparent until it disappears and the animation restarts.
I'm using scaling to make the image larger but resetting it to it's original size is becoming problematic and at the moment I have resorted to cloning a second circle to reset it rather than just working with a single shape, there has to be a simpler way of doing this.
I've create a jsFiddle to demonstrate my rough code so far, any help would be appreciated.
http://jsfiddle.net/colethecoder/Y3S9n/1
Paperjs does not store the original Path, nor does it remember any operations that have been applied to reach the current state, so it can be difficult to reset to a previous state. The easiest approach is to use the this.scale that your current code is calculating and when you want to reset do this.circle.scale(1/this.scale); Here is a jsfiddle that way.
FYI, here is the code path for scaling:
Item.scale()
Item.transform()
Item.apply()
Path._apply()
Segment._transformCoordinates()
So the end result is that _transformCoordinates() is called on each of the four segments in the circle, and it simply moves the point coordinates...nothing is remembered to "undo" the scaling later.
Alternatively to remembering the scale yourself, you can use the Path.fitBounds() function to shrink the circles to an arbitrary size...for instance you could save the bounding rectangle right after creating the Circle, and then fitBounds back to that size.
Set item.applyMatrix = false if you don't want to persist transformations alongside item.
For example, the following code linearly (i.e. "additively") animates item.scaling:
var item = new Path.Rectangle({
point: [75, 75],
size: [5, 5],
strokeColor: 'black',
applyMatrix: false
});
function onFrame(event) {
item.scaling += 0.1;
}
The way i approached this issue was attaching a new object called originalBounds to the paper.js shapes immediately after their instantiation. If i needed to play with its size, coming back its original one became fairly trivial.

Categories