diff --git a/.attachments/fixed-raycast.png b/.attachments/fixed-raycast.png new file mode 100644 index 0000000..eacff4b Binary files /dev/null and b/.attachments/fixed-raycast.png differ diff --git a/README.md b/README.md index 660f799..f5d939e 100644 --- a/README.md +++ b/README.md @@ -35,3 +35,9 @@ Different voxel types are now supported in the data structures and passed to the When placing a block, the program now raycasts to place where the camera is looking. ![a place of brown dirt with word Hi built out of stone.](.attachments/raycasting_test.png) + +### 0.6.1 : Raycast Bug Fixes - 11/17/25 + +It took me a couple of days to fix the ray casting. I forgot that my mesh is offset by 0.5, so 3/4 raycasts looked at least a block off of what the camera was looking at. + +![Hello, written in blocks on a dirt plane](.attachments/fixed-raycast.png) diff --git a/run.ps1 b/run.ps1 new file mode 100644 index 0000000..508130d --- /dev/null +++ b/run.ps1 @@ -0,0 +1 @@ +.\build\Debug\VoxelEngine.exe \ No newline at end of file diff --git a/src/World.cpp b/src/World.cpp index 600220d..c66ff9f 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -74,7 +74,11 @@ std::optional> World::raycast_voxel(glm::vec3 // std::cout << "[RAYCAST] Start: (" << start.x << ", " << start.y << ", " << start.z << ")" << std::endl; // std::cout << "[RAYCAST] Direction: (" << direction.x << ", " << direction.y << ", " << direction.z << ")" << std::endl; - glm::ivec3 pos = glm::ivec3(std::floor(start.x), std::floor(start.y), std::floor(start.z)); + // Adjust start position to account for voxels being centered at integer + 0.5 + // (voxel at pos (0,0,0) occupies space from (-0.5,-0.5,-0.5) to (0.5,0.5,0.5)) + glm::vec3 adjusted_start = start + glm::vec3(0.5f, 0.5f, 0.5f); + + glm::ivec3 pos = glm::ivec3(std::floor(adjusted_start.x), std::floor(adjusted_start.y), std::floor(adjusted_start.z)); // std::cout << "[RAYCAST] Starting voxel: (" << pos.x << ", " << pos.y << ", " << pos.z << ")" << std::endl; // (+1, -1, or 0 for each axis) @@ -94,7 +98,7 @@ std::optional> World::raycast_voxel(glm::vec3 // Calculate t_max: distance along ray to next voxel boundary for each axis glm::vec3 t_max; - glm::vec3 fract = start - glm::vec3(pos); + glm::vec3 fract = adjusted_start - glm::vec3(pos); // For each axis, calculate distance to the next boundary if (step_dir.x > 0) diff --git a/src/main.cpp b/src/main.cpp index 3bf9911..51846a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,8 @@ unsigned int SCR_WIDTH = 1920; unsigned int SCR_HEIGHT = 1080; +const int EDIT_RANGE = 5; + // Jump const float JUMP_COOLDOWN = 0.0f; const float JUMP_POWER = 10.0f; // Initial Jump Speed @@ -96,12 +98,22 @@ void processInput(GLFWwindow *window) { float current_time = glfwGetTime(); + if (glfwGetKey(window, GLFW_KEY_P) == GLFW_PRESS) { + glm::vec3 eye = camera.getEyePosition(); + glm::mat4 view = camera.getView(); + glm::vec3 forward = -glm::vec3(view[0][2], view[1][2], view[2][2]); // Extract forward from view matrix + + std::cout << "Camera target (from pitch/yaw): (" << camera.target.x << ", " << camera.target.y << ", " << camera.target.z << ")" << std::endl; + std::cout << "Camera forward (from view matrix): (" << forward.x << ", " << forward.y << ", " << forward.z << ")" << std::endl; + std::cout << "Match: " << (glm::length(camera.target - forward) < 0.01f ? "YES" : "NO") << std::endl; + } + // Update targeted block every frame for highlight std::optional> raycast_result = - world.raycast_voxel(camera.getEyePosition(), camera.target, 5); + world.raycast_voxel(camera.getEyePosition(), camera.target, EDIT_RANGE); if (raycast_result.has_value()) { targeted_block = raycast_result.value().first; - + // Debug: print occasionally static int frame_count = 0; if (frame_count % 60 == 0) { @@ -203,10 +215,10 @@ void processInput(GLFWwindow *window) std::cout << "\n=== LEFT CLICK (PLACE) ===" << std::endl; std::cout << "Camera eye pos: (" << camera.getEyePosition().x << ", " << camera.getEyePosition().y << ", " << camera.getEyePosition().z << ")" << std::endl; std::cout << "Camera target: (" << camera.target.x << ", " << camera.target.y << ", " << camera.target.z << ")" << std::endl; - + std::optional> raycast_result = - world.raycast_voxel(camera.getEyePosition(), camera.target, 3); - + world.raycast_voxel(camera.getEyePosition(), camera.target, EDIT_RANGE); + if (raycast_result.has_value()) { auto [target_block, normal] = raycast_result.value(); std::cout << "Hit block at: (" << target_block.x << ", " << target_block.y << ", " << target_block.z << ")" << std::endl; @@ -228,10 +240,10 @@ void processInput(GLFWwindow *window) std::cout << "\n=== RIGHT CLICK (REMOVE) ===" << std::endl; std::cout << "Camera eye pos: (" << camera.getEyePosition().x << ", " << camera.getEyePosition().y << ", " << camera.getEyePosition().z << ")" << std::endl; std::cout << "Camera target: (" << camera.target.x << ", " << camera.target.y << ", " << camera.target.z << ")" << std::endl; - + std::optional> raycast_result = - world.raycast_voxel(camera.getEyePosition(), camera.target, 3); - + world.raycast_voxel(camera.getEyePosition(), camera.target, EDIT_RANGE); + if (raycast_result.has_value()) { auto [target_block, normal] = raycast_result.value(); std::cout << "Hit block at: (" << target_block.x << ", " << target_block.y << ", " << target_block.z << ")" << std::endl; @@ -257,7 +269,7 @@ int main() { glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 2. --- Create a Window --- - GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Voxel Engine 0.6.0", NULL, NULL); + GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Voxel Engine 0.6.1", NULL, NULL); if (window == NULL) { std::cerr << "Failed to create GLFW window" << std::endl; glfwTerminate(); @@ -299,10 +311,10 @@ int main() { unsigned int crosshairVAO, crosshairVBO; glGenVertexArrays(1, &crosshairVAO); glGenBuffers(1, &crosshairVBO); - + glBindVertexArray(crosshairVAO); glBindBuffer(GL_ARRAY_BUFFER, crosshairVBO); - + // Crosshair vertices in NDC (Normalized Device Coordinates: -1 to 1) float crosshairSize = 0.02f; // Size in NDC float crosshairVertices[] = { @@ -313,7 +325,7 @@ int main() { 0.0f, -crosshairSize, 0.0f, 0.0f, crosshairSize, 0.0f }; - + glBufferData(GL_ARRAY_BUFFER, sizeof(crosshairVertices), crosshairVertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); @@ -324,10 +336,10 @@ int main() { glGenVertexArrays(1, &highlightVAO); glGenBuffers(1, &highlightVBO); glGenBuffers(1, &highlightEBO); - + glBindVertexArray(highlightVAO); glBindBuffer(GL_ARRAY_BUFFER, highlightVBO); - + // Cube outline vertices (slightly larger than 1 unit cube for visibility) float offset = 0.001f; // Slight offset to prevent z-fighting float highlightVertices[] = { @@ -341,7 +353,7 @@ int main() { 0.5f + offset, 0.5f + offset, 0.5f + offset, // 6 -0.5f - offset, 0.5f + offset, 0.5f + offset // 7 }; - + // Indices for the 12 edges of the cube unsigned int highlightIndices[] = { // Bottom face @@ -351,11 +363,11 @@ int main() { // Vertical edges 0, 4, 1, 5, 2, 6, 3, 7 }; - + glBufferData(GL_ARRAY_BUFFER, sizeof(highlightVertices), highlightVertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); - + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, highlightEBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(highlightIndices), highlightIndices, GL_STATIC_DRAW); glBindVertexArray(0); @@ -364,7 +376,7 @@ int main() { unsigned int debugRayVAO, debugRayVBO; glGenVertexArrays(1, &debugRayVAO); glGenBuffers(1, &debugRayVBO); - + glBindVertexArray(debugRayVAO); glBindBuffer(GL_ARRAY_BUFFER, debugRayVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, nullptr, GL_DYNAMIC_DRAW); // 2 points * 3 coords @@ -490,39 +502,6 @@ int main() { glBindVertexArray(0); } - // ---- Draw Debug Ray ---- - { - shader.use(); - glm::vec3 ray_start = camera.getEyePosition(); - - static bool printed_debug = false; - - // Draw multiple small cubes along the ray path to make it visible - for (int i = 1; i <= 10; i++) { - float distance = i * 0.5f; - glm::vec3 point = ray_start + camera.target * distance; - - if (!printed_debug && i == 1) { - std::cout << "\n[DEBUG RAY]" << std::endl; - std::cout << "Ray start: (" << ray_start.x << ", " << ray_start.y << ", " << ray_start.z << ")" << std::endl; - std::cout << "Ray direction: (" << camera.target.x << ", " << camera.target.y << ", " << camera.target.z << ")" << std::endl; - std::cout << "First marker at: (" << point.x << ", " << point.y << ", " << point.z << ")" << std::endl; - printed_debug = true; - } - - glm::mat4 model = glm::mat4(1.0f); - model = glm::translate(model, point); - model = glm::scale(model, glm::vec3(0.1f)); // Small marker - glm::mat4 mvp = projection * view * model; - shader.setMat4("u_mvp", mvp); - shader.setVec3("u_Color", glm::vec3(1.0f, 0.0f, 0.0f)); // Red markers - - glBindVertexArray(highlightVAO); - glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, 0); - glBindVertexArray(0); - } - } - // ---- Draw Crosshair ---- glDisable(GL_DEPTH_TEST); // Draw on top of everything shader.use(); @@ -548,4 +527,4 @@ int main() { glfwTerminate(); // Clean up GLFW return 0; -} \ No newline at end of file +}