Jak naprawić obrót kamery za pomocą myszki w mojej implementacji?

0

Mam taki kod:

struct Camera
{
	void setPerspective(float fov, float aspect, float nearClip, float farClip)
	{
		projection = glm::perspective(glm::radians(fov), aspect, farClip, nearClip);
		inverseProjection = glm::inverse(projection);
	}

	void setWorldOffset(const glm::vec3& offset)
	{
		updatedMatrices = false;
		position() = glm::vec4(offset, 1.0f);
	}

	void AddWorldOffset(const glm::vec3& offset)
	{
		updatedMatrices = false;
		position() += glm::vec4(offset, 1.0f);
	}

	void AddRelativeOffset(const glm::vec3& offset)
	{
		UpdateBasis();

		updatedMatrices = false;
		position() += glm::vec4(
			offset.x * getRight() + 
			offset.y * getUp() + 
			offset.z * getForward(), 
			1.0f
		);
	}

	void setWorldAngles(const glm::vec3& angles)
	{
		updatedBasis = false;
		updatedMatrices = false;

		rotation = glm::angleAxis(angles.z, glm::vec3(0.0f, 0.0f, 1.0f));
		rotation *= glm::angleAxis(angles.x, glm::vec3(1.0f, 0.0f, 0.0f));
		rotation *= glm::angleAxis(angles.y, glm::vec3(0.0f, 1.0f, 0.0f));

		rotation = normalize(rotation);
	}

	void AddWorldAngles(const glm::vec3& angles)
	{
		updatedBasis = false;
		updatedMatrices = false;

		rotation *= glm::angleAxis(angles.z, glm::vec3(0.0f, 0.0f, 1.0f));
		rotation *= glm::angleAxis(angles.x, glm::vec3(1.0f, 0.0f, 0.0f));
		rotation *= glm::angleAxis(angles.y, glm::vec3(0.0f, 1.0f, 0.0f));

		rotation = normalize(rotation);
	}

	void setRelativeAngles(const glm::vec3& angles)
	{
		updatedBasis = false;
		updatedMatrices = false;

		rotation = glm::angleAxis(angles.z, getForward());
		rotation *= glm::angleAxis(angles.x, getRight());
		rotation *= glm::angleAxis(angles.y, getUp());

		rotation = normalize(rotation);
	}

	void AddRelativeAngles(const glm::vec3& angles)
	{
		updatedBasis = false;
		updatedMatrices = false;

		rotation *= glm::angleAxis(angles.z, getForward());
		rotation *= glm::angleAxis(angles.x, getRight());
		rotation *= glm::angleAxis(angles.y, getUp());

		rotation = glm::normalize(rotation);
	}

	void UpdateBasis()
	{
		if (updatedBasis) return;
		updatedBasis = true;

		const auto mat = glm::mat3_cast(rotation);
		inverseView[0] = glm::vec4(mat[0], 0.0f);
		inverseView[1] = glm::vec4(mat[1], 0.0f);
		inverseView[2] = glm::vec4(mat[2], 0.0f);
		inverseView[3] = glm::vec4(getPosition(), 1.0f);
	}

	void RecalculateView()
	{
		if (updatedMatrices) return;
		updatedMatrices = true;

		UpdateBasis();

		view = glm::inverse(inverseView);
		viewProjection = projection * view;
		//inverseViewProjection = glm::inverse(viewProjection);
        inverseViewProjection = inverseView * inverseProjection

		frustumCorners[0] = glm::vec3(inverseViewProjection * glm::vec4(-1.0f, -1.0f, -1.0f, 1.0f));
		frustumCorners[1] = glm::vec3(inverseViewProjection * glm::vec4(1.0f, -1.0f, -1.0f, 1.0f));
		frustumCorners[2] = glm::vec3(inverseViewProjection * glm::vec4(-1.0f, 1.0f, -1.0f, 1.0f));
		frustumCorners[3] = glm::vec3(inverseViewProjection * glm::vec4(1.0f, 1.0f, -1.0f, 1.0f));
	}

	glm::vec4& position() { return inverseView[3]; }

	const glm::vec3 getRight() const { return glm::vec3(inverseView[0]); }
	const glm::vec3 getUp() const { return glm::vec3(inverseView[1]); }
	const glm::vec3 getForward() const { return glm::vec3(inverseView[2]); }
	const glm::vec3 getPosition() const { return glm::vec3(inverseView[3]); }

	[[nodiscard]] inline const std::array<glm::vec3, 4>& getFrustumCorners() const noexcept { return frustumCorners; }

private:
	glm::mat4 view = glm::mat4(1.0f);
	glm::mat4 projection = glm::mat4(1.0f);
	glm::mat4 viewProjection = glm::mat4(1.0f);

	glm::mat4 inverseView = glm::mat4(1.0f);
	glm::mat4 inverseProjection = glm::mat4(1.0f);
	glm::mat4 inverseViewProjection = glm::mat4(1.0f);

	std::array<glm::vec3, 4> frustumCorners{};

	glm::quat rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);

	bool updatedBasis = true;
	bool updatedMatrices = true;
};

na moje wygląda dobrze, renderowana scena też wygląda dobrze:

screenshot-20230924140154.png

napisałem też kod, który kontroluje tę kamerę:

const glm::vec2 mousePos = Input::get().getMousePosition();
const glm::vec2 delta = (mousePos - lastMousePosition);
lastMousePosition = mousePos;

if (Input::get().isKeyPressed(Key_Shift)) {
	speed = baseSpeed * shiftMultiplier;
} else {
	speed = baseSpeed;
}

if (Input::get().isKeyPressed(Key_W)) {
	camera.AddRelativeOffset(glm::vec3(0.0f, 0.0f, -speed * dt));
} else if (Input::get().isKeyPressed(Key_S)) {
	camera.AddRelativeOffset(glm::vec3(0.0f, 0.0f, speed * dt));
}

if (Input::get().isKeyPressed(Key_A)) {
	camera.AddRelativeOffset(glm::vec3(-speed * dt, 0.0f, 0.0f));
} else if (Input::get().isKeyPressed(Key_D)) {
	camera.AddRelativeOffset(glm::vec3(speed * dt, 0.0f, 0.0f));
}

if (Input::get().isKeyPressed(Key_Space)) {
	camera.AddRelativeOffset(glm::vec3(0.0f, speed * dt, 0.0f));
} else if (Input::get().isKeyPressed(Key_Control)) {
	camera.AddRelativeOffset(glm::vec3(0.0f, -speed * dt, 0.0f));
}

if (Input::get().isKeyPressed(Key_Q)) {
	camera.AddRelativeAngles(glm::vec3(0.0f, 0.0f, -speed * dt));
} else if (Input::get().isKeyPressed(Key_E)) {
	camera.AddRelativeAngles(glm::vec3(0.0f, 0.0f, speed * dt));
}

if (Input::get().isMouseButtonPressed(Mouse_Left)) {
	const float offsetLengthPercent = glm::length(delta) / (0.5f * 800.0f);
	const float scaledRotationSpeed = rotationSpeed * offsetLengthPercent;

	glm::vec3 angles = 0.0f;
	angles.x = glm::radians(-delta.y * scaledRotationSpeed * dt);
	angles.y = glm::radians(-delta.x * scaledRotationSpeed * dt);
	angles.z = 0.0f;
	camera.AddRelativeAngles(angles);
}

camera.RecalculateView();

no i ruch prawo, lewo, góra, dół, przód, tył działa, obrót na Q i E też działa, ale jak nakładam kilka typów obrotu, np. trochę roll na Q i potem ruszę myszką to ten obrót nie jest poprawny:

zatacza ona takie koło jak na filmiku:

jak to naprawić? Nie jestem pewien co tutaj jest nie tak.

0

a dlaczego tak masz te ify? znaczy W i S nie mogą być jednocześnie wcisnięte ale W i A tak?

0

czyli jak są dwa obroty jednocześnie to nie robisz po pierwszym UpdateBasis() ? co właściwie ta funkcja robi?

0

Może masz w nie takiej kolejności te obroty?

no i ruch prawo, lewo, góra, dół, przód, tył działa, obrót na Q i E też działa, ale jak nakładam kilka typów obrotu, np. trochę roll na Q i potem ruszę myszką to ten obrót nie jest poprawny:

Albo może przeliczasz coś w złej kolejności, jeśli chodzi o lokalne i globalne transformacje.

Bo na początku ci ten obrót działa? Jak obiekt jest w pozycji początkowej?

1 użytkowników online, w tym zalogowanych: 0, gości: 1