[CORE][FIX] Update terrain hitpoint precision

- change search method
- prevent outbound retrieving
This commit is contained in:
Linloir 2022-12-20 10:13:12 +08:00
parent 4cbc16e4c6
commit 14f7c8b33a
No known key found for this signature in database
GPG Key ID: 58EEB209A0F2C366
2 changed files with 69 additions and 20 deletions

View File

@ -2,7 +2,7 @@
#include <iostream> #include <iostream>
#define LOCALLOGLEVEL INFO #define LOCALLOGLEVEL DEBUG
class Logger { class Logger {
public: public:

View File

@ -6,6 +6,7 @@
#include "terrain.h" #include "terrain.h"
#include "utils.h" #include "utils.h"
#include "vertex.h" #include "vertex.h"
#include "logger.h"
Terrain::Terrain(std::string path){ Terrain::Terrain(std::string path){
// Convert '\ ' to '/' for Windows // Convert '\ ' to '/' for Windows
@ -137,14 +138,23 @@ void Terrain::render() {
} }
float Terrain::GetHeight(float px, float pz) { float Terrain::GetHeight(float px, float pz) {
float fx = px + height / 2; float fx = px + double(height) / 2;
float fz = pz + width / 2; float fz = pz + double(width) / 2;
int x = ((int)fx) % height; int x = ((int)fx) % height;
int z = ((int)fz) % width; int z = ((int)fz) % width;
int gx = (x + 1) % height; int gx = (x + 1) % height;
int gz = (z + 1) % width; int gz = (z + 1) % width;
// prevent retrieving out of bounds
if (x < 0) x = 0;
if (z < 0) z = 0;
if (gx < 0) gx = 0;
if (gz < 0) gz = 0;
if (x > height - 1) x = height - 1;
if (z > width - 1) z = width - 1;
if (gx > height - 1) gx = height - 1;
if (gz > width - 1) gz = width - 1;
float ans = (x - fx) * (Point[gx][gz] - Point[x][z]) + Point[x][z]; float ans = (x - fx) * (Point[gx][gz] - Point[x][z]) + Point[x][z];
//float ans = Point[x][z]; //float ans = Point[x][z];
@ -153,16 +163,34 @@ float Terrain::GetHeight(float px, float pz) {
} }
glm::vec3 Terrain::GetNormal(glm::vec3 pos) { glm::vec3 Terrain::GetNormal(glm::vec3 pos) {
float fx = pos.x; // construct a triangle with its geometry center at pos
float fz = pos.z; glm::vec3 p1 = pos + glm::vec3(-1.0f, 0.0f, -0.57735f);
glm::vec3 p2 = pos + glm::vec3(1.0f, 0.0f, -0.57735f);
glm::vec3 p3 = pos + glm::vec3(0.0f, 0.0f, 1.1547f);
glm::vec3 point1(fx - 1, GetHeight(fx - 1, fz - 1), fz - 1); // calculate the height
glm::vec3 point2(fx + 1, GetHeight(fx + 1, fz + 1), fz + 1); p1.y = GetHeight(p1.x, p1.z);
p2.y = GetHeight(p2.x, p2.z);
p3.y = GetHeight(p3.x, p3.z);
glm::vec3 l1 = pos - point1; // calculate the normal
glm::vec3 l2 = point2 - point1; glm::vec3 v1 = p2 - p1;
glm::vec3 ans = glm::normalize(glm::cross(l1, l2)); glm::vec3 v2 = p3 - p1;
return ans; glm::vec3 normal = glm::normalize(glm::cross(v1, v2));
// make the normal point up
if (normal.y < 0.0f) {
normal = -normal;
}
//glm::vec3 point1(fx - 1, GetHeight(fx - 1, fz - 1), fz - 1);
//glm::vec3 point2(fx + 1, GetHeight(fx + 1, fz + 1), fz + 1);
//glm::vec3 l1 = pos - point1;
//glm::vec3 l2 = point2 - point1;
//glm::vec3 ans = glm::normalize(glm::cross(l1, l2));
return normal;
} }
HitRecord Terrain::hit(const Ray& ray) { HitRecord Terrain::hit(const Ray& ray) {
@ -193,17 +221,38 @@ HitRecord Terrain::hit(const Ray& ray) {
glm::vec3 startPosition = lastRayPosition; glm::vec3 startPosition = lastRayPosition;
glm::vec3 endPosition = orig; glm::vec3 endPosition = orig;
// Binary search with 32 steps. Try to find the exact collision point // Binary search with 64 steps. Try to find the exact collision point
for (int i = 0; i < 32; i++) float threshold = 0.1f;
{ glm::vec3 mid;
// Binary search pass while(true) {
glm::vec3 middlePoint = (startPosition + endPosition) * 0.5f; mid = (startPosition + endPosition) * 0.5f;
if (middlePoint.y < height) map_height = GetHeight(mid.x, mid.z);
endPosition = middlePoint; if (abs(mid.y - map_height) < threshold) {
break;
}
else if (mid.y - endPosition.y < 0.001f) {
// if no more space to search, return
break;
}
Logger::debug("Current height difference: " + std::to_string(abs(mid.y - map_height)));
if (mid.y > map_height)
{
startPosition = mid;
}
else else
startPosition = middlePoint; {
endPosition = mid;
}
} }
glm::vec3 position = (startPosition + endPosition) * 0.5f; //{
// // Binary search pass
// glm::vec3 middlePoint = (startPosition + endPosition) * 0.5f;
// if (middlePoint.y < height)
// endPosition = middlePoint;
// else
// startPosition = middlePoint;
//}
glm::vec3 position = mid;
glm::vec3 normal = GetNormal(position); glm::vec3 normal = GetNormal(position);
// If t > 200, consider the ray as not hitted // If t > 200, consider the ray as not hitted