How To Obtain 3D Object Picking Up Distance Target Position From Camera View Matrix?

Started by
15 comments, last by Andor Patho 7 years, 8 months ago

Context:

I have 3 matrices used in a specially crafted 3D library. It does not use OpenGL nor DirectX, but I'm guessing it's a DirectX variant implementation, where the camera moves around in the 3D world, instead of staying put at the world origin.

I have model matrix, used to manipulate the 3D objects in 3D space. That includes rotation, translation, and scaling.

I have a view matrix, used to determine where in 3D space is the camera located. I translate the view matrix to move the camera around.

And finally, I have the projection matrix, where it uses stereoscopic perspective. This is aided by a slider that determines the inter-ocular distance for left and right perspective render targets.

Using these matrices, I am on the path to implement a "3D Object Pick Up" mechanic, so the player can "pick" up objects and hold them in front of the camera until they "let go". The issue I am having at the moment, is obtaining the vector position to move the objects up close to the player and move them in a circle around the camera. I figured I can apply matrix transformations on the model matrix to move them, but that causes the 3D objects to move erratically.

Problem:

QEVWDN5.gif

Here's a simple GIF animation showing the target vector position that I wanted to obtain via camera view matrix.

I would like to have this position that is always at a set distance away from the player's camera position while the player is rotating the camera around. This position will be the spot where the player engages with objects by "picking them up" and "holding them at that location as the camera looks around.

Even though it's 2D in the GIF, I am referring to a 3D pick up vector position, translated from the camera view matrix.

Current Progress:

I only know how to set the object's rotation, so it will always face the camera as the object is "held" by the player. Here's the following code:


void Player::Manipulate(std::shared_ptr<GameObject> obj, C3D_Mtx& currentProjectionMatrix, C3D_Mtx& currentViewMatrix, C3D_Mtx& modelMatrix){
	if (this->cameraManipulateFlag){
		//Matrix and C3D_Mtx.
		//C3D_Mtx requires all rows to be [WZYX], instead of the other way around (XYZW).
		//This is due to how the GPU reads the matrix data.
		//Everything else mathematically is the same.
		
		//Rotation - Obtaining the inverse matrix.
		C3D_Mtx inverse, result;
		Mtx_Copy(&inverse, &currentViewMatrix);
		Mtx_Inverse(&inverse);
		
		//Rotation - Multiplying the inverse with other matrices to get the actual rotation.
		Mtx_Multiply(&result, &modelMatrix, &this->oldViewMatrix);
		Mtx_Multiply(&modelMatrix, &result, &inverse);
	}
	else {
		Mtx_Copy(&this->oldViewMatrix, &currentViewMatrix);
	}
}

Does anyone know how to obtain the vector position in front of the camera by a set distance (usually 4 to 6 unit vectors away from the player camera view)? Thanks in advance.

I'm stuck on this problem for 2 weeks now. And nothing is progressing.

Advertisement

- deleted -

I've looked into what you mentioned above. I'm pretty sure that's not what I was looking for (range of hit distance, detection of objects within a certain radius from the player, etc.), even though it is helpful to know about.

What I am looking for is the method of obtaining the vector position after translating and rotating a matrix copy of the camera view matrix. An analogy of the vector position in front of player camera a set distance away, is like holding your arm out in front of you, and tracking your fist's absolute world position as you sway your upper body from the waist to the left and right, while not moving your outstretched arm wildly.

If I understand you correctly, you want to calculate the world space position of a point a certain distance straight ahead (in the camera look direction) from the camera. That should be pretty straightforward: take the position of your point in view space - assuming "into the screen" is +z in your coordinate system, this would be a point with coordinates P[0, 0, distance, 1], and multiply it with your view matrix. This should give you the coordinates of your point in world space.

If I understand you correctly, you want to calculate the world space position of a point a certain distance straight ahead (in the camera look direction) from the camera. That should be pretty straightforward: take the position of your point in view space - assuming "into the screen" is +z in your coordinate system, this would be a point with coordinates P[0, 0, distance, 1], and multiply it with your view matrix. This should give you the coordinates of your point in world space.

I did your method inside a test application. The resulting coordinates after mulitplying the view matrix with the vector P, didn't seem to match up to the player's world coordinates:

UaCKHo5.gif

As you can see, the player's world coordinate is near (12, -40), but the world coordinate of the object's "ahead" position (the vector P used in your post) is very far away, hovering near the origin. You may ignore the extra "Player Position" at the very bottom. It's a side effect of forcing the output to a specific position on the screen.

Is there something wrong?


//Gamedev.net                                                                                                                          
C3D_FVec aheadPosition = FVec4_New(0.0f, 0.0f, -4.0f, 1.0f);   //Create new vector, P.                                                 
Mtx_Copy(&result, &currentViewMatrix);                         //Copies from current view matrix to temp container, result.            
aheadPosition = Mtx_MultiplyFVec3(&result, aheadPosition);     //Multiply view matrix with vector P, lhs = result, rhs = aheadPosition. Get new vector P'.
text(19, 0, " ");                                                                                                                      
std::cout << "Ahead Position: " << aheadPosition.x << "   " << aheadPosition.y << "    " << aheadPosition.z << std::endl;              
std::cout << std::fixed << std::setprecision(2) << "Player position: " << this->camX << "   0.0    " << this->camZ << std::endl;       
                                                                                                                                       
//Setting the object's world coordinates, using vector P'.                                                                                              
obj->positionX = aheadPosition.x;                                                                                                      
obj->positionY = aheadPosition.y;                                                                                                      
obj->positionZ = aheadPosition.z;                                                                                                      

When you are moving the player position around, the ahead position does not change, which means the translation component of your view matrix doesn't seem to affect it (rotation seems fine). I think I see the problem:

aheadPosition = Mtx_MultiplyFVec3(&result, aheadPosition);

You use the Mtx_MultiplyFVec3 function, which guessing by the name multiplies matrices with a 3-component vector. I'm guessing if you pass a 4-component vector to it, the 4th component gets ignored (or considered 0), which in this case is quite important, in short if the 4th component is 0, the vector represents a direction and magnitude not a position, so it can only be rotated, not translated. If this sounds confusing, read up a little on linear algebra. If you work with 3d transformations, the minimum you have to understand are the components of the 4x4 transformation matrix (rotation, translation, scale), and how it behaves with vectors using homogeneous coordinates. If you work out the matrix multiplication on paper, you will see how the 0 or 1 in the 4th component changes the outcome.

Short answer: see if you have a variant of the matrix multiplication function for 4-component vectors.

1ojUysF.gif

Ok, so I swapped it out now. It's all good.
.

//Gamedev.net                                                                                                                           
C3D_FVec aheadPosition = FVec4_New(0.0f, 0.0f, -4.0f, 1.0f);   //Create new vector, P. Replaced FVec3_New() to FVec4_New().             
Mtx_Copy(&result, &currentViewMatrix);                         //Copies from current view matrix to temp container, result.             
aheadPosition = Mtx_MultiplyFVec4(&result, aheadPosition);     //Multiply view matrix with vector P. Vec3 swapped with Vec4  <----
text(19, 0, " ");                                                                                                                       
std::cout << "Ahead Position: " << aheadPosition.x << "   " << aheadPosition.y << "    " << aheadPosition.z << std::endl;               
std::cout << std::fixed << std::setprecision(2) << "Player position: " << this->camX << "   0.0    " << this->camZ << std::endl;        
.


It seems the new "aheadPosition" vector is giving coordinates that are way too far away from the player camera. I believed I may need to clamp the values to a certain magnitude (distance) away from the camera. Is this the right way to go about it?

EDIT: Maybe I need to normalize "aheadPosition" vector, and then add it to the player camera's position?
I made animations to show that the aheadPosition world coordinates are not entirely correct. The cube is not following where the player is going as the player is moving or facing.

6FQPjbO.gif

A top-down animation depicting what was displayed above, is shown here:

ykgWxs7.gif

And this is a top-down animation of my ideal/intended path the object should be moving as the player camera rotates.

2oOeH1y.gif

I feel like I'm almost there. If anyone knows how to work with this for now, I really appreciated it.

Try multiplying with the inverse of the view matrix. I assumed based on what you wrote, that the view matrix contains the camera position and rotation, and your transformations get applied as model * view^-1, but the view matrix might already be inverted, so it contains the transformation into view space from world space. That would mean you need to go the other direction, and need to invert the view matrix.

I'm very close to fruition, but it doesn't seem to be right at the moment. After multiplying by the inverse of the view matrix, the object is somehow placed directly behind the player's camera. As the player camera rotates on the screen, the object rotates along with it, thus the player will never see it.

The rotation of the object is applied as modelMatrix * oldViewMatrix * (currentViewMatrix ^ -1).

The translation of the object is applied as modelMatrix * (currentViewMatrix ^ -1).

In between, the modelMatrix is never reverted to identity matrix, nor pushed to the matrix stack/popped back from matrix stack.

void Player::Manipulate(std::shared_ptr<GameObject> obj, C3D_Mtx& currentProjectionMatrix, C3D_Mtx& currentViewMatrix, C3D_Mtx& modelMatrix){                   
	if (this->cameraManipulateFlag){                                                                                                                            
		//Matrix and C3D_Mtx.                                                                                                                                   
		//C3D_Mtx requires all rows to be [WZYX], instead of the other way around (XYZW).                                                                       
		//This is due to how the GPU reads the matrix data.                                                                                                     
		//Everything else mathematically is the same.                                                                                                           
		                                                                                                                                                        
		//Rotation - Obtaining the inverse matrix.                                                                                                              
		C3D_Mtx inverse, result;                                                                                                                                
		Mtx_Copy(&inverse, &currentViewMatrix);                                                                                                                 
		Mtx_Inverse(&inverse);                                                                                                                                  
		                                                                                                                                                        
		//Rotation - Multiplying the inverse with other matrices to get the actual rotation.                                                                    
		Mtx_Multiply(&result, &modelMatrix, &this->oldViewMatrix);                                                                                              
		Mtx_Multiply(&modelMatrix, &result, &inverse);                                                                                                          
		                                                                                                                                                        
		                                                                                                                                                        
		//Gamedev.net                                                                                                                                           
		C3D_FVec aheadPosition = FVec4_New(0.0f, 0.0f, 2.0f, 1.0f);                                                                                             
		aheadPosition = Mtx_MultiplyFVec4(&inverse, aheadPosition);                                                                                             
		                                                                                                                                                        
		text(19, 0, " ");                                                                                                                                       
		std::cout << std::fixed << std::setprecision(2) << "Ahead : " << aheadPosition.x << "    " << aheadPosition.y << "    " << aheadPosition.z << std::endl;
		std::cout << std::fixed << std::setprecision(2) << "Player: " << this->camX << "  0.0  " << this->camZ << std::endl;                                    
                                                                                                                                                                
		Mtx_Translate(&modelMatrix, -aheadPosition.x, aheadPosition.y, -aheadPosition.z, true);                                                                 
	}                                                                                                                                                           
	else {                                                                                                                                                      
		Mtx_Copy(&this->oldViewMatrix, &currentViewMatrix);                                                                                                     
	}                                                                                                                                                           
}                                                                                                                                                               
I've been trying to get the object to show up on the screen, by translating it back in front of the player, and by reversing the signs of the coordinates, but nothing showed up on the screen.

However, I know the resulting "aheadPosition" coordinates is very ideal, since it is close to the player's camera position when it is set as P[0, 0, 1, 1] before multiplication. All I need to do is the figure out how to flip it to the other side, and this is where I don't know how to do so.

This topic is closed to new replies.

Advertisement