Advertisement

FPS: Handle rotating gun with camera

Started by May 03, 2024 02:00 PM
1 comment, last by JoeJ 7 months, 2 weeks ago

Hi,

I am working on a basic FPS game and I am trying to get my gun model to stay attached to the the camera when the camera is looking around using mouse look.

I have looked around and could not find any good solutions. My initial thought was to just take the pitch and yaw of the camera and then create a rotation matrix to apply to the model's model matrix which would hopefully rotate the mesh as the camera look direction changes. However, this introduced some issues where the yaw would be inverted for the player mesh and the pitch would not go up and down it would go diagonal. As seen in the clip below.

Pitch doesn't behave correctly. Yaw is inverted.

I've tried inverting the yaw radian amount to correct the inverted movement the player experiences but this just makes the camera look another way and the gun is no longer ever in front of the camera.

Image

I'm wondering if anyone has any advice on how I might approach keeping the gun always on the camera no matter which way the camera is looking.

This is my current code:

// Mouse input control function:

static void glfw_callback_mouse(GLFWwindow* window, double x, double y)
{
	vkWindow* windowClass = reinterpret_cast<vkWindow*>(glfwGetWindowUserPointer(window));

	if (playerCamera)
	{
		double x_offset = x - windowClass->m_lastMousePosX;
		double y_offset = windowClass->m_lastMousePosY - y;

		windowClass->m_lastMousePosX = x;
		windowClass->m_lastMousePosY = y;

		const float mouseSensitivity = 0.1f;
		x_offset *= mouseSensitivity;
		y_offset *= mouseSensitivity;

		windowClass->camera->yaw += x_offset;
		windowClass->camera->pitch += y_offset;

		glm::vec3 direction = glm::vec3(0.0f);
		direction.x = static_cast<float>(std::cos(glm::radians(windowClass->camera->yaw)) * std::cos(glm::radians(windowClass->camera->pitch)));
		direction.y = static_cast<float>(std::sin(glm::radians(windowClass->camera->pitch)));
		direction.z = static_cast<float>(std::sin(glm::radians(windowClass->camera->yaw)) * std::cos(glm::radians(windowClass->camera->pitch)));
		windowClass->camera->SetDirection(glm::normalize(direction));
	}
}

// Update method inside the player class:
void Update()
{
	FPSCamera->Update();
	glm::vec cameraPosition = FPSCamera->GetPosition();
	cameraPosition.y = 20.0f;
	FPSCamera->SetPosition(cameraPosition);

	m_position = FPSCamera->GetPosition();

	float rotX = glm::radians(FPSCamera->yaw);
	float rotY = glm::radians(FPSCamera->pitch);

	glm::mat4 yawRotation = glm::rotate(glm::mat4(1.0f), rotX, glm::vec3(0.0f, 1.0f, 0.0f)); 
	glm::mat4 pitchRotation = glm::rotate(glm::mat4(1.0f), rotY, glm::vec3(1.0f, 0.0f, 0.0f)); 

	glm::mat4 combinedRotation = pitchRotation * yawRotation;

	m_Model->SetRotationMatrix(combinedRotation);

	glm::vec3 assetpos = glm::vec3(m_position.x, -14.0f, m_position.z);

	glm::vec3 modelPosition = (FPSCamera->GetPosition() + FPSCamera->GetDirection()) * 1.0f;

	m_position = modelPosition;
	m_position.y = -14.0f;
	m_Model->SetTranslation(m_position);
}

// Mesh transform before draw
void GameModel::Draw(...)
{
	for (auto& mesh : meshes)
	{

		psConstant push_constant = {};
		push_constant.model = glm::mat4(1.0f);
		push_constant.model = glm::translate(push_constant.model, m_translate);
	
		push_constant.model = push_constant.model * m_RotationMatrix;
		push_constant.model = glm::scale(push_constant.model, m_Scale);

		vkCmdPushConstants(...);

		vkCmdBindIndexBuffer(..);
		vkCmdDrawIndexed(.....);
	}

}

snoken said:
windowClass->camera->SetDirection(glm::normalize(direction));

This function should create a orientation matrix for the camera (and / or it's inverse), which you could use directly instead trying to replicate it.

Besides, eventually the orientation of the model is right, but just the position is wrong?
Hard to tell because the gifs show no world so i can't see how you rotate the view.

This topic is closed to new replies.

Advertisement