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).
This commit is contained in:
Michaël Lemaire 2013-06-11 12:07:17 +02:00
parent 1b890849a8
commit a02f82c13a
4 changed files with 53 additions and 6 deletions

View file

@ -183,6 +183,15 @@ CameraPerspective cameraGetPerspective(CameraDefinition* camera)
return camera->perspective; 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) void cameraSetLocation(CameraDefinition* camera, Vector3 location)
{ {
camera->location = location; camera->location = location;

View file

@ -35,6 +35,7 @@ Vector3 cameraGetDirection(CameraDefinition* camera);
Vector3 cameraGetDirectionNormalized(CameraDefinition* camera); Vector3 cameraGetDirectionNormalized(CameraDefinition* camera);
VectorSpherical cameraGetDirectionSpherical(CameraDefinition* camera); VectorSpherical cameraGetDirectionSpherical(CameraDefinition* camera);
CameraPerspective cameraGetPerspective(CameraDefinition* camera); CameraPerspective cameraGetPerspective(CameraDefinition* camera);
double cameraGetRealDepth(CameraDefinition* camera, Vector3 projected);
void cameraSetLocation(CameraDefinition* camera, Vector3 location); void cameraSetLocation(CameraDefinition* camera, Vector3 location);
void cameraSetLocationCoords(CameraDefinition* camera, double x, double y, double z); void cameraSetLocationCoords(CameraDefinition* camera, double x, double y, double z);

View file

@ -5,6 +5,7 @@
#include <math.h> #include <math.h>
#include "renderer.h" #include "renderer.h"
#include "camera.h"
#include "system.h" #include "system.h"
typedef struct typedef struct
@ -381,10 +382,10 @@ static void _scanGetDiff(ScanPoint* v1, ScanPoint* v2, ScanPoint* result)
result->callback = v1->callback; 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 v1depth = cameraGetRealDepth(camera, v1->pixel);
double v2depth = (v1->pixel.z + diff->pixel.z); double v2depth = cameraGetRealDepth(camera, v3Add(v1->pixel, diff->pixel));
double factor = ((1.0 - value) / v1depth + value / v2depth); double factor = ((1.0 - value) / v1depth + value / v2depth);
result->pixel.x = v1->pixel.x + diff->pixel.x * value; 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 = point2->pixel.x;
} }
fx = fx - point1->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;*/ /*point.pixel.x = (double)curx;*/
@ -539,7 +540,7 @@ static void _renderScanLines(RenderArea* area)
fy = fy - down.pixel.y; fy = fy - down.pixel.y;
current.y = cury; current.y = cury;
_scanInterpolate(&down, &diff, fy / dy, &current); _scanInterpolate(area->renderer->render_camera, &down, &diff, fy / dy, &current);
_pushFragment(area, current.x, current.y, current.pixel.z, (cury == starty || cury == endy), current.location, current.callback); _pushFragment(area, current.x, current.y, current.pixel.z, (cury == starty || cury == endy), current.location, current.callback);
} }

View file

@ -17,5 +17,41 @@ START_TEST(test_camera_definition)
} }
END_TEST 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)