Skip to main content
1-Visitor
March 5, 2020
Solved

Simultaniously rotate model and image Vuforia Studio

  • March 5, 2020
  • 2 replies
  • 5479 views

Hello,

I have tried the Slider widget on the 2D, and did a 0 to 360° to rotate my 3D model, but the thing is i put images on the 3D Canvas that don't rotate, even if i bind the slider with them ( they rotate around themeselve and not around the 3D model).

So i would like to know if there's a possibility to "merge" the 3D model with images so it would be considered as one big model, that will rotate all the component, or if there's another solution to this problem.

I thanks you for taking time to answer me.

 

Best answer by tincescu
// $scope, $element, $attrs, $injector, $sce, $timeout, $http, $ionicPopup, and $ionicPopover services are available


let sin = Math.sin;
let cos = Math.cos
let PI = 3.141;


var stack = [];

// Information needed for rotation
class WidgetInfo
{ 	
 	constructor(initialX,initialY,initialZ,name){
 this.initialX = initialX;
 this.initialY = initialY;
 this.initialZ = initialZ;
 this.name = name;
 }
}


$scope.GetScaleMatrix = function(w,h,d) {
 return [
 w, 0, 0, 0,
 0, h, 0, 0,
 0, 0, d, 0,
 0, 0, 0, 1
 ];

 
}

$scope.GetRotationMatrixAroundXAxis = function(a) {
 	 a = a * (3.141 / 180);
 	 return [
 1, 0, 0, 0,
 0, cos(a), -sin(a), 0,
 0, sin(a), cos(a), 0,
 0, 0, 0, 1
 ];
}


$scope.GetRotationMatrixAroundYAxis = function(a) {
 	a = a * (3.141 / 180);
 return [
 cos(a), 0, sin(a), 0,
 0, 1, 0, 0,
 -sin(a), 0, cos(a), 0,
 0, 0, 0, 1
 ];
}

$scope.GetRotationMatrixAroundZAxis = function(a) {
 	a = a * (3.141 / 180);
 return [
 cos(a), -sin(a), 0, 0,
 sin(a), cos(a), 0, 0,
 0, 0, 1, 0,
 0, 0, 0, 1
 ];
}

$scope.GetTranslationMatrix = function(x,y,z) {
 
 	return [
 1, 0, 0, 0,
 0, 1, 0, 0,
 0, 0, 1, 0,
 x, y, z, 1
];
 
}



$scope.GetIdentityMatrix = function() {
 return [
 1, 0, 0, 0,
 0, 1, 0, 0,
 0, 0, 1, 0,
 0, 0, 0, 1
 ];
} 





function multiplyMatrixAndPoint(matrix, point) {
 // Give a simple variable name to each part of the matrix, a column and row number
 let c0r0 = matrix[ 0], c1r0 = matrix[ 1], c2r0 = matrix[ 2], c3r0 = matrix[ 3];
 let c0r1 = matrix[ 4], c1r1 = matrix[ 5], c2r1 = matrix[ 6], c3r1 = matrix[ 7];
 let c0r2 = matrix[ 8], c1r2 = matrix[ 9], c2r2 = matrix[10], c3r2 = matrix[11];
 let c0r3 = matrix[12], c1r3 = matrix[13], c2r3 = matrix[14], c3r3 = matrix[15];
 
 // Now set some simple names for the point
 let x = point[0];
 let y = point[1];
 let z = point[2];
 let w = point[3];
 
 // Multiply the point against each part of the 1st column, then add together
 let resultX = (x * c0r0) + (y * c0r1) + (z * c0r2) + (w * c0r3);
 
 // Multiply the point against each part of the 2nd column, then add together
 let resultY = (x * c1r0) + (y * c1r1) + (z * c1r2) + (w * c1r3);
 
 // Multiply the point against each part of the 3rd column, then add together
 let resultZ = (x * c2r0) + (y * c2r1) + (z * c2r2) + (w * c2r3);
 
 // Multiply the point against each part of the 4th column, then add together
 let resultW = (x * c3r0) + (y * c3r1) + (z * c3r2) + (w * c3r3);
 
 return [resultX, resultY, resultZ, resultW];
}


function multiplyMatrices(matrixA, matrixB) {
 // Slice the second matrix up into rows
 let row0 = [matrixB[ 0], matrixB[ 1], matrixB[ 2], matrixB[ 3]];
 let row1 = [matrixB[ 4], matrixB[ 5], matrixB[ 6], matrixB[ 7]];
 let row2 = [matrixB[ 8], matrixB[ 9], matrixB[10], matrixB[11]];
 let row3 = [matrixB[12], matrixB[13], matrixB[14], matrixB[15]];

 // Multiply each row by matrixA
 let result0 = multiplyMatrixAndPoint(matrixA, row0);
 let result1 = multiplyMatrixAndPoint(matrixA, row1);
 let result2 = multiplyMatrixAndPoint(matrixA, row2);
 let result3 = multiplyMatrixAndPoint(matrixA, row3);

 // Turn the result rows back into a single matrix
 return [
 result0[0], result0[1], result0[2], result0[3],
 result1[0], result1[1], result1[2], result1[3],
 result2[0], result2[1], result2[2], result2[3],
 result3[0], result3[1], result3[2], result3[3]
 ];
}


$scope.UpdateImagePosition = function() {
 
 	let transformMatrix = $scope.GetIdentityMatrix(); 	
 
	for(i=0; i<stack.length; i++) 
 {
 	name = stack[i].name;
 	initialX = stack[i].initialX;
 	initialY = stack[i].initialY;
 	initialZ = stack[i].initialZ;
 let transformMatrix = $scope.GetIdentityMatrix(); 	
 transformMatrix = multiplyMatrices(transformMatrix , $scope.GetTranslationMatrix( $scope.view.wdg['model-1'].x, $scope.view.wdg['model-1'].y,$scope.view.wdg['model-1'].z));

 transformMatrix = multiplyMatrices(transformMatrix , $scope.GetRotationMatrixAroundYAxis(-$scope.view.wdg['model-1'].ry));
 transformMatrix = multiplyMatrices(transformMatrix , $scope.GetTranslationMatrix( initialX, initialY, initialZ)); 

 $scope.view.wdg[name].x = transformMatrix [12];
 $scope.view.wdg[name].y = transformMatrix [13];
 $scope.view.wdg[name].z = transformMatrix [14]; 
 }
	$scope.intervalPromise = $interval($scope.UpdateImagePosition, 100, 1, true); 
}

$scope.UpdateTimer = function() {
	 	
}

$scope.init = function() { 

 
 $scope.AddWidgetToRotateSystem('3DImage-1');
 $scope.AddWidgetToRotateSystem('3DImage-2');

 $scope.UpdateImagePosition(); 

}

$scope.AddWidgetToRotateSystem = function(name)
{
 	widgetInfo = new WidgetInfo($scope.view.wdg[name].x,$scope.view.wdg[name].y,$scope.view.wdg[name].z,name);
 stack.push(widgetInfo);
}

angular.element(document).ready(function () {
	$scope.init();
});

 

I made it so that in the Init function you can add all the images that you want to rotate.

This approach is good becasue you are not forced to rotate all the widgets, instead you rotate only the ones you need.

 

You can see in the video below that I am rotating 2/3 3D images.

2 replies

5-Regular Member
March 5, 2020

Hello, is the behaviour in the video what you are looking for?

 

In this case, it might be a bit complicated.

We need to use a so-called transformation matrix in order to relatively translate the 3D Image around the arm.

You can find more about these here:

https://www.tutorialspoint.com/computer_graphics/3d_transformation.htm

https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Matrix_math_for_the_web

 

The code I used is here ( I also uploaded the project if you want to take a deeper look):

// $scope, $element, $attrs, $injector, $sce, $timeout, $http, $ionicPopup, and $ionicPopover services are available


let sin = Math.sin;
let cos = Math.cos
let PI = 3.141;


var initialY, initialZ;

$scope.GetScaleMatrix = function(w,h,d) {
 return [
 w, 0, 0, 0,
 0, h, 0, 0,
 0, 0, d, 0,
 0, 0, 0, 1
 ];

 
}

$scope.GetRotationMatrixAroundXAxis = function(a) {
 	 a = a * (3.141 / 180);
 	 return [
 1, 0, 0, 0,
 0, cos(a), -sin(a), 0,
 0, sin(a), cos(a), 0,
 0, 0, 0, 1
 ];
}


$scope.GetRotationMatrixAroundYAxis = function(a) {
 	a = a * (3.141 / 180);
 return [
 cos(a), 0, sin(a), 0,
 0, 1, 0, 0,
 -sin(a), 0, cos(a), 0,
 0, 0, 0, 1
 ];
}

$scope.GetRotationMatrixAroundZAxis = function(a) {
 	a = a * (3.141 / 180);
 return [
 cos(a), -sin(a), 0, 0,
 sin(a), cos(a), 0, 0,
 0, 0, 1, 0,
 0, 0, 0, 1
 ];
}

$scope.GetTranslationMatrix = function(x,y,z) {
 
 	return [
 1, 0, 0, 0,
 0, 1, 0, 0,
 0, 0, 1, 0,
 x, y, z, 1
];
 
}



$scope.GetIdentityMatrix = function() {
 return [
 1, 0, 0, 0,
 0, 1, 0, 0,
 0, 0, 1, 0,
 0, 0, 0, 1
 ];
} 





function multiplyMatrixAndPoint(matrix, point) {
 // Give a simple variable name to each part of the matrix, a column and row number
 let c0r0 = matrix[ 0], c1r0 = matrix[ 1], c2r0 = matrix[ 2], c3r0 = matrix[ 3];
 let c0r1 = matrix[ 4], c1r1 = matrix[ 5], c2r1 = matrix[ 6], c3r1 = matrix[ 7];
 let c0r2 = matrix[ 8], c1r2 = matrix[ 9], c2r2 = matrix[10], c3r2 = matrix[11];
 let c0r3 = matrix[12], c1r3 = matrix[13], c2r3 = matrix[14], c3r3 = matrix[15];
 
 // Now set some simple names for the point
 let x = point[0];
 let y = point[1];
 let z = point[2];
 let w = point[3];
 
 // Multiply the point against each part of the 1st column, then add together
 let resultX = (x * c0r0) + (y * c0r1) + (z * c0r2) + (w * c0r3);
 
 // Multiply the point against each part of the 2nd column, then add together
 let resultY = (x * c1r0) + (y * c1r1) + (z * c1r2) + (w * c1r3);
 
 // Multiply the point against each part of the 3rd column, then add together
 let resultZ = (x * c2r0) + (y * c2r1) + (z * c2r2) + (w * c2r3);
 
 // Multiply the point against each part of the 4th column, then add together
 let resultW = (x * c3r0) + (y * c3r1) + (z * c3r2) + (w * c3r3);
 
 return [resultX, resultY, resultZ, resultW];
}


function multiplyMatrices(matrixA, matrixB) {
 // Slice the second matrix up into rows
 let row0 = [matrixB[ 0], matrixB[ 1], matrixB[ 2], matrixB[ 3]];
 let row1 = [matrixB[ 4], matrixB[ 5], matrixB[ 6], matrixB[ 7]];
 let row2 = [matrixB[ 8], matrixB[ 9], matrixB[10], matrixB[11]];
 let row3 = [matrixB[12], matrixB[13], matrixB[14], matrixB[15]];

 // Multiply each row by matrixA
 let result0 = multiplyMatrixAndPoint(matrixA, row0);
 let result1 = multiplyMatrixAndPoint(matrixA, row1);
 let result2 = multiplyMatrixAndPoint(matrixA, row2);
 let result3 = multiplyMatrixAndPoint(matrixA, row3);

 // Turn the result rows back into a single matrix
 return [
 result0[0], result0[1], result0[2], result0[3],
 result1[0], result1[1], result1[2], result1[3],
 result2[0], result2[1], result2[2], result2[3],
 result3[0], result3[1], result3[2], result3[3]
 ];
}


$scope.UpdateImagePosition = function() {
 
 	let transformMatrix = $scope.GetIdentityMatrix(); 	
	

 transformMatrix = multiplyMatrices(transformMatrix , $scope.GetTranslationMatrix( $scope.view.wdg['model-1'].x, $scope.view.wdg['model-1'].y,$scope.view.wdg['model-1'].z));

 	transformMatrix = multiplyMatrices(transformMatrix , $scope.GetRotationMatrixAroundYAxis(-$scope.view.wdg['model-1'].ry));
 	transformMatrix = multiplyMatrices(transformMatrix , $scope.GetTranslationMatrix( 0, initialY, initialZ)); 

 	$scope.view.wdg['3DImage-1'].x = transformMatrix [12];
 	$scope.view.wdg['3DImage-1'].y = transformMatrix [13];
 	$scope.view.wdg['3DImage-1'].z = transformMatrix [14]; 


	$scope.intervalPromise = $interval($scope.UpdateImagePosition, 100, 1, true); 
}

$scope.UpdateTimer = function() {
	 	
}

$scope.init = function() { 
 	initialY = $scope.view.wdg['3DImage-1'].y;
 	initialZ = $scope.view.wdg['3DImage-1'].z;
 	$scope.UpdateImagePosition(); 

}

angular.element(document).ready(function () {
	$scope.init();
});

 

 

 

 

MaximeDid1-VisitorAuthor
1-Visitor
March 9, 2020

Hello, 

First of all i want to thank you for the reponse.

I have encoutered 2 problems with your solution:

1- When i put the code, it translates the image to the 0 of the X axis 

2- I can't rotate more than 1  image at the same time even if i copy the last function and replace the 3D-image 1 by 3D-image 2, it seems to take in account only the last functions i copy paste.

 

I wanna also say that it revolves correctly around the Y axis like i want.

 

Thank You,

 

 

5-Regular Member
March 9, 2020

 

 

// $scope, $element, $attrs, $injector, $sce, $timeout, $http, $ionicPopup, and $ionicPopover services are available


let sin = Math.sin;
let cos = Math.cos
let PI = 3.141;


var initialX, initialY, initialZ;

$scope.GetScaleMatrix = function(w,h,d) {
 return [
 w, 0, 0, 0,
 0, h, 0, 0,
 0, 0, d, 0,
 0, 0, 0, 1
 ];

 
}

$scope.GetRotationMatrixAroundXAxis = function(a) {
 	 a = a * (3.141 / 180);
 	 return [
 1, 0, 0, 0,
 0, cos(a), -sin(a), 0,
 0, sin(a), cos(a), 0,
 0, 0, 0, 1
 ];
}


$scope.GetRotationMatrixAroundYAxis = function(a) {
 	a = a * (3.141 / 180);
 return [
 cos(a), 0, sin(a), 0,
 0, 1, 0, 0,
 -sin(a), 0, cos(a), 0,
 0, 0, 0, 1
 ];
}

$scope.GetRotationMatrixAroundZAxis = function(a) {
 	a = a * (3.141 / 180);
 return [
 cos(a), -sin(a), 0, 0,
 sin(a), cos(a), 0, 0,
 0, 0, 1, 0,
 0, 0, 0, 1
 ];
}

$scope.GetTranslationMatrix = function(x,y,z) {
 
 	return [
 1, 0, 0, 0,
 0, 1, 0, 0,
 0, 0, 1, 0,
 x, y, z, 1
];
 
}



$scope.GetIdentityMatrix = function() {
 return [
 1, 0, 0, 0,
 0, 1, 0, 0,
 0, 0, 1, 0,
 0, 0, 0, 1
 ];
} 





function multiplyMatrixAndPoint(matrix, point) {
 // Give a simple variable name to each part of the matrix, a column and row number
 let c0r0 = matrix[ 0], c1r0 = matrix[ 1], c2r0 = matrix[ 2], c3r0 = matrix[ 3];
 let c0r1 = matrix[ 4], c1r1 = matrix[ 5], c2r1 = matrix[ 6], c3r1 = matrix[ 7];
 let c0r2 = matrix[ 8], c1r2 = matrix[ 9], c2r2 = matrix[10], c3r2 = matrix[11];
 let c0r3 = matrix[12], c1r3 = matrix[13], c2r3 = matrix[14], c3r3 = matrix[15];
 
 // Now set some simple names for the point
 let x = point[0];
 let y = point[1];
 let z = point[2];
 let w = point[3];
 
 // Multiply the point against each part of the 1st column, then add together
 let resultX = (x * c0r0) + (y * c0r1) + (z * c0r2) + (w * c0r3);
 
 // Multiply the point against each part of the 2nd column, then add together
 let resultY = (x * c1r0) + (y * c1r1) + (z * c1r2) + (w * c1r3);
 
 // Multiply the point against each part of the 3rd column, then add together
 let resultZ = (x * c2r0) + (y * c2r1) + (z * c2r2) + (w * c2r3);
 
 // Multiply the point against each part of the 4th column, then add together
 let resultW = (x * c3r0) + (y * c3r1) + (z * c3r2) + (w * c3r3);
 
 return [resultX, resultY, resultZ, resultW];
}


function multiplyMatrices(matrixA, matrixB) {
 // Slice the second matrix up into rows
 let row0 = [matrixB[ 0], matrixB[ 1], matrixB[ 2], matrixB[ 3]];
 let row1 = [matrixB[ 4], matrixB[ 5], matrixB[ 6], matrixB[ 7]];
 let row2 = [matrixB[ 8], matrixB[ 9], matrixB[10], matrixB[11]];
 let row3 = [matrixB[12], matrixB[13], matrixB[14], matrixB[15]];

 // Multiply each row by matrixA
 let result0 = multiplyMatrixAndPoint(matrixA, row0);
 let result1 = multiplyMatrixAndPoint(matrixA, row1);
 let result2 = multiplyMatrixAndPoint(matrixA, row2);
 let result3 = multiplyMatrixAndPoint(matrixA, row3);

 // Turn the result rows back into a single matrix
 return [
 result0[0], result0[1], result0[2], result0[3],
 result1[0], result1[1], result1[2], result1[3],
 result2[0], result2[1], result2[2], result2[3],
 result3[0], result3[1], result3[2], result3[3]
 ];
}


$scope.UpdateImagePosition = function() {
 
 	let transformMatrix = $scope.GetIdentityMatrix(); 	
	

 transformMatrix = multiplyMatrices(transformMatrix , $scope.GetTranslationMatrix( $scope.view.wdg['model-1'].x, $scope.view.wdg['model-1'].y,$scope.view.wdg['model-1'].z));

 	transformMatrix = multiplyMatrices(transformMatrix , $scope.GetRotationMatrixAroundYAxis(-$scope.view.wdg['model-1'].ry));
 	transformMatrix = multiplyMatrices(transformMatrix , $scope.GetTranslationMatrix( initialX, initialY, initialZ)); 

 	$scope.view.wdg['3DImage-1'].x = transformMatrix [12];
 	$scope.view.wdg['3DImage-1'].y = transformMatrix [13];
 	$scope.view.wdg['3DImage-1'].z = transformMatrix [14]; 
 
 


	$scope.intervalPromise = $interval($scope.UpdateImagePosition, 100, 1, true); 
}

$scope.UpdateTimer = function() {
	 	
}

$scope.init = function() { 
 	initialX = $scope.view.wdg['3DImage-1'].x;
 	initialY = $scope.view.wdg['3DImage-1'].y;
 	initialZ = $scope.view.wdg['3DImage-1'].z;
 	$scope.UpdateImagePosition(); 

}

angular.element(document).ready(function () {
	$scope.init();
});

Try it now, this should fix the x axe.

Also, I am working at a more generic code which will allow you to add any number of images with a single line of code for each. Will post soon.

16-Pearl
March 5, 2020

f you use a Spatial Target, rather than a ThingMark, you can just rotate the whole thing using gestures.

 

You haven't explained why you are trying to rotate everything, but I"m assuming by the fact that you are, you're not trying to align to real-world geometry so then a spatial experience could be used?

MaximeDid1-VisitorAuthor
1-Visitor
March 9, 2020

I have to present some machines to clients, and i want to use the thingmarks so that anyone can open the 3D model. I wanna rotate the model with the images because these images have to be close to a specific part of the machine ( when you click on them, you open a popup or an image with some documentation).