Merged perspective_correction into master
This commit is contained in:
commit
b793259554
10 changed files with 153 additions and 48 deletions
|
@ -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;
|
||||
|
@ -300,6 +309,11 @@ Vector3 cameraUnproject(CameraDefinition* camera, Vector3 point)
|
|||
{
|
||||
point.x = (point.x / (0.5 * camera->width) - 1.0);
|
||||
point.y = -(point.y / (0.5 * camera->height) - 1.0);
|
||||
if (point.z < 1.0)
|
||||
{
|
||||
point.x = -point.x;
|
||||
point.y = -point.y;
|
||||
}
|
||||
return m4Transform(camera->unproject, point);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <math.h>
|
||||
|
||||
#include "renderer.h"
|
||||
#include "camera.h"
|
||||
#include "system.h"
|
||||
|
||||
typedef struct
|
||||
|
@ -45,6 +46,7 @@ typedef struct
|
|||
struct RenderArea
|
||||
{
|
||||
ColorProfile* hdr_mapping;
|
||||
Renderer* renderer;
|
||||
RenderParams params;
|
||||
int pixel_count;
|
||||
int pixel_done;
|
||||
|
@ -77,7 +79,6 @@ typedef struct {
|
|||
int pixel_done;
|
||||
Thread* thread;
|
||||
RenderArea* area;
|
||||
Renderer* renderer;
|
||||
} RenderChunk;
|
||||
|
||||
#define RENDER_INVERSE 1
|
||||
|
@ -94,11 +95,12 @@ void renderQuit()
|
|||
{
|
||||
}
|
||||
|
||||
RenderArea* renderCreateArea()
|
||||
RenderArea* renderCreateArea(Renderer* renderer)
|
||||
{
|
||||
RenderArea* result;
|
||||
|
||||
result = malloc(sizeof(RenderArea));
|
||||
result->renderer = renderer;
|
||||
result->hdr_mapping = colorProfileCreate();
|
||||
result->params.width = 1;
|
||||
result->params.height = 1;
|
||||
|
@ -380,14 +382,18 @@ 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 = 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;
|
||||
result->pixel.y = v1->pixel.y + diff->pixel.y * value;
|
||||
result->pixel.z = v1->pixel.z + diff->pixel.z * value;
|
||||
result->location.x = v1->location.x + diff->location.x * value;
|
||||
result->location.y = v1->location.y + diff->location.y * value;
|
||||
result->location.z = v1->location.z + diff->location.z * value;
|
||||
result->location.x = ((1.0 - value) * (v1->location.x / v1depth) + value * (v1->location.x + diff->location.x) / v2depth) / factor;
|
||||
result->location.y = ((1.0 - value) * (v1->location.y / v1depth) + value * (v1->location.y + diff->location.y) / v2depth) / factor;
|
||||
result->location.z = ((1.0 - value) * (v1->location.z / v1depth) + value * (v1->location.z + diff->location.z) / v2depth) / factor;
|
||||
result->callback = v1->callback;
|
||||
}
|
||||
|
||||
|
@ -476,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;*/
|
||||
|
||||
|
@ -534,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);
|
||||
}
|
||||
|
@ -601,7 +607,7 @@ void* _renderPostProcessChunk(void* data)
|
|||
callback = chunk->area->fragment_callbacks[fragment->flags.callback];
|
||||
if (callback.function)
|
||||
{
|
||||
col = callback.function(chunk->renderer, fragment->data.location, callback.data);
|
||||
col = callback.function(chunk->area->renderer, fragment->data.location, callback.data);
|
||||
/*colorNormalize(&col);*/
|
||||
}
|
||||
else
|
||||
|
@ -631,7 +637,7 @@ void* _renderPostProcessChunk(void* data)
|
|||
}
|
||||
|
||||
#define MAX_CHUNKS 8
|
||||
void renderPostProcess(RenderArea* area, Renderer* renderer, int nbchunks)
|
||||
void renderPostProcess(RenderArea* area, int nbchunks)
|
||||
{
|
||||
volatile RenderChunk chunks[MAX_CHUNKS];
|
||||
int i;
|
||||
|
@ -659,12 +665,11 @@ void renderPostProcess(RenderArea* area, Renderer* renderer, int nbchunks)
|
|||
{
|
||||
chunks[i].thread = NULL;
|
||||
chunks[i].area = area;
|
||||
chunks[i].renderer = renderer;
|
||||
}
|
||||
|
||||
running = 0;
|
||||
loops = 0;
|
||||
while ((y < ny && !renderer->render_interrupt) || running > 0)
|
||||
while ((y < ny && !area->renderer->render_interrupt) || running > 0)
|
||||
{
|
||||
timeSleepMs(100);
|
||||
|
||||
|
@ -678,13 +683,13 @@ void renderPostProcess(RenderArea* area, Renderer* renderer, int nbchunks)
|
|||
chunks[i].thread = NULL;
|
||||
running--;
|
||||
}
|
||||
else if (renderer->render_interrupt)
|
||||
else if (area->renderer->render_interrupt)
|
||||
{
|
||||
chunks[i].interrupt = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (y < ny && !chunks[i].thread && !renderer->render_interrupt)
|
||||
if (y < ny && !chunks[i].thread && !area->renderer->render_interrupt)
|
||||
{
|
||||
chunks[i].finished = 0;
|
||||
chunks[i].interrupt = 0;
|
||||
|
|
|
@ -28,7 +28,7 @@ typedef struct
|
|||
void renderInit();
|
||||
void renderQuit();
|
||||
|
||||
RenderArea* renderCreateArea();
|
||||
RenderArea* renderCreateArea(Renderer* renderer);
|
||||
void renderDeleteArea(RenderArea* area);
|
||||
|
||||
void renderSetParams(RenderArea* area, RenderParams params);
|
||||
|
@ -39,7 +39,7 @@ void renderUpdate(RenderArea* area);
|
|||
|
||||
void renderPushTriangle(RenderArea* area, Vector3 pixel1, Vector3 pixel2, Vector3 pixel3, Vector3 location1, Vector3 location2, Vector3 location3, f_RenderFragmentCallback callback, void* callback_data);
|
||||
|
||||
void renderPostProcess(RenderArea* area, Renderer* renderer, int nbchunks);
|
||||
void renderPostProcess(RenderArea* area, int nbchunks);
|
||||
int renderSaveToFile(RenderArea* area, const char* path);
|
||||
void renderSetPreviewCallbacks(RenderArea* area, RenderCallbackStart start, RenderCallbackDraw draw, RenderCallbackUpdate update);
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ static Vector3 _getCameraDirection(Renderer* renderer, Vector3 target)
|
|||
|
||||
static double _getPrecision(Renderer* renderer, Vector3 location)
|
||||
{
|
||||
|
||||
UNUSED(renderer);
|
||||
UNUSED(location);
|
||||
return 0.0;
|
||||
|
@ -48,21 +47,16 @@ static double _getPrecision(Renderer* renderer, Vector3 location)
|
|||
|
||||
static Vector3 _projectPoint(Renderer* renderer, Vector3 point)
|
||||
{
|
||||
|
||||
UNUSED(renderer);
|
||||
return point;
|
||||
return cameraProject(renderer->render_camera, point);
|
||||
}
|
||||
|
||||
static Vector3 _unprojectPoint(Renderer* renderer, Vector3 point)
|
||||
{
|
||||
|
||||
UNUSED(renderer);
|
||||
return point;
|
||||
return cameraUnproject(renderer->render_camera, point);
|
||||
}
|
||||
|
||||
static void _pushTriangle(Renderer* renderer, Vector3 v1, Vector3 v2, Vector3 v3, f_RenderFragmentCallback callback, void* callback_data)
|
||||
{
|
||||
|
||||
Vector3 p1, p2, p3;
|
||||
|
||||
p1 = renderer->projectPoint(renderer, v1);
|
||||
|
@ -74,14 +68,12 @@ static void _pushTriangle(Renderer* renderer, Vector3 v1, Vector3 v2, Vector3 v3
|
|||
|
||||
static void _pushQuad(Renderer* renderer, Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, f_RenderFragmentCallback callback, void* callback_data)
|
||||
{
|
||||
|
||||
renderer->pushTriangle(renderer, v2, v3, v1, callback, callback_data);
|
||||
renderer->pushTriangle(renderer, v4, v1, v3, callback, callback_data);
|
||||
}
|
||||
|
||||
static void _pushDisplacedTriangle(Renderer* renderer, Vector3 v1, Vector3 v2, Vector3 v3, Vector3 ov1, Vector3 ov2, Vector3 ov3, f_RenderFragmentCallback callback, void* callback_data)
|
||||
{
|
||||
|
||||
Vector3 p1, p2, p3;
|
||||
|
||||
p1 = renderer->projectPoint(renderer, v1);
|
||||
|
@ -93,20 +85,17 @@ static void _pushDisplacedTriangle(Renderer* renderer, Vector3 v1, Vector3 v2, V
|
|||
|
||||
static void _pushDisplacedQuad(Renderer* renderer, Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, Vector3 ov1, Vector3 ov2, Vector3 ov3, Vector3 ov4, f_RenderFragmentCallback callback, void* callback_data)
|
||||
{
|
||||
|
||||
renderer->pushDisplacedTriangle(renderer, v2, v3, v1, ov2, ov3, ov1, callback, callback_data);
|
||||
renderer->pushDisplacedTriangle(renderer, v4, v1, v3, ov4, ov1, ov3, callback, callback_data);
|
||||
}
|
||||
|
||||
static RayCastingResult _rayWalking(Renderer* renderer, Vector3 location, Vector3 direction, int terrain, int water, int sky, int clouds)
|
||||
{
|
||||
|
||||
return _RAYCASTING_NULL;
|
||||
}
|
||||
|
||||
static Color _applyLightingToSurface(Renderer* renderer, Vector3 location, Vector3 normal, SurfaceMaterial* material)
|
||||
{
|
||||
|
||||
LightStatus* light = lightingCreateStatus(renderer->lighting, location, renderer->getCameraLocation(renderer, location));
|
||||
renderer->atmosphere->getLightingStatus(renderer, light, normal, 0);
|
||||
Color result = lightingApplyStatus(light, normal, material);
|
||||
|
@ -116,7 +105,6 @@ static Color _applyLightingToSurface(Renderer* renderer, Vector3 location, Vecto
|
|||
|
||||
static Color _applyMediumTraversal(Renderer* renderer, Vector3 location, Color color)
|
||||
{
|
||||
|
||||
color = renderer->atmosphere->applyAerialPerspective(renderer, location, color).final;
|
||||
color = renderer->clouds->getColor(renderer, color, renderer->getCameraLocation(renderer, location), location);
|
||||
return color;
|
||||
|
@ -124,7 +112,6 @@ static Color _applyMediumTraversal(Renderer* renderer, Vector3 location, Color c
|
|||
|
||||
Renderer* rendererCreate()
|
||||
{
|
||||
|
||||
Renderer* result = malloc(sizeof (Renderer));
|
||||
RenderParams params = {1, 1, 1, 5};
|
||||
|
||||
|
@ -135,7 +122,7 @@ Renderer* rendererCreate()
|
|||
result->render_progress = 0.0;
|
||||
result->is_rendering = 0;
|
||||
result->render_camera = cameraCreateDefinition();
|
||||
result->render_area = renderCreateArea();
|
||||
result->render_area = renderCreateArea(result);
|
||||
|
||||
renderSetParams(result->render_area, params);
|
||||
|
||||
|
@ -168,7 +155,6 @@ Renderer* rendererCreate()
|
|||
|
||||
void rendererDelete(Renderer* renderer)
|
||||
{
|
||||
|
||||
cameraDeleteDefinition(renderer->render_camera);
|
||||
lightingManagerDelete(renderer->lighting);
|
||||
|
||||
|
@ -185,7 +171,6 @@ void rendererDelete(Renderer* renderer)
|
|||
|
||||
void rendererSetPreviewCallbacks(Renderer* renderer, RenderCallbackStart start, RenderCallbackDraw draw, RenderCallbackUpdate update)
|
||||
{
|
||||
|
||||
renderSetPreviewCallbacks(renderer->render_area, start, draw, update);
|
||||
}
|
||||
|
||||
|
@ -228,7 +213,7 @@ void rendererStart(Renderer* renderer, RenderParams params)
|
|||
threadJoin(thread);
|
||||
|
||||
renderer->is_rendering = 1;
|
||||
renderPostProcess(renderer->render_area, renderer, core_count);
|
||||
renderPostProcess(renderer->render_area, core_count);
|
||||
renderer->is_rendering = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -186,16 +186,6 @@ static RayCastingResult _rayWalking(Renderer* renderer, Vector3 location, Vector
|
|||
return result;
|
||||
}
|
||||
|
||||
static Vector3 _projectPoint(Renderer* renderer, Vector3 point)
|
||||
{
|
||||
return cameraProject(renderer->render_camera, point);
|
||||
}
|
||||
|
||||
static Vector3 _unprojectPoint(Renderer* renderer, Vector3 point)
|
||||
{
|
||||
return cameraUnproject(renderer->render_camera, point);
|
||||
}
|
||||
|
||||
static double _getPrecision(Renderer* renderer, Vector3 location)
|
||||
{
|
||||
Vector3 projected;
|
||||
|
@ -216,8 +206,6 @@ Renderer* sceneryCreateStandardRenderer()
|
|||
cameraCopyDefinition(_camera, result->render_camera);
|
||||
|
||||
result->rayWalking = _rayWalking;
|
||||
result->projectPoint = _projectPoint;
|
||||
result->unprojectPoint = _unprojectPoint;
|
||||
result->getPrecision = _getPrecision;
|
||||
|
||||
sceneryBindRenderer(result);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
extern int tests_cpu_count;
|
||||
|
||||
static inline void _add_methods_to_case(TCase* tc, ...)
|
||||
{
|
||||
void* method;
|
||||
|
|
|
@ -2,10 +2,13 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "rendering/main.h"
|
||||
#include "rendering/system.h"
|
||||
|
||||
int tests_cpu_count;
|
||||
extern void test_euclid_case(Suite* s);
|
||||
extern void test_camera_case(Suite* s);
|
||||
extern void test_clouds_case(Suite* s);
|
||||
extern void test_render_case(Suite* s);
|
||||
extern void test_noise_case(Suite* s);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
|
@ -15,10 +18,13 @@ int main(int argc, char** argv)
|
|||
|
||||
paysagesInit();
|
||||
|
||||
tests_cpu_count = systemGetCoreCount();
|
||||
|
||||
/* TODO Find a way to automate this */
|
||||
test_euclid_case(s);
|
||||
test_camera_case(s);
|
||||
test_clouds_case(s);
|
||||
test_render_case(s);
|
||||
test_noise_case(s);
|
||||
|
||||
SRunner *sr = srunner_create(s);
|
||||
|
|
|
@ -17,5 +17,48 @@ 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);
|
||||
point = cameraProject(cam, v3(-25.1, 8.3, 1.3));
|
||||
point = cameraUnproject(cam, point);
|
||||
ck_assert_vector_values(point, -25.1, 8.3, 1.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);
|
||||
point = cameraProject(cam, v3(12.5, 8.0, -3.0));
|
||||
ck_assert_double_eq(cameraGetRealDepth(cam, point), 12.5);
|
||||
point = cameraProject(cam, v3(12.5, 12.0, 58.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)
|
||||
|
||||
|
|
61
src/testing/test_render.c
Normal file
61
src/testing/test_render.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
#include "testing/common.h"
|
||||
|
||||
#include <math.h>
|
||||
#include "rendering/renderer.h"
|
||||
#include "rendering/tools.h"
|
||||
|
||||
static Color _postProcessFragment(Renderer* renderer, Vector3 location, void* data)
|
||||
{
|
||||
UNUSED(renderer);
|
||||
UNUSED(data);
|
||||
|
||||
/* Checker-board */
|
||||
double x = fmod(location.x, 0.2);
|
||||
double z = fmod(location.z, 0.2);
|
||||
if (x < 0.0)
|
||||
{
|
||||
x = 0.2 + x;
|
||||
}
|
||||
if (z < 0.0)
|
||||
{
|
||||
z = 0.2 + z;
|
||||
}
|
||||
if ((x > 0.1) ^ (z > 0.1))
|
||||
{
|
||||
return COLOR_WHITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return COLOR_BLACK;
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(test_render_quad)
|
||||
{
|
||||
Renderer* renderer = rendererCreate();
|
||||
|
||||
renderer->render_width = 800;
|
||||
renderer->render_height = 600;
|
||||
renderer->render_quality = 1;
|
||||
|
||||
cameraSetLocationCoords(renderer->render_camera, 0.0, 0.5, 2.0);
|
||||
cameraSetTargetCoords(renderer->render_camera, 0.0, 0.5, 0.0);
|
||||
cameraSetRenderSize(renderer->render_camera, renderer->render_width, renderer->render_height);
|
||||
|
||||
RenderParams params = {renderer->render_width, renderer->render_height, 1, 1};
|
||||
renderSetParams(renderer->render_area, params);
|
||||
|
||||
renderSetBackgroundColor(renderer->render_area, &COLOR_BLUE);
|
||||
renderClear(renderer->render_area);
|
||||
|
||||
renderer->pushQuad(renderer, v3(-1.0, 0.0, 1.0), v3(-1.0, 0.0, -1.0), v3(1.0, 0.0, -1.0), v3(1.0, 0.0, 1.0), _postProcessFragment, NULL);
|
||||
renderPostProcess(renderer->render_area, tests_cpu_count);
|
||||
|
||||
renderSaveToFile(renderer->render_area, "./output/test_render_quad.png");
|
||||
|
||||
rendererDelete(renderer);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
TEST_CASE(render, test_render_quad)
|
||||
|
Loading…
Reference in a new issue