From a02f82c13ad2093599b0e9dc363ddab37359080f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 11 Jun 2013 12:07:17 +0200 Subject: [PATCH] First attempt at perspective correction We inverse the perspective transformation to interpolate the scanlines. The perspective is corrected but there are still precision problems (straight lines are deformed). --- src/rendering/camera.c | 9 +++++++++ src/rendering/camera.h | 1 + src/rendering/render.c | 11 ++++++----- src/testing/test_camera.c | 38 +++++++++++++++++++++++++++++++++++++- 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/rendering/camera.c b/src/rendering/camera.c index 3702eb9..1556f61 100644 --- a/src/rendering/camera.c +++ b/src/rendering/camera.c @@ -183,6 +183,15 @@ CameraPerspective cameraGetPerspective(CameraDefinition* camera) return camera->perspective; } +double cameraGetRealDepth(CameraDefinition* camera, Vector3 projected) +{ + /* TODO Optimize this */ + Matrix4 m = m4NewPerspective(camera->perspective.yfov, camera->perspective.xratio, camera->perspective.znear, camera->perspective.zfar); + projected.x = (projected.x / (0.5 * camera->width) - 1.0); + projected.y = -(projected.y / (0.5 * camera->height) - 1.0); + return m4Transform(m4Inverse(m), projected).z; +} + void cameraSetLocation(CameraDefinition* camera, Vector3 location) { camera->location = location; diff --git a/src/rendering/camera.h b/src/rendering/camera.h index a77967c..e5b5efc 100644 --- a/src/rendering/camera.h +++ b/src/rendering/camera.h @@ -35,6 +35,7 @@ Vector3 cameraGetDirection(CameraDefinition* camera); Vector3 cameraGetDirectionNormalized(CameraDefinition* camera); VectorSpherical cameraGetDirectionSpherical(CameraDefinition* camera); CameraPerspective cameraGetPerspective(CameraDefinition* camera); +double cameraGetRealDepth(CameraDefinition* camera, Vector3 projected); void cameraSetLocation(CameraDefinition* camera, Vector3 location); void cameraSetLocationCoords(CameraDefinition* camera, double x, double y, double z); diff --git a/src/rendering/render.c b/src/rendering/render.c index e044ba9..51210d2 100644 --- a/src/rendering/render.c +++ b/src/rendering/render.c @@ -5,6 +5,7 @@ #include #include "renderer.h" +#include "camera.h" #include "system.h" typedef struct @@ -381,10 +382,10 @@ static void _scanGetDiff(ScanPoint* v1, ScanPoint* v2, ScanPoint* result) result->callback = v1->callback; } -static void _scanInterpolate(ScanPoint* v1, ScanPoint* diff, double value, ScanPoint* result) +static void _scanInterpolate(CameraDefinition* camera, ScanPoint* v1, ScanPoint* diff, double value, ScanPoint* result) { - double v1depth = v1->pixel.z; - double v2depth = (v1->pixel.z + diff->pixel.z); + double v1depth = cameraGetRealDepth(camera, v1->pixel); + double v2depth = cameraGetRealDepth(camera, v3Add(v1->pixel, diff->pixel)); double factor = ((1.0 - value) / v1depth + value / v2depth); result->pixel.x = v1->pixel.x + diff->pixel.x * value; @@ -481,7 +482,7 @@ static void _pushScanLineEdge(RenderArea* area, ScanPoint* point1, ScanPoint* po fx = point2->pixel.x; } fx = fx - point1->pixel.x; - _scanInterpolate(point1, &diff, fx / dx, &point); + _scanInterpolate(area->renderer->render_camera, point1, &diff, fx / dx, &point); /*point.pixel.x = (double)curx;*/ @@ -539,7 +540,7 @@ static void _renderScanLines(RenderArea* area) fy = fy - down.pixel.y; current.y = cury; - _scanInterpolate(&down, &diff, fy / dy, ¤t); + _scanInterpolate(area->renderer->render_camera, &down, &diff, fy / dy, ¤t); _pushFragment(area, current.x, current.y, current.pixel.z, (cury == starty || cury == endy), current.location, current.callback); } diff --git a/src/testing/test_camera.c b/src/testing/test_camera.c index 6a8920a..0fc2143 100644 --- a/src/testing/test_camera.c +++ b/src/testing/test_camera.c @@ -17,5 +17,41 @@ START_TEST(test_camera_definition) } END_TEST -TEST_CASE(camera, test_camera_definition) +START_TEST(test_camera_projection) +{ + CameraDefinition* cam; + cam = cameraCreateDefinition(); + + cameraSetLocationCoords(cam, 0.0, 1.0, 1.0); + cameraSetTargetCoords(cam, 0.0, 0.0, 0.0); + + /* Test the reversibility of projection */ + Vector3 point = cameraProject(cam, v3(12.0, 5.2, -6.3)); + point = cameraUnproject(cam, point); + ck_assert_vector_values(point, 12.0, 5.2, -6.3); + + cameraDeleteDefinition(cam); +} +END_TEST + +START_TEST(test_camera_depth) +{ + CameraDefinition* cam; + cam = cameraCreateDefinition(); + + cameraSetLocationCoords(cam, 0.0, 0.0, 0.0); + cameraSetTargetCoords(cam, 1.0, 0.0, 0.0); + + /* Test the real depth getter */ + Vector3 point = cameraProject(cam, v3(12.5, 0.0, 0.0)); + ck_assert_double_eq(cameraGetRealDepth(cam, point), 12.5); + + cameraDeleteDefinition(cam); +} +END_TEST + +TEST_CASE(camera, + test_camera_definition, + test_camera_projection, + test_camera_depth)