How to scale a mesh without changing the position? - javascript

I have in this scene 27 meshes, each of which has an associated number. The one with the highest number will have the scale 1. The rest will have a value less than 1 successively.
Next I want it to climb each of the loops accordingly. My problem occurs when the position of each mesh is changed.
Indeed it is scaled to the size that is due, but it changes position. I'm struggling as several screens are stacking.
I just need you to climb and stay in the same position as in this example:
US states are scaled, but still keeping their position. I think that they scale to the center of the figure.
I created the meshes (each called "municipios")
for(var s=0; s< features.features[x].geometry.coordinates[0].length; s=s+1){
geometria[x].vertices.push(new THREE.Vector3((((features.features[x].geometry.coordinates[0][s][0])+75.5)*10),(((features.features[x].geometry.coordinates[0][s][1])-5.5)*10),0));
}
forma_figura[x]=new THREE.Shape(geometria[x].vertices);
extrude_geometria[x]=new THREE.ExtrudeGeometry(forma_figura[x],datos_extrusion);
municipios[x] = new THREE.Mesh( extrude_geometria[x], materialExtrude[x] );
scene.add(municipios[x]);
// so I change the scale:
//formula is the value of scale. The biggest number has escale 1.
new TWEEN.Tween(municipios[x].scale).to({ x: formula, y: formula }, 1000).start();
//this ultimate line is the same: municipios[x].scale.set(formula,formula,formula);

Because the mesh position is not at its center, or whatever reference you want it to be : if you create a geometry with average vertices x component over 100, its visible position will be its real position plus (100,0,0). If you did not specify a position for the mesh ((0,0,0) by default), it will look being at (100,0,0) precisely. Scaling it by .5 for instance will result in the average position being at (100,0,0)*.5=(50,0,0), making the mesh apparently change its position.
What needs to be done is :
to substract the coordinates of the center from all the vertices. Vertices are inside the geometry, so once it is done, geometry.verticesNeedUpdate = true needs to be set.
then to add the coordinates of the center to the mesh, to compensate.
So the resulting mesh will be positionned at its center without having moved.
There are three different possibilities to define the center :
Three.js can center your mesh automatically based on the center of the bounding box with geometry.center() and THREE.GeometryUtils.center(geometry).
You can compute the centroid by looping through the vertices a first time to get their average coordinates.
You may neither want the center of the bouding box, nor the centroid, but a custom center. For example if you are scaling 'people' meshes and want their feet touch the ground at any scale : on the horizontal plane the center you want can be one of the two first, but its vertical coordinate must be the lowest vertical coordinate found (the very bottom of the feet).
Of course if your meshes are imported from a 3D editor software you can also do that inside it.

Related

Rotating around dodecahedron

I am trying to make a Three.js scene where I've got a dodecahedron. I want the camera to be zoomed in on one side of the dodecahedron and when a button is pressed I want it to zoom out, rotate until it is standing across another side and then zoom in again.
To make this clear:
If the camera would be fully zoomed in on side 1 and I pressed "5", I would want the camera to zoom out - showing the dodecahedron - then rotate towards 5 (or let the dodecahedron rotate side 5 facing the camera?) and zoom in again. It's important that the camera is always set parallel with the base of the pentagon it's facing, not the top or any other rotation.
I thought it would be smart to start off with just a cube, to not start too complicated. I added some tweens (when pressing G) to illustrate some basic movement, but that doesn't look too good anymore in the fiddle. jsfiddle
Because I feel like I should have a function that does all this movement and calculating for me I first tried to write down each position and rotation each side-view had from the cube so I might detect a pattern. I can see some pattern in the values I wrote down for the cube, but I do not know how to convert this into a working function, let alone for a dodecahedron. My noted values are
side1 (0, 0, 600) (0, 0, 0)
side2 (600, 0, 0) (0, pi/2, 0)
side3 (0, 0, -600) (0, pi, 0);
side4 (-600, 0, 0) (0, -pi/2, 0);
side5 (0, 600, 0) (-pi/2, 0, 0);
side6 (0, -600, 0) (pi/2, 0, 0);
I can see some sort of recurrence happening and some relationships, but I wouldn't see how to link them in a function. I think that would be a first step in getting to a function doing the same but for a more complex shape. Could anyone guide me into some direction I should be looking right now? Because I could of course work with a lot of if clauses, but that's not the correct way to go I feel.
To solve the problem, the first we would do is getting the center coordinate of each side of the dodecahedron.
as you know in three.js, a mesh consists of triangles, every triangle has three points, all the faces and vertices can be found in mesh.geometry.faces and mesh.geometry.vertices. in dodecahedron, each side has three faces and five vertices, and I use each face normal to divide them into 12 groups which have same normal and in the same plane. Then, we got 5 points of each side, calculate the average coordinate to get the center coordinate.
After getting coordinates we need to rotate, one way is rotating the dodecahedron and keep the camera, another way is keeping the dodecahedron and translate camera, in this case, I select the second one.
Now camera face to centerA, the green circle is the track of camera, because we need to keep the distance from camera to the dodecahedron center.
To get the target position, we just scale the centerB vector, cause the coordinate of the centerB is object system coordinate, we need to apply the matrix to change the coordinate to world system coordinate.
Then, we translate the camera in an animation, the camera needs to take an arc.
I use the parametric equation of a circle in 3D space to do that, about the equation you can see Parametric Equation of a Circle in 3D Space. With this formula, I got the parameter θ1 on camera position and θ2 on target position. I update the camera position with θ1 in every animation frame loop.
I add some comments on jsfiddle.(Still has some bugs, need to update.)
Here is another solution by keeping the camera and rotate the object.

Zooming 2d game camera makes it move from the origin (Javascript)

These two snippets are the culprits:
function tr(){
ctx.translate(0-cameraX,0-cameraY);
ctx.scale(zoom,zoom);
}
function uiPosToWorldPos(pos){
return [(pos[0] + cameraX) / zoom,(pos[1] + cameraY) / zoom];
}
What I am doing is moving my world opposite of my camera to create a scrolling/parallax world (fairly standard.) This is all good and well until I add zooming of the camera. I am having trouble finding a way to factor in the zoom to the above functions without this one problem: The farther my camera is from (0,0) and the lower zoom (zooming out) the farther my camera tends to move away from the origin.
I want to be able to zoom in and out cleanly wherever I am so that the same point in the world will remain center camera regardless of zoom. The 2nd function is necessary to determine where my mouse is on the world and also so I can set my bounds and only draw the items that are on my screen.
You calculate your scale coefficient and then multiples it with your object position.

Rotate a Two.js object in its position

I have a large circle with smaller ones inside made using two.js.
My problem is that these two do not rotate in their own place but in the top left axis.
I want the group of circles (circlesGroup) rotate only inside the large one in a static position. The circlesGroup and the large circle are grouped together as rotatoGroup.
two.bind('update', function(frameCount, timeDelta) {
circlesGroup.rotation = frameCount / 120;
});
two.bind('update', function(frameCount, timeDelta) {
rotatoGroup.rotation = frameCount / 60;
});
The whole code is in CodePen.
All visible shapes when invoked with two.make... ( circles, rectangles, polygons, and lines ) are oriented in the center like this Adobe Illustrator example:
When this shape's translation, rotation, or scale change those changes will be reflected as transformations about the center of the shape.
Two.Groups however do not behave this way. Think of them as display-less rectangles. They're origin, i.e group.translation vector, always begins at (0, 0). In your case you can deal with this by normalizing the translation your defining on all your circles.
Example 1: Predefined in normalized space
In this codepen example we're defining the position of all the circles around -100, 100, effectively half the radius in both positive-and-negative x-and-y directions. Once we've defined the circles within these constraints we can move the whole group with group.translation.set to place it in the center of the screen. Now when the circles rotate they are perceived as rotating around themselves.
Example 2: Normalizing after the fact
In this codepen example we're working with what we already have. A Two.Group that contains all of our shapes ( the bigger circle as well as the array of the smaller circles ). By using the method group.center(); ( line 31 ) we can normalize the children of the group to be around (0, 0). We can then change the translation of the group in order to be in the desired position.
N.B: This example is a bit complicated because it invokes underscore's defer method which forces the centering of the group after all the changes have been registered. I'm in the process of fixing this.

Object controll with mouse position relative to circle

Need some inspiration. I've got a picture (blue) and want it to move proportional to the mouse position inside an invisible area (orange). So, if the mouse moves in top-left direction, the image should follow the movement.
I don't want to simply copy the mouse position, rather create an Joystick like behaviour, so if the mouse moves, the image should move stepwise in the desired direction.
But how? I've no idea how to set the right x+y coordinates for the image or how to establish a formula to calculate them.
Incremental (vectored) positions. Consider:
Let's call the dead center of your invisible circle the vector reference point (0,0) or VRP.
You move your mouse away form the VRP. Let's use your image as a reference and say that your mouse is at (-3x -2y) relative to the VRP. You keep it there; It creates a -3 X vector and a -2 Y vector.
For as long as you keep your mouse there, those vectors will be applied to the square's current coordinate at each cycle, like this:
Assume Picture starter position is absolute 100,100.
Cycle 1: [x]:100 -3 = 97;[Y]:100 -2 = 97. New picture position = 97x98y.
Cycle 2: [x]:97 -3 = 94;[Y]:98 -2 = 96. New picture position = 94x96y.
And so forth. If you want to stop the movement, just bring the cursor back to the VRP.
You may sophisticate the mechanism creating acceleration intermediate vectors, or a dead zone around the vector reference point.

Show Extents Algorithm?

OH Great and Knowledgeable Stack Overflow, I humbly request your great minds assistance...
I'm using the three js library, and I need to implement a 'show extents' button. It will move the camera to a position such that all the objects in the world are visible in the camera view (given they are not blocked of course).
I can find the bounding box of all the objects in the world, say they are w0x,w0y,w0z and w1x,w1y,w1z
How can I, given these to bounds, place the camera such that it will have a clear view of the edges of the box?
Obviously there will have to be a 'side' chosen to view from...I've googled for an algorithm to no avail!
Thanks!
So Let's say that you have picked a face. and that you are picking a camera position so that the camera's line-of-sight is parallel to one of the axes.
Let's say that the face has a certain width, "w", and let's say that your camera has a horizontal field-of-view "a". What you want to figure out is what is the distance, "d" from the center of the face that the camera should be to see the whole width.
If you draw it out you will see that you basically have an isosceles triangle whose base is length w and with the angle a at the apex.
Not only that but the angle bisector of the apex angle forms two identical right triangles and it's length (to the base) is the distance we need to figure out.
Trig tells us that the tangent of an angle is the ratio of the oposite and adjacent sides of the triangle. So
tan(a/2) = (w/2) / d
simplifying to:
d = w / 2*tan(a/2)
So if you are placing the camera some axis-aligned distance from one of your bounding box faces then you just need to move d distance along the axis of choice.
Some caveats, make sure you are using radians for the javascript trig function input. Also you may have to compute this again for your face height and camera's vertical field-of-view and pick the farther distance if your face is not square.
If you want to fit the bounding box from an arbitrary angle you can use the same ideas - but first you have to find the (aligned) bounding box of the scene projected onto a plane perpendicular to the camera's line of sight

Categories