the perspective transform finally looks right

This commit is contained in:
Trammell hudson 2018-02-28 22:07:51 -05:00
parent 78de86f4a8
commit 8b8097253c
Failed to extract signature
4 changed files with 73 additions and 31 deletions

View File

@ -22,15 +22,14 @@ camera_new(
v3_t eye,
v3_t lookat,
v3_t up,
float fov,
float scale
float fov
)
{
camera_t * c = calloc(1, sizeof(*c));
if (!c)
return NULL;
camera_setup(c, eye, lookat, up, fov, scale);
camera_setup(c, eye, lookat, up, fov);
return c;
}
@ -41,8 +40,7 @@ camera_setup(
v3_t eye,
v3_t lookat,
v3_t up,
float fov,
float scale
float fov
)
{
// compute the basis for the camera
@ -62,9 +60,9 @@ camera_setup(
{ u.p[2], v.p[2], w.p[2], 0 },
{ -v3_dot(u,eye), -v3_dot(v,eye), -v3_dot(w,eye), 1 },
#else
{ u.p[0], u.p[1], u.p[2], -v3_dot(u,lookat) },
{ v.p[0], v.p[1], v.p[2], -v3_dot(v,lookat) },
{ w.p[0], w.p[1], w.p[2], -v3_dot(w,lookat) },
{ u.p[0], u.p[1], u.p[2], -v3_dot(u,eye) },
{ v.p[0], v.p[1], v.p[2], -v3_dot(v,eye) },
{ w.p[0], w.p[1], w.p[2], -v3_dot(w,eye) },
{ 0, 0, 0, 1 },
#endif
};
@ -80,7 +78,7 @@ camera_setup(
// now compute the perspective projection matrix
float s = 1.0 / tan(fov * M_PI / 180 / 2);
c->near = 1.0;
c->near = 4.0;
c->far = 20;
float f1 = - c->far / (c->far - c->near);
float f2 = - c->far * c->near / (c->far - c->near);
@ -142,17 +140,28 @@ camera_project(
for (int j = 0 ; j < 4 ; j++)
p[i] += c->r[i][j] * v[j];
if(1) fprintf(stderr, "%.2f %.2f %.2f -> %.2f %.2f %.2f %.2f\n",
// what if p->p[4] == 0?
// pz < 0 == The point is behind us; do not display?
//if (p[2] < c->near || p[2] > c->far)
if (p[2] < 0)
return 0;
p[0] /= p[3];
p[1] /= p[3];
/*
for (int i = 0 ; i < 3 ; i++)
p[i] /= p[3];
p[2] /= p[3];
*/
if(0) fprintf(stderr, "%.2f %.2f %.2f -> %.2f %.2f %.2f %.2f\n",
v[0], v[1], v[2],
p[0], p[1], p[2], p[3]
);
/*
for (int i = 0 ; i < 3 ; i++)
p[i] /= p[3];
p[0] *= -1;
p[1] *= -1;
p[2] /= p[3];
*/
@ -162,10 +171,6 @@ camera_project(
v_out->p[1] = p[1];
v_out->p[2] = p[2];
// what if p->p[4] == 0?
// pz < 0 == The point is behind us; do not display?
if (p[2] < c->near || p[2] > c->far)
return 0;
return 1;
}

View File

@ -9,8 +9,7 @@ camera_new(
v3_t eye,
v3_t lookat,
v3_t up,
float fov,
float scale
float fov
);
extern void
@ -19,8 +18,7 @@ camera_setup(
v3_t eye,
v3_t lookat,
v3_t up,
float fov,
float scale
float fov
);
/** Transform a XYZ point into a screen point.

View File

@ -768,8 +768,10 @@ int onscreen(
{
if (p->p[0] < -width/2 || width/2 < p->p[0])
return 0;
/*
if (p->p[1] < -height/2 || height/2 < p->p[1])
return 0;
*/
/*
if (p->p[0] < 0 || width < p->p[0])
return 0;
@ -868,7 +870,8 @@ int main(
}
const camera_t * const cam = camera_new(eye, lookat, up, fov, scale);
(void) scale;
const camera_t * const cam = camera_new(eye, lookat, up, fov);
printf("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"%.0fpx\" height=\"%.0fpx\" viewbox=\"0 0 %.0f %.0f\">\n", width, height, width, height);
@ -897,18 +900,27 @@ int main(
for(int j = 0 ; j < 3 ; j++)
{
camera_project(cam, &stl->p[j], &s[j]);
// if any points are behind us, reject
// this one
if (!camera_project(cam, &stl->p[j], &s[j]))
{
behind++;
goto reject_early;
}
}
if(debug >= 2)
fprintf(stderr, "%.3f,%.3f,%.3f -> %.1f,%.1f,%.1f\n",
stl->p[0].p[0],
stl->p[0].p[1],
stl->p[0].p[2],
s[0].p[0],
s[0].p[1],
s[0].p[2]
);
for(int j = 0 ; j < 3 ; j++)
{
fprintf(stderr, "%.3f %.3f %.3f -> %.3f %.3f %.3f\n",
stl->p[j].p[0],
stl->p[j].p[1],
stl->p[j].p[2],
s[j].p[0],
s[j].p[1],
s[j].p[2]
);
}
tri_t * const tri = tri_new(s, stl->p);
@ -962,6 +974,8 @@ tri_print(tri);
reject:
tri_delete(tri);
reject_early:
continue;
}
if (debug)

25
test.c Normal file
View File

@ -0,0 +1,25 @@
#include <stdio.h>
#include "camera.h"
#include "v3.h"
int main(void)
{
v3_t lookat = {{0,0,0}};
v3_t eye = {{0,-20,0}};
v3_t up = {{0,0,1}};
float fov = 20;
camera_t * camera = camera_new(eye, lookat, up, fov);
for (float x = -5 ; x <= 5 ; x += 5)
for (float y = -25 ; y < 55 ; y += 5 )
{
v3_t v_in = {{ x, y, 5 }};
v3_t v_out;
int onscreen = camera_project(camera, &v_in, &v_out);
if (!onscreen && y > eye.p[1])
fprintf(stderr, "false positive\n");
if (onscreen && y < eye.p[1])
fprintf(stderr, "false negative\n");
}
}