I'm currently centering objects/models (mesh) in my scene by calling mesh.geometry.center()
This helps me place the object in the center based on its bounding box.
This works perfectly for static objects that don't ever change size (for example lets say I want to render a cardboard box and I'll never change its proportions).
However, I also have some complex 3D models (for example - a bowling ball, a couple of jagged rocks and the Eiffel Tower).
At the moment, each of these models will be placed centrally based on its bounding box. This means that the jaggedy points of the rocks, the curved base of the bowling ball, or the first section of the base of the Eiffel Tower will jut through / clip through the base of the cardboard box (or, conversely, if not scaled appropriately, will just float in mid-air)
What I need is a way find the center of each mesh on only the X and Y axis to allow me to place these models flat on an XY plane without having to manually adjust the Z value. Is this possible?
A general way to do this for objects or trees of objects...
Here I get the bounds of the object.. then scale it so it ranges to 1 on the largest axis... and centers it on x,z axis, and seated on the y.
var cent = new THREE.Vector3();
var size = new THREE.Vector3();
var bbox = new THREE.Box3().setFromObject(yourObject);
bbox.getCenter(cent);
bbox.getSize(size);
//Rescale the object to normalized space
var maxAxis = Math.max(size.x, size.y, size.z);
yourObject.scale.multiplyScalar(1.0 / maxAxis);
//Now get the updated/scaled bounding box again..
bbox.setFromObject(yourObject);
bbox.getCenter(cent);
bbox.getSize(size);
yourObject.position.x = -cent.x;
yourObject.position.y = 0;
yourObject.position.z = -cent.z;
Related
I have a 500 pixel by 500 pixel image that I am using to pull data from a 250,000 index array where each index represents 1 pixel.
The user is able to draw a rectangle at any orientation, and I am capturing the coordinates for each corner.
I am trying to capture each pixel within the rectangle to reference the data array and extract the related data.
I looked at Bresenham algorithm in Javascript and while I can get all the points between each of the coordinates using this solution, I am unable to loop through these points as the paths do not always contain the same number of pixels.
An example of the values I'm looking for using the following coordinates would be:
corner1 = [100,100]
corner2 = [100,105]
corner3 = [105,105]
corner4 = [105,100]
And the result (sort order is not important):
pixelsInRectangle = [
[100,100],[100,101],[100,102],[100,103],[100,104],[100,105],
[101,100],[101,101],[101,102],[101,103],[101,104],[101,105],
[102,100],[102,101],[102,102],[102,103],[102,104],[102,105],
[103,100],[103,101],[103,102],[103,103],[103,104],[103,105],
[104,100],[104,101],[104,102],[104,103],[104,104],[104,105],
[105,100],[105,101],[105,102],[105,103],[105,104],[105,105]
]
One set of coordinates I'm trying to solve for are:
corner1 = [183,194]
corner2 = [190,189]
corner3 = [186,184]
corner4 = [179,190]
Any recommendations would be greatly appreciated!
If rectangle is not axis aligned:
Sort vertices by Y-coordinate.
Get the lowest one. From two next Y-coordinates choose left and right ones.
Start simple line rasterization scan along left edge and along right edge simultaneously: for current integer Y value calculate corresponding rounded X-coordinate for left edge, for right edge, and output all horizonatal line between (xleft, y)-(xright,y)
For edge between vertices (x0,y0)-(x1,y1) formula is
x = x0 + (x1-x0)*(y-y0)/(y1-y0)
(example for triangle exploiting the same technique)
When some vertex is reached, change equation of corresponding edge, continue.
Using this way, you fill triangle, parallelogramm, another triangle (or just two triangles if two vertices share the same Y)
(You can use Bresenham or DDA, or another line rasterization algorithm if necessary)
I have a set of 3D shapes (pyramid, cube, octahedron, prism etc.) and I need to build described sphere around each of them. It is easy to do so using geometry.boundingSphere as it has radius of the described sphere. But if I scale an object the bounding sphere is not being updated. Is it possible to update bounding sphere relatively to the scale?
Using Three.js 0.129.
const { position } = entity.object3D;
const mesh = entity.getObject3D('mesh') as THREE.Mesh;
mesh.geometry.computeBoundingSphere();
const { radius } = mesh.geometry.boundingSphere;
createSphere(radius, position);
The geometry.boundingSphere property represents the geometry. You could technically have two meshes with different scales share the same geometry, so you would want to maintain the geometry's original bounding sphere, and then compute a new one for each mesh, individually.
One problem with scaling the bounding sphere is that you can scale your mesh in x, y, and z separately, and even invert vertex position values given negative scaling values. unequal scale values would lead to it being less of a sphere, and more of a spheroid, which would not help you in math.
What you can do is recompute a bounding sphere for your mesh, given its updated world transformation matrix. I suggest using the world matrix because other ancestors of your mesh could also influence scale in unpredictable ways.
// Given:
// (THREE.Mesh) yourMesh
// Copy the geometry
let geoClone = yourMesh.geometry.clone() // really bad for memory, but it's simple/easy
// Apply the world transformation to the copy (updates vertex positions)
geoClone.applyMatrix4( yourMesh.matrixWorld )
// Convert the vertices into Vector3s (also bad for memeory)
let vertices = []
let pos = geoClone.attributes.position.array
for( let i = 0, l = pos.length; i < l; i += 3 ){
vertices.push( new THREE.Vector3( pos[i], pos[i+1], pos[i+2] ) )
}
// Create and set your mesh's bounding sphere
yourMesh.userData.boundingSphereWorld = new THREE.Sphere()
yourMesh.userData.boundingSphereWorld.setFromPoints( vertices )
This will create a world-aligned bounding sphere for your mesh. If you want one based on local transformations, you can follow the same idea using the local yourMesh.matrix matrix instead. Just know that your sphere's center will then be based on your mesh's local transformation/rotation, not just its scale.
I'm making an animation editor entirely with HTML and Javascript. For the Canvas manipulation operations I'm using CreateJS.
At this point, I want to render a small UI inside the canvas, that shows off what item is selected.
The problem starts when I rotate the Image, so far I know that I can get the Boundaries of a Bitmap after its transformation, but this operation gives me the data that I'm not Looking for.
The Code below sets the coordinates for the UI drawn in the canvas:
update : function(){
//Big rectangle
this.ui[0].x = this.object.x;
this.ui[0].y = this.object.y;
this.ui[0].rotation = this.object.rotation;
this.ui[0].scaleX = this.object.scaleX;
this.ui[0].scaleY = this.object.scaleY;
//North West rectangle coordinates
this.ui[1].x = this.object.getTransformedBounds().x;
this.ui[1].y = this.object.getTransformedBounds().y;
//North East rectangle coordinates
this.ui[2].x = this.object.getTransformedBounds().x + this.object.getTransformedBounds().width;
this.ui[2].y = this.object.getTransformedBounds().y;
//South West rectangle coordinates
this.ui[3].x = this.object.getTransformedBounds().x;
this.ui[3].y = this.object.getTransformedBounds().y + this.object.getTransformedBounds().height;
//South East rectangle coordinates
this.ui[4].x = this.object.getTransformedBounds().x + this.object.getTransformedBounds().width;
this.ui[4].y = this.object.getTransformedBounds().y + this.object.getTransformedBounds().height;
}
The method getTransformedBounds() returns the whole rectangular area that the image occupies after it's transformation. Is there a way to get the Actual rectangular area that the object occupies in the canvas so I can achieve something like this:
http://postimg.org/image/5wr32wt7j/
and not this:
http://postimg.org/image/dqroob10f/
I'm kinda new with createJS so please bear with me.
You can use getBounds() instead of getTransformedBounds(). It returns the untransformed local bounds. Then just draw a rect in a Shape using those bounds, and transform the Shape to match the transformation of the "object".
Alternately, put both the "ui" and the "object" in a Container together, and apply the transformations to the Container instead of to the "object".
Is there a way to create a matrix from a rotation quaternion and a translation vector without converting both to matrices first?
What I'm doing right now (using my own little math library) is:
var rotation = new quat(...);
var translation = new vec3(...);
var rotationMatrix = new mat4(rotation);
var translationMatrix = new mat4(translation);
var matrix = mat4.product(translationMatrix, rotationMatrix);
Instead, I'd like to do the following:
var rotation = new quat(...);
var translation = new vec3(...);
var matrix = new mat4(rotation, translation);
It seems inefficient and wasteful to allocate two temporary matrices, especially in Javascript, where they have to be allocated on the heap.
Thank you!
The top left 3×3 submatrix is the rotation, the top right 3×1 vector is the translation, the bottom row is (0,0,0,1). (This is assuming that you're multiplying matrix times column vector, not row vector times matrix. Otherwise the situation would be transposed.) So yes, it should be easy to adapt the constructor which creates the matrix from a rotation to also cater for the case where there is an extra translation vector. Or you might create the matrix from the rotation and then change some of its entries to incorporate the translation.
Note that this assumes your notation to mean “rotate then translate”. If it's the other way round, then you'd have to apply the rotation to the translation vector before including that into the matrix.
I would like draw 3D points represented in image to 3D rectangle. Any idea how could I represent these in x,y and z axis
Here projection type is orthographic.
Thanks
Okay. Let's look at a simple example of what you are trying to accomplish it, and why this is such a complicated problem.
First, lets look a some projection functions. You need a way to mathematically describe how to transform a 3D (or higher dimensional) point into a 2D space (your monitor), or a projection.
The simpiest to understand is a very simple dimetric projection. Something like:
x' = x + z/2;
y' = y + z/4;
What does this mean? Well, x' is you x coordinate 2D projection: for every unit you move backwards in space, the projection will move that point half that many units to the right. And y' represents that same projection for your y coordinate: for every unit you move backwards in space, the projection will move that point a quarter unit up.
So a point at [0,0,0] will get projected to a 2d point of [0,0]. A point at [0,0,4] will get projected to a 2d point of [2,1].
Implemented in JavaScript, it would look something like this:
// Dimetric projection functions
var dimetricTx = function(x,y,z) { return x + z/2; };
var dimetricTy = function(x,y,z) { return y + z/4; };
Once you have these projection functions -- or ways to translate from 3D space into 2D space -- you can use them to start draw your image. A simple example of that using js canvas. First, some context stuff:
var c = document.getElementById("cnvs");
var ctx = c.getContext("2d");
Now, lets make a little helper to draw a 3D point:
var drawPoint = (function(ctx,tx,ty, size) {
return function(p) {
size = size || 3;
// Draw "point"
ctx.save();
ctx.fillStyle="#f00";
ctx.translate(tx.apply(undefined, p), ty.apply(undefined,p));
ctx.beginPath();
ctx.arc(0,0,size,0,Math.PI*2);
ctx.fill();
ctx.restore();
};
})(ctx,dimetricTx,dimetricTy);
This is pretty simple function, we are injecting the canvas context as ctx, as well as our tx and ty functions, which in this case our the dimetric functions we saw earlier.
And now a polygon drawer:
var drawPoly = (function(ctx,tx,ty) {
return function() {
var args = Array.prototype.slice.call(arguments, 0);
// Begin the path
ctx.beginPath();
// Move to the first point
var p = args.pop();
if(p) {
ctx.moveTo(tx.apply(undefined, p), ty.apply(undefined, p));
}
// Draw to the next point
while((p = args.pop()) !== undefined) {
ctx.lineTo(tx.apply(undefined, p), ty.apply(undefined, p));
}
ctx.closePath();
ctx.stroke();
};
})(ctx, dimetricTx, dimetricTy);
With those two functions, you could effectively draw the kind of graph you are looking for. For example:
// The array of points
var points = [
// [x,y,z]
[20,30,40],
[100,70,110],
[30,30,75]
];
(function(width, height, depth, points) {
var c = document.getElementById("cnvs");
var ctx = c.getContext("2d");
// Set some context
ctx.save();
ctx.scale(1,-1);
ctx.translate(0,-c.height);
ctx.save();
// Move our graph
ctx.translate(100,20);
// Draw the "container"
ctx.strokeStyle="#999";
drawPoly([0,0,depth],[0,height,depth],[width,height,depth],[width,0,depth]);
drawPoly([0,0,0],[0,0,depth],[0,height,depth],[0,height,0]);
drawPoly([width,0,0],[width,0,depth],[width,height,depth],[width,height,0]);
drawPoly([0,0,0],[0,height,0],[width,height,0],[width,0,0]);
ctx.stroke();
// Draw the points
for(var i=0;i<points.length;i++) {
drawPoint(points[i]);
}
})(150,100,150,points);
However, you should now be able to start to see some of the complexity of your actual question emerge. Namely, you asked about rotation, in this example we are using an extremely simple projection (our dimetric projection) which doesn't take much other than an oversimplified relationship between depth and its influences on x,y position. As the projections become more complex, you need to know more about your relationship/orientation in 3D space in order to create a reasonable 2D projection.
A working example of the above code can be found here. The example also includes isometric projection functions that can be swapped out for the dimetric ones to see how that changes the way the graph looks. It also does some different visualization stuff that I didn't include here, like drawing "shadows" to help "visualize" the actual orientation -- the limitations of 3D to 2D projections.
It's complicated, and even a superficial discussion is kind of beyond the scope of this stackoverflow. I recommend you read more into the mathematics behind 3D, there are plenty of resources, both online and in print form. Once you have a more solid understanding of the basics of how the math works then return here if you have a specific implementation question about it.
What you want to do is impossible to do using the method you've stated - this is because a box - when rotated in 3 dimensions won't look anything like that diagram of yours. It will also vary based on the type of projection you need. You can, however get started using three.js which is a 3D drawing library for Javascript.
Hope this helps.
How to Draw 3D Rectangle?
posted in: Parallelogram | updated on: 14 Sep, 2012
To sketch 3 - Dimensional Rectangle means we are dealing with the figures which are different from 2 – D figures, which would need 3 axes to represent them. So, how to draw 3D rectangle?
To start with, first make two lines, one vertical and another horizontal in the middle of the paper such that they represent a “t” letter of English. This is what we need to draw for temporary use and will be removed later after the construction of the 3 – D rectangle is complete. Next we draw a Square whose measure of each side is 1 inch. Square must be perfect in Geometry so that 90 degree angles that are formed at respective corners are exact in measure. Now starting from upper right corner of the square we draw a line segment that will be stretched to a measure of 2 inches in the direction at an angle of 45 degrees. Similarly, we repeat the procedure by drawing another Line Segment from the upper left corner of the square and stretching it to 2 inches length in the direction at an angle of 45 degrees. These 2 line segments are considered to be the diagonals with respect to the horizontal line that we drew temporarily in starting. Also these lines will be parallel to each other. Next we draw a line that joins the end Point of these two diagonals.
Next starting from the very right of the 2 inch diagonal end point, draw a line of measure 1 inch that is supposed to be perpendicular to the temporary horizontal line. Next we need to join the lower left corner of the square with end point of the last 1’’ line we drew in 4th step and finally we get our 3 - D rectangular. Now we can erase our initial “t”. This 3- D rectangle resembles a Cuboid.