Rotate model in Autodesk Forge Viewer - autodesk-forge

Hi I am developing an application using the viewer api. I have a master model. And I load other models on this model. I can move and resize these models that I have uploaded later. I achieved rotation using makeRotationX ,makeRotationY,makeRotationZ functions. But when I rotate the loaded model, it moves it to the starting point. What could be the reason for this? So for example, I add the cube to the left, but it moves to the main 0,0,0 point and does the rotation.
I just change the rotation Y value and this is the result.
Code :
cubeModel.getModelTransform().makeRotationY(inputValue * Math.PI / 180);
viewer.impl.invalidate(true, true, true)

This is because the model's THREE.Matrix4 transform that you retrieve using model.getModelTransform() may already include some transformation (in this particular case, the transformation is offsetting the red cube to the left). And the makeRotationY method doesn't append any transformation, it simply resets the matrix to a new transformation that only rotates around the Y axis.
Instead, what you'll want to do is something like this:
let xform = model.getModelTransform().clone();
// modify the xform instead of resetting it, for example
let rotate = new THREE.Matrix4().makeRotationY(0.1);
let scale = new THREE.Matrix4().makeScale(0.1, 0.5, 0.1);
xform.premultiply(rotate);
xform.multiply(scale);
// since we cloned the matrix earlier (good practice), apply it back to the model
model.setModelTransform(xform);

Related

Converting Nose's 3D Position values to 2D values?

Just wondering if this has been attempted before.
I'm making a game where by 2D objects fall from the top and I use my nose to 'catch' those objects.
Currently I have it set up in such a way that if the X and Y values for the nose and 2D object are the same, it increases the counter.
However I've noticed that the position for 3D and 2D objects both reflect very different values.
I've tried using null objects to contain the 2D canvas, but it didn't work either.
Messing around with tolerance values didn't achieve the desired effect.
Equals Patch
First number is taken from the null object, second number is taken from the nose's position.
From nullobject: -0.09079
From nose: 0.00108
Is this something to do with limitations or am I doing something wrongly here? Thanks for taking your time to read this :(
Here is a project that translates 3D nose position to 2D screen space. I made a video on how to do it: video and here is a link to free download.
It requires a few lines of script and the Scene Module to project the 3D position to 2D screen space.
const Scene = require('Scene');
const Patches = require('Patches');
Promise.all([
// The 3D Object or 3D Point we want to track
Scene.root.findFirst('Nose3D'),
]).then(function (results) {
// Define variable names for items we found
const nose3D = results[0];
// This transforms the world coordinate of the 3D Object to a screen coordinate.
var nose2D = Scene.projectToScreen(nose3D.worldTransform.position)
// Get the Nose3D Position, then set the projectToScreen point Nose2D
Patches.outputs.getPoint("Nose3D").then(pointSignal => {
Patches.inputs.setPoint2D('Nose2D', nose2D);
});
});

LeafletJS: How to flip tiles vertically on-the-fly?

Background:
I've produced a 1-terapixel rendering of the Mandelbrot Set and am using LeafletJS to zoom and pan around in it interactively. It works great. But since the Mandelbrot Set is symmetric along the real axis, I'm currently using twice as many tile images as necessary.
Question: How can I hook into LeafletJS's display-time code (using some callback?) so that whenever a tile is loaded via HTTP, it either passes through unchanged or is flipped vertically? This would allow me to reduce the data by many tens of gigabytes on higher zoom levels.
Example: Here are four tiles from zoom level 1 (shown here separated by one pixel). I'd like to throw away the bottom two tile images and load them instead as vertically-flipped versions of the top two tiles. Can this be done on-the-fly with LeafletJS?
More concretely: If I know zoom level z and tile coordinates x,y, I'd like to flip the tile vertically at load-time whenever y is less than 2^(z–1). For instance, at zoom level z=10, I'd like to flip the tiles vertically for all y < 512.
I imagine the answer is going to involve something like setting the transform, -moz-transform, -o-transform, and -webkit-transform properties of the <img> tag to scaleY(-1) and maybe filter and -ms-filter to FlipV, but I don't know where/how to define these in a LeafletJS context.
You would just need to modify the y number of bottom tiles in L.TileLayer._loadTile method, before it gets applied on the image URL.
As for flipping the image itself, unfortunately we cannot use classes because a transform property is already applied by Leaflet directly on the tiles (images), so it overrides any transform in class. Then we have to append any transform, -moz-transform etc. on the tile.style.
L.HalfTileLayer = L.TileLayer.extend({
_loadTile: function (tile, tilePoint) {
tile._layer = this;
tile.onload = this._tileOnLoad;
tile.onerror = this._tileOnError;
this._adjustTilePoint(tilePoint);
//////////////////
var limit = Math.pow(2, tilePoint.z - 1),
y = tilePoint.y;
if (y >= limit) { // modify for bottom tiles, i.e. higher y
tilePoint.y = 2 * limit - y - 1; // y starts at 0
tile.style.transform += " scaleY(-1)"; // append
// apply more transforms for cross-browser
}
/////////////////
tile.src = this.getTileUrl(tilePoint);
this.fire('tileloadstart', {
tile: tile,
url: tile.src
});
}
});
(new L.HalfTileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png')).addTo(map);
Demo: http://jsfiddle.net/ve2huzxw/73/
Note that in the default configuration, y = 0 is the top, y = 2^z - 1 is the bottom.

Java get point location from angle change

This may be an issue that I simply do no know the proper terminology to research the answer to this, I am pretty sure the solution is a function of trig.
I have a method which accepts an X/Y position coordinate and an angle in degrees. It should return an updated X/Y based on the rotation angle provided.
For example, A point is usually located at x=0,y=2 (top middle). Now I need to rotate it to it's side by 90 degrees. In my mind I know it's location is now x=2,y=0 (middle right) but I do not know the equation to produce this.
I think I need to first determine the quadrant of the starting point, and then perform the proper trig function from there. This is for a game I am developing using libgdx which is where the Vector2 object comes from.
I have come this far:
public Vector2 getPointsRotated(Vector2 startPoint, float angle){
Vector2 newPoint = new Vector2(0,0);
// determine the starting quadrant
int quad=0;
if((startPoint.x>=0)&&(startPoint.y>=0)){quad=0;}
if((startPoint.x<0)&&(startPoint.y>=0)){quad=1;}
if((startPoint.x<0)&&(startPoint.y<0)){quad=2;}
if((startPoint.x>=0)&&(startPoint.y<0)){quad=3;}
if(quad==0){
// doesn't work
newPoint.x = (float) ((newPoint.x)* (Math.sin(angle)));
newPoint.y = (float) ((newPoint.y)* (Math.cos(angle)));
}
// ...
// other quadrants also don't work
// ...
return newPoint;
}
Thanks for any help.
Update:
I have been avoiding and returning to this problem for a few days. Now after finally posting the question here I figure it out within minutes (for ppl using libgdx anyway).
Libgdx provides a rotate function for Vector2s
so something like:
Vector2 position = new Vector2(0,2);
position.rotate(angle);
works perfectly.
I find rotation matrices are very helpful for this sort of problem.
https://gamedev.stackexchange.com/questions/54299/tetris-rotations-using-linear-algebra-rotation-matrices

Rotating a Model in Away3D

Here's what i want to do:
I want to load a model (most likely .3ds) into my .swf and be able to rotate it with the mouse.
This works fine at first glance, but there's problem, the rotations 'switch' over. Or to say it differently:
Imagine we have a model in the shape of a pipe.
If we drag the mouse to the right, the model rotates along its X-Axis to the left, mouse to the left, X-Axis rotation to the right, moving the mouse up, Y-Axis rotation downward, mouse down, Y-Axis rotation upward.
Now, lets say we turn the pipe to the right or left, until we face the (former) 'backside' of the pipe, and then we move the mouse down. The model will rotate downward instead of upward.
I hope you understand what i mean with this. I've been looking around for a good while now and never found a satisfying solution. There was talk about quaternions, but i can't grasp them.
Another suggestion i read somewhere is the following:
create a Matrix3D object, apply rotation on it, then multiply it with the desired Matrix3D of my 3d-Model.
I tried to do it, but the result stays the same, the directions of rotation switches depending on what side i'm facing.
private function update(e:Event):void
{
xCalc = (0.3*(stage.mouseX - lastMouseX));
yCalc = (0.3*(stage.mouseY - lastMouseY));
if(move)
{
var objTransform:Matrix3D = new Matrix3D();
objTransform.prependRotation(xCalc, Vector3D.Y_Axis, objC.pivotPoint);
objTransform.prependRotation(yCalc, Vector3D.X_Axis, objC.pivotPoint);
mesh.transform = multiply3DMatrices(mesh.transform, objTransform);
}
lastMouseX = stage.mouseX;
lastMouseY = stage.mouseY;
view.render();
}
multiply3DMatrices simply multiplies two 4x4 Matrices together.
objC is the ObjectContainer3D that holds my model. For some reason i cannot rotate it properly, unless i manipulate the rotationX/Y/Z properties.
mesh is the mesh inside of the Model (which is very simple, a single mesh).
Also, i'm aware that i could try another Framework for this (like papervision) but this project requires me to use Away3D.
Solved it by myself, the problem was that i created a new Matrix3D Object every time. The fixed code looks like this:
private function update(e:Event):void
{
...
if(move)
{
var objTransform:Matrix3D = mesh.transform;
objTransform.appendRotation(xCalc, Vector3D.Y_Axis, objC.pivotPoint);
objTransform.appendRotation(yCalc, Vector3D.X_Axis, objC.pivotPoint);
mesh.transform = objTransform;
}
...
}
And yes, the user bwroga was actually right, i should've used appendRotation instead of prependRotation, as well.

AS3 - geometry - perspective projection of a point on a 2D plane

I'm currently struggling on a problem that seems far beyond my maths capacities (been a long time since I've made some proper maths...) and I would appreciate some help on that.
Here's my setting :
I got some simple shapes (rectangles), and I "project" their bottom points on a line, coming from an Origin point.
Up to this point everything is fine.
But now I'd like to draw the original shape distorted as if it was projected with some perspective on a plane.
Please consider that I have nothing related to any rotation, isometric or any 3D or fake 2D perspective in my code, I'm only trying to draw some shapes using the graphics library to only have a feeling of something real.
Here's a quick drawing of what I'm trying to do :
What I know :
Origin point coordinates
the rect position & sizes
the red line position
the A & B points coordinates
What I want to determine is the coordinates of the C & D points, thing that could be easy if I wasn't struggling to find the "Origin bis" coordinates.
What I'm trying to do is to fake the projection of my rectangle on something that can be considered as a "floor" (related to the plane where my original rectangle is that can be seen as a wall).
Maybe I'm over-complicating the problem or maybe I fail to see any other easier way to do it, but I'm really not good anymore in any geometry or maths thing... :-(
Thanks a lot for your answers !
hmm i don't know if I undestood it correctly but I think you have too few input parameters:
you said the following information is given:
Origin point coordinates
the rect position & sizes
the red line position
the A & B points coordinates
I don't think it is possible to get your projected rectangle with this information alone.
Additionally, I think your green lines and the 'origin Bis' aren't helpful as well.
Perhaps, try this:
Supose, a blue line going through the points C & D is given as well.
Then you could find your projected rectangle by projecting the top of the rectangle onto that blue line.
So in summary:
You define an origin + two parallel lines, a red and a blue one.
Then you can project the top of the rect onto the blue line and the bottom of the rect onto the red line, yielding the points A,B,C,D
I hope this helps.
If I'm right, this code will show what you wanted to see.
First of all, I've ignored your initial setup of objects and information, and focused on the example situation itself; fake-projecting shadow for a "monolith" (any object is possible with the example below, even textured)
My reason was that it's really quite easy with the Matrix class of ActionScript, a handy tool worth learning.
Solution:
You can use the built-in Matrix class to do skew transform on DisplayObjects.
Try this example:
(The "useful" part lies in the _EF EnterFrame handler ;) )
import flash.display.MovieClip;
import flash.geom.Matrix;
import flash.events.Event;
import flash.display.BitmapData;
const PIP180:Number = Math.PI / 180;
const MAX_SHADOW_HEIGHT_MULTIPLIER:Number = 0.25; // you can also calculate this from an angle, like ... = Math.sin(angle * PIP180);
const ANIM_DEG_PER_FRAME:Number = 1.0 * PIP180; // the shadow creeps at a +1 degree per frame rate
var tx:BitmapData = new MonolithTexture(); // define this BitmapData in the library
var skew:Number = -10 * PIP180; // initial
var mono:MovieClip = new MovieClip();
mono.graphics.beginBitmapFill(tx);
// drawn that way the registration point is 0,0, so it's standing on the ground
mono.graphics.drawRect(0, -tx.height, tx.width, tx.height);
mono.graphics.endFill();
// align monolith to the "ground"
mono.x = stage.stageWidth / 2;
mono.y = stage.stageHeight - 100;
// make it be 100x300 pixel
mono.width = 100;
mono.height = 300;
var shad:MovieClip = new MovieClip();
// colored:
shad.graphics.beginFill(0x000000);
// or textured:
//shad.graphics.beginBitmapFill(tx);
shad.graphics.drawRect(0, -tx.height, tx.width, tx.height);
shad.graphics.endFill();
addChild(shad); // shadow first
addChild(mono); // then the caster object
addEventListener(Event.ENTER_FRAME, _EF);
function _EF(e:Event):void {
// animate skew on the positive half circle
skew = (skew + ANIM_DEG_PER_FRAME) % Math.PI;
// Matrix takes 6 parameters: a, b, c, d, x, y
// for this shadow trick, use them as follows:
// a = width scaling (as mono and shad are drawn in the same way, copy mono.scaleX for a perfect fit
// b = 0, because we don't want to project the vertical axis of transformation to the horizontal
// c = horizontal skew
// d = height scaling * skew * making it a bit flat using the constant
// x = mono.x, ...
// y = mono.y since originally mono and shad look alike, only the Matrix makes shad render differently
var mtx:Matrix = new Matrix(mono.scaleX, 0, Math.cos(skew), mono.scaleY * Math.sin(skew) * MAX_SHADOW_HEIGHT_MULTIPLIER, mono.x, mono.y);
shad.transform.matrix = mtx;
}
Now all you got to know to utilize this in your case, is the following N factors:
Q1: from what angle you want to project the shadow?
A1: horizontal factor is the skew variable itself, while vertical angle is stored as constant here, called MAX_SHADOW_HEIGHT_MULTIPLIER
Q2: do you want to project shadow only "upwards", or freely?
A2: if "upwards" is fine, keep skew in the positive range, otherwise let it take negative values as well for a "downward" shadow
P.S.: if you render the internals of the objects that they don't snap to 0 y as a base point, you can make them seem float/sink, or offset both objects vertically with a predefined value, with the opposite sign.
You face 1 very simple problem, as you said:
'What I want to determine is the coordinates of the C & D points, thing that could be easy if I wasn't struggling to find the "Origin bis" coordinates.'
But these co-ordinates relate to each other, so without one (or another value such as an angle) you cannot have the other. If you are to try this in 3D you are simply allowing the 3D engine to define 'Origin bis' and do your calculating for C and D itself.
So regardless you will need an 'Original bis', another value relating to the redline or your Rect for which to calculate the placement of C and D.
I remember making stuff like this and sometimes it's better to just stick with simple, you either make an 'Original bis' defines by yourself (it can be either stationary or move with the player/background) and get C and D the way you got A and B only that you use a lower line than the red line, or as I would of done, once you have A and B, simple skew/rotate your projection from those points down a bit further, and you get something the same as an 'Original bis' that follows the player. This works fine at simulating 'feeling of something real' but sadly as has been said, it looking real depends on what you are portraying. We do not know what the areas above or below the red line are (sky/ground, ground/water) and whether 'Origin' and 'Origin bis' is your light source, vanishing point, etc.