• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Jak znaleźć punkt w którym prosta przecina trójkąt w OpenGL.

VPS Starter Arubacloud
0 głosów
419 wizyt
pytanie zadane 2 stycznia 2022 w C i C++ przez tonn204 Mądrala (7,440 p.)
edycja 2 stycznia 2022 przez tonn204

Witam, w moim programie chcę wykryć czy prosta przecina trójkąt (prosta ta to promień który wychodzi z punktu w którym jest myszka). Próbuję to zrobić na podstawie tej strony i filmiku, ale nie rozumiem co oznaczają te wszystkie wektory typy vo, v1, albo kierunek promienia a przede wszystkim nie wiem skąd mam je wziąć aby użyć ich w kodzie. Wiem znam jedynie pozycje myszki. Proszę o dokładnie wytłumaczenie i z góry dziękuję za pomoc.

tutaj kod który zwraca koordynaty na których jest aktualnie myszka

#include "MousePicker.h"

MousePicker::MousePicker(Camera* camera, glm::mat4 projection, GLFWwindow* window)
{
	this->camera = camera;
	this->window = window;
	projectionMatrix = projection;
	viewMatrix = camera->GetViewMatrix();
}

glm::vec3 MousePicker::getCurrentRay()
{
	return this->currentRay;
}

void MousePicker::update()
{
	viewMatrix = camera->GetViewMatrix();
	currentRay = calculateMouseRay();
}

glm::vec3 MousePicker::calculateMouseRay()
{
	glfwGetCursorPos(window, &this->mouseX, &this->mouseY);
	glm::vec3 normalizedCoords = this->getNormalizedCoords(mouseX, mouseY);
	glm::vec4 rayClip = glm::vec4(normalizedCoords.x, normalizedCoords.y, -normalizedCoords.z, 1.0f);
	glm::vec4 eyeCoords = this->toEyeCoords(rayClip);
	glm::vec3 worldRay = this->toWorldCoords(eyeCoords);

	return worldRay;
}

glm::vec3 MousePicker::getNormalizedCoords(double xPos, double yPos)
{
	int width, height;

	glfwGetWindowSize(window, &width, &height);

	double x = ((2.0f * xPos) / (double)(width)) - 1.0f;
	double y = 1.0f - ((2.0f * yPos) / (double)(height));

	return glm::vec3(width, height, 1.0f);
}

glm::vec4 MousePicker::toEyeCoords(glm::vec4 rayClip)
{
	glm::mat4 invertedProjection = glm::inverse(projectionMatrix);
	glm::vec4 eyeCoords = invertedProjection * rayClip;

	return glm::vec4(eyeCoords.x, eyeCoords.y, -1.0f, 0.0f);
}

glm::vec3 MousePicker::toWorldCoords(glm::vec4 eyeCoords)
{
	glm::mat4 invertedView = glm::inverse(viewMatrix);
	glm::vec3 rayWorld = invertedView * eyeCoords;
	glm::vec3 finalRayWorld = glm::vec3(rayWorld.x, rayWorld.y, rayWorld.z);
	finalRayWorld = glm::normalize(finalRayWorld);

	return finalRayWorld;
}
#pragma once

#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "Camera.h"

class MousePicker
{
private:
	glm::vec3 currentRay;
	glm::mat4 projectionMatrix;
	glm::mat4 viewMatrix;

	double mouseX = 0.0f;
	double mouseY = 0.0f;

	Camera *camera;

	GLFWwindow* window;

	glm::vec3 calculateMouseRay();
	glm::vec3 getNormalizedCoords(double mouseX, double mouseY);
	glm::vec4 toEyeCoords(glm::vec4 rayClip);	
	glm::vec3 toWorldCoords(glm::vec4 eyeCoords);

public:
	MousePicker(Camera* camera, glm::mat4 projection, GLFWwindow* window);

	glm::vec3 getCurrentRay();
	void update();
};

 

komentarz 3 stycznia 2022 przez Oscar Nałogowiec (29,290 p.)
Jeden punkt to trochę za mało do wyznaczenia linii prostej. We wzorze

a*x + b*y +c = 0

są trzy parametry, potrzeba 3 liczb do określenia prostej.
komentarz 3 stycznia 2022 przez tonn204 Mądrala (7,440 p.)
Tak ta klasa MousePicker  zwraca zwraca mi 3 punkty na koordynatach x, y, z
komentarz 3 stycznia 2022 przez Oscar Nałogowiec (29,290 p.)
Nie zauważyłem, że mówimy o 3D. Wtedy potrzeba 4 liczb do określenia prostej.
komentarz 3 stycznia 2022 przez tonn204 Mądrala (7,440 p.)
edycja 3 stycznia 2022 przez tonn204

Program działa tylko częściowo. Kiedy kamerą wejdę w trójkąt dostaję informację że promien przecina trojkat. Dlaczego tak jest?

#include <iostream>

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "VBO.h"
#include "VAO.h"
#include "EBO.h"
#include "Camera.h"
#include "MousePicker.h"
#include "Shader.h"

#define EPSILON 0.000001
#define TEST_CULL

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow* window);

bool rayTriangleIntersect(glm::vec3 orygin, glm::vec3 dir, glm::vec3 v0, glm::vec3 v1, glm::vec3 v2, float &t, float &u, float &v);

const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;

float deltaTime = 0.0f;	
float lastFrame = 0.0f;

int main()
{
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	GLFWwindow* window = glfwCreateWindow(800, 600, "Hello Window!", NULL, NULL);
	if (window == NULL)
	{
		std::cout << "Failed to initialize GLFW" << std::endl;
		glfwTerminate();
		return -1;
	}

	glfwMakeContextCurrent(window);

	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	glViewport(0, 0, 800, 600);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
	glfwSetCursorPosCallback(window, mouse_callback);
	glfwSetScrollCallback(window, scroll_callback);

	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

	glEnable(GL_DEPTH_TEST);

	float vertices[] = {
	-0.5f, -0.5f, 0.0f,
	 0.5f, -0.5f, 0.0f,
	 0.0f,  0.5f, 0.0f
	};

	Shader shaderProgram("vertexShader.vs", "fragmentShader.fs");

	VAO VAO1;
	VAO1.Bind();
	VBO VBO(vertices, sizeof(vertices));
	VAO1.LinkAttrib(VBO, 0, 3, GL_FLOAT, 3 * sizeof(float), (void*)0);

	shaderProgram.use();

	glm::mat4 projection = glm::mat4(1.0f);
	MousePicker picker(&camera, &projection, window);

	float u, v, t;

	while (!glfwWindowShouldClose(window))
	{	
		float currentFrame = glfwGetTime();
		deltaTime = currentFrame - lastFrame;
		lastFrame = currentFrame;

		processInput(window);
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		picker.update();

		shaderProgram.use();

		projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
		shaderProgram.setMat4("projection", projection);

		glm::mat4 view = camera.GetViewMatrix();
		shaderProgram.setMat4("view", view);

		glm::vec3 rayCoords = picker.getCurrentRay();

		if (rayTriangleIntersect(camera.Position, rayCoords, glm::vec3(-0.5f, -0.5f, 0.0f), glm::vec3(0.5f, -0.5f, 0.0f), glm::vec3(0.0f, 0.5f, 0.0f), t, u, v))
		{
			std::cout << "Ray intersects triangle" << std::endl;
		}

		std::cout << rayCoords.x << "  " << rayCoords.y << "  " << rayCoords.z << std::endl;

		VAO1.Bind();
		glDrawArrays(GL_TRIANGLES, 0, 3);

		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	VAO1.Unbind();
	VBO.Unbind();
	VAO1.Delete();
	VBO.Delete();
	shaderProgram.~Shader();
	glfwTerminate();
}

bool rayTriangleIntersect(glm::vec3 orygin, glm::vec3 dir, glm::vec3 v0, glm::vec3 v1, glm::vec3 v2, float &t, float &u, float &v)
{
	glm::vec3 E1 = v1 - v0;
	glm::vec3 E2 = v2 - v0;
	glm::vec3 T = orygin - v0;

	glm::vec3 P = glm::cross(dir, E2);
	glm::vec3 Q;
	float det = glm::dot(E1, P);
	float inv_det;

	#ifdef TEST_CULL
	if (det < EPSILON)
		return false;

	u = glm::dot(T, P);
	if (u < 0.0f || u > det)
		return false;

	Q = glm::cross(T, E1);
	v = glm::dot(dir, Q);
	if (v < 0.0f || u + v > det)
		return false;

	t = glm::dot(E2, Q);
	inv_det = 1.0 / det;
	t *= inv_det;
	u *= inv_det;
	v *= inv_det;
	#else
	if (det > -EPSILON && det < EPSILON)
		return false;	
	inv_det = 1.0f / det;
	T = orygin - v0;
	u = glm::dot(T, P) * inv_det;
	if (u < 0.0 || u > 1.0)
		return false;
	
	Q = glm::cross(T, E1);
	v = glm::dot(dir, Q) * inv_det;
	if (v < 0.0 || u + v > 1.0)
		return false;

	t = glm::dot(E2, Q) * inv_det;
#endif
	return true;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	glViewport(0, 0, width, height);
}

void processInput(GLFWwindow* window)
{
	static bool lkey = false;

	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);

	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
		camera.ProcessKeyboard(FORWARD, deltaTime);
	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
		camera.ProcessKeyboard(BACKWARD, deltaTime);
	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
		camera.ProcessKeyboard(LEFT, deltaTime);
	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
		camera.ProcessKeyboard(RIGHT, deltaTime);

	if (glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS && !lkey)
	{
		lkey = true;

		int polygonMode;
		glGetIntegerv(GL_POLYGON_MODE, &polygonMode);

		if (polygonMode == GL_LINE)
			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		if (polygonMode == GL_FILL)
			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	}
	else if (glfwGetKey(window, GLFW_KEY_R) == GLFW_RELEASE && lkey)
		lkey = false;
}

void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
	if (firstMouse)
	{
		lastX = xpos;
		lastY = ypos;
		firstMouse = false;
	}

	float xoffset = xpos - lastX;
	float yoffset = lastY - ypos;

	lastX = xpos;
	lastY = ypos;

	camera.ProcessMouseMovement(xoffset, yoffset);
}

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
	camera.ProcessMouseScroll(yoffset);
}

 

Zaloguj lub zarejestruj się, aby odpowiedzieć na to pytanie.

Podobne pytania

0 głosów
0 odpowiedzi 95 wizyt
pytanie zadane 10 sierpnia 2020 w OpenGL, Unity przez tonn204 Mądrala (7,440 p.)
0 głosów
0 odpowiedzi 235 wizyt

92,451 zapytań

141,261 odpowiedzi

319,073 komentarzy

61,853 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...