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:
parent
1b890849a8
commit
a02f82c13a
4 changed files with 53 additions and 6 deletions
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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, ¤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);
|
_pushFragment(area, current.x, current.y, current.pixel.z, (cury == starty || cury == endy), current.location, current.callback);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue