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

Let's try to simplify a bit a reduce the code only to the parts that are relevant to getting the ahead position right.

Start with an identity model matrix. Calculate the world-space ahead position from the view matrix as we discussed. Translate the identity model matrix with the ahead position. This should give you a model matrix that transforms model space to the ahead position in world space. Use this model matrix in the standard transformation pipeline. Comment out any other code that is in that function. How does it behave? If it is behind the camera, flip the input (view-space) ahead position, so in the example you posted above change it to [0, 0, -2, 1].

Advertisement
I simplified the code down to the very basic:

//Main game engine rendering function pipeline in the codebase.
void Core::SceneRender(float interOcularDistance){
	//Declaring reusable model matrix.
	C3D_Mtx modelMatrix;

	//Compute projection matrix and update matrix to shader program.                                                                                                               
	Mtx_PerspStereoTilt(&this->projectionMatrix, 40.0f * (std::acos(-1) / 180.0f), 400.0f / 240.0f, 0.01f, 1000.0f, interOcularDistance, 2.0f, false);
	C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, this->uLoc_projection, &this->projectionMatrix);

	//Do something about view matrix.
	this->player.RenderUpdate(&this->viewMatrix);

	//Compute view matrix and update matrix to shader program.
	C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, this->uLoc_view, &this->viewMatrix);

	//Draw the vertex buffer objects.                     
	for (size_t i = 0; i < this->gameObjects.size(); i++) {
		//Switch buffers
		this->gameObjects[i]->ConfigureBuffer();

		//Calculate model view matrix.
		Mtx_Identity(&modelMatrix);
		
		if (this->player.cameraManipulateFlag){
			C3D_Mtx inverse;
			Mtx_Copy(&inverse, &this->viewMatrix);                                           
			Mtx_Inverse(&inverse);                                                            
			
			//Doing the simplified calculations.
			C3D_FVec aheadPosition = FVec4_New(0.0f, 0.0f, -3.0f, 1.0f);
			aheadPosition = Mtx_MultiplyFVec4(&inverse, aheadPosition);
			Mtx_Translate(&modelMatrix, aheadPosition.x, aheadPosition.y, aheadPosition.z, true);
			
			text(18, 0, "Player picking up object.     ");
			std::cout << "Ahead : " << std::fixed << std::setprecision(1) << aheadPosition.x << "  " << aheadPosition.y << "  " << aheadPosition.z << "  " << aheadPosition.w << std::endl;
			std::cout << "Player: " << std::fixed << std::setprecision(1) << this->player.camX << "  0.0  " << this->player.camZ << std::endl;
			std::cout << "Model Matrix: " << std::endl;
			for (int i = 0; i < 16; i++){
				float a = modelMatrix.m[(i/4) + (3-i%4)];
				if (a < 0.0f){
					std::cout << std::fixed << std::setprecision(1) << a << "  ";	
				}
				else {
					std::cout << std::fixed << std::setprecision(1) << a << "   ";
				}
				if (i % 4 == 3){
					std::cout << std::endl;
				}
			}
		}
		else{
			//This is to clear the output console.
			text(18, 0, "Player not picking up object.");
			text(19, 0, "                              ");
			text(20, 0, "                              ");
			text(21, 0, "                              ");
			text(22, 0, "                              ");
			text(23, 0, "                              ");
			text(24, 0, "                              ");
			text(25, 0, "                              ");
			text(26, 0, "                              ");
			text(27, 0, "                              ");
			text(28, 0, "                              ");
		}
		
		//Update to shader program.
		C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, this->uLoc_model, &modelMatrix);

		//Render entity.
		this->gameObjects[i]->Render();
	}
}
And here's the animation of the model moving around:

oHIDcmA.gif

Observing this, I can now see the object set at the world origin, while the camera is rotating around. When the player activates "cameraManipulationFlag", the object is picked up, and is placed directly in front of the player's camera. There's no rotations involved, so the object never faces the player.

From here, I can now see the object's previous rotation attempt is what's causing the glitchy translation issues. That also means I may need to re-figure out how to get the object oriented towards the player as the player "holds" the object around.

Thanks, AndorPatho, at least the positioning/translation works now. (Just not apparent in the GIF, since I have the output console showing it clearly).

I'm going to look into testing to see if the 3D graphics library contains Quaternion.LookAt() and see if it's possible to make the object always orient itself to the player.
*Duplicate post from above. Sorry.*

Luckily adding the rotation part should not be that hard either. We can just generalize what we did with the position to the entire transform of the object. We want the object to be "frozen" in view space, so we take the entire transform in view space, and transform it to world space.

So instead of taking the ahead position, multiplying with the inverse of the view matrix, then using it in the model matrix, we do it in a slightly different order:

Take the ahead position, plug it into the model matrix and then multiply with the inverse of the view matrix.

Sorry if I confused you earlier with doing just the translation part, but maybe it helped you understand what the different parts of a transform do better. Another interesting way to look at this problem is this: you want the object to be frozen in view space, so what you are essentially trying to do is cancel the view transformation (because you don't want the position and rotation of the camera to have any effect on the object's screen position). The way I showed you works, because if you put all the transforms together, you get: Model * View^-1 * View, which is just Model * Identity. If you are able to modify the view matrix for just this single object, you could also just set the view matrix to identity directly, and achieve the same effect.

Take the ahead position, plug it into the model matrix and then multiply with the inverse of the view matrix.


How do you "plug" it in? As in, out of the 4 rows/columns, what matrix row/column do I put the aheadPosition vector in?

So instead of taking the ahead position, multiplying with the inverse of the view matrix, then using it in the model matrix, we do it in a slightly different order: Take the ahead position, plug it into the model matrix and then multiply with the inverse of the view matrix.


I finally understood what you mean by "plugging in". This means "translate" the model matrix by the aheadPosition. It took a while to figure out.

The object is now placed in front of the camera. Thanks again for your help!

Yeah, sorry about the vague wording. Glad it's working now, and you're welcome.

This topic is closed to new replies.

Advertisement