proper lookat and perspective matrix
This commit is contained in:
parent
7391a667fe
commit
060a4d472d
144
camera.c
144
camera.c
@ -11,26 +11,24 @@
|
|||||||
|
|
||||||
struct _camera_t
|
struct _camera_t
|
||||||
{
|
{
|
||||||
float zoom;
|
float near;
|
||||||
v3_t eye;
|
float far;
|
||||||
float r[3][3];
|
float r[4][4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
camera_t *
|
camera_t *
|
||||||
camera_new(
|
camera_new(
|
||||||
v3_t eye,
|
v3_t eye,
|
||||||
float phi,
|
v3_t lookat,
|
||||||
float theta,
|
v3_t up
|
||||||
float psi
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
camera_t * c = calloc(1, sizeof(*c));
|
camera_t * c = calloc(1, sizeof(*c));
|
||||||
if (!c)
|
if (!c)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
c->zoom = 4096;
|
camera_setup(c, eye, lookat, up);
|
||||||
camera_setup(c, eye, phi, theta, psi);
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,64 +37,126 @@ void
|
|||||||
camera_setup(
|
camera_setup(
|
||||||
camera_t * const c,
|
camera_t * const c,
|
||||||
v3_t eye,
|
v3_t eye,
|
||||||
float phi,
|
v3_t lookat,
|
||||||
float theta,
|
v3_t up
|
||||||
float psi
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const float sx = sin(phi);
|
// compute the basis for the camera
|
||||||
const float cx = cos(phi);
|
// negative look direction from eye to destination
|
||||||
const float sy = sin(theta);
|
v3_t w = v3_norm(v3_sub(eye, lookat));
|
||||||
const float cy = cos(theta);
|
|
||||||
const float sz = sin(psi);
|
|
||||||
const float cz = cos(psi);
|
|
||||||
|
|
||||||
c->r[0][0] = cy * cz;
|
// compute the side axis
|
||||||
c->r[0][1] = (-cy * sz) + (sx * sy * cz);
|
v3_t u = v3_norm(v3_cross(up, w));
|
||||||
c->r[0][2] = ( sx * sz) + (cx * sy * cz);
|
|
||||||
|
|
||||||
c->r[1][0] = cx * sz;
|
// and the "up" normal
|
||||||
c->r[1][1] = ( cx * cz) + (sx * sy * sz);
|
v3_t v = v3_norm(v3_cross(w, u));
|
||||||
c->r[1][2] = (-sx * cz) + (cx * sy * sz);
|
|
||||||
|
|
||||||
c->r[2][0] = -sy;
|
float cam[4][4] = {};
|
||||||
c->r[2][1] = sx * cy;
|
|
||||||
c->r[2][2] = cx * cy;
|
|
||||||
|
|
||||||
c->eye = eye;
|
cam[0][0] = u.p[0];
|
||||||
|
cam[1][0] = u.p[1];
|
||||||
|
cam[2][0] = u.p[2];
|
||||||
|
cam[3][0] = 0;
|
||||||
|
|
||||||
|
cam[0][1] = v.p[0];
|
||||||
|
cam[1][1] = v.p[1];
|
||||||
|
cam[2][1] = v.p[2];
|
||||||
|
cam[3][1] = 0;
|
||||||
|
|
||||||
|
cam[0][2] = w.p[0];
|
||||||
|
cam[1][2] = w.p[1];
|
||||||
|
cam[2][2] = w.p[2];
|
||||||
|
cam[3][2] = 0;
|
||||||
|
|
||||||
|
// compute u dot c, v dot c, w, dot c
|
||||||
|
cam[0][3] = -v3_dot(lookat, u);
|
||||||
|
cam[1][3] = -v3_dot(lookat, v);
|
||||||
|
cam[2][3] = -v3_dot(lookat, w);
|
||||||
|
cam[3][3] = 1;
|
||||||
|
|
||||||
|
for(int i = 0 ; i < 4 ; i++)
|
||||||
|
{
|
||||||
|
for(int j = 0 ; j < 4 ; j++)
|
||||||
|
fprintf(stderr, " %+5.3f", cam[i][j]);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// now compute the perspective projection matrix
|
||||||
|
float fov = 60;
|
||||||
|
float s = 1.0 / tan(fov * M_PI / 180 / 2);
|
||||||
|
c->near = 1.0;
|
||||||
|
c->far = 200;
|
||||||
|
float f1 = - c->far * (c->far - c->near);
|
||||||
|
float f2 = - c->far * c->near / (c->far - c->near);
|
||||||
|
|
||||||
|
float pers[4][4] = {
|
||||||
|
{ s, 0, 0, 0 },
|
||||||
|
{ 0, s, 0, 0 },
|
||||||
|
{ 0, 0, f1, -1 },
|
||||||
|
{ 0, 0, f2, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
// and apply it to the camera matrix to generate transform
|
||||||
|
for(int i = 0 ; i < 4 ; i++)
|
||||||
|
{
|
||||||
|
for(int j = 0 ; j < 4 ; j++)
|
||||||
|
{
|
||||||
|
float d = 0;
|
||||||
|
for(int k = 0 ; k < 4 ; k++)
|
||||||
|
d += cam[i][k] * pers[k][j];
|
||||||
|
c->r[i][j] = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int i = 0 ; i < 4 ; i++)
|
||||||
|
{
|
||||||
|
for(int j = 0 ; j < 4 ; j++)
|
||||||
|
fprintf(stderr, " %+5.3f", c->r[i][j]);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Transform a XYZ point into a screen point.
|
/** Transform a XYZ point into a screen point.
|
||||||
*
|
*
|
||||||
* Returns 0 if this is behind us. Perhaps it should do a z buffer?
|
* Returns 0 if this is behind us. Perhaps it should do a z buffer?
|
||||||
|
* https://en.wikipedia.org/wiki/3D_projection
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
camera_project(
|
camera_project(
|
||||||
const camera_t * const c,
|
const camera_t * const c,
|
||||||
const v3_t * const v,
|
const v3_t * const v_in,
|
||||||
v3_t * const v_out
|
v3_t * const v_out
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
v3_t p = c->eye;
|
float v[4] = { v_in->p[0], v_in->p[1], v_in->p[2], 1 };
|
||||||
|
float p[4] = { 0, 0, 0, 0};
|
||||||
|
|
||||||
|
for (int i = 0 ; i < 4 ; i++)
|
||||||
|
for (int j = 0 ; j < 4 ; j++)
|
||||||
|
p[i] += c->r[j][i] * v[j];
|
||||||
|
|
||||||
|
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++)
|
for (int i = 0 ; i < 3 ; i++)
|
||||||
for (int j = 0 ; j < 3 ; j++)
|
p[i] /= p[3];
|
||||||
p.p[i] += c->r[i][j] * v->p[j];
|
*/
|
||||||
|
p[2] /= p[3];
|
||||||
|
|
||||||
// what if p->p[2] == 0?
|
|
||||||
|
|
||||||
// Transform to screen coordinate frame,
|
// Transform to screen coordinate frame,
|
||||||
// is this rotating?
|
// and return it to the caller
|
||||||
float px = p.p[1] / p.p[2];
|
v_out->p[0] = p[0] * 100;
|
||||||
float py = p.p[0] / p.p[2];
|
v_out->p[1] = p[1] * 100;
|
||||||
float pz = p.p[2] / c->zoom;
|
v_out->p[2] = p[2] * 100;
|
||||||
|
|
||||||
// return it to the caller
|
|
||||||
v_out->p[0] = px * c->zoom;
|
|
||||||
v_out->p[1] = py * c->zoom;
|
|
||||||
v_out->p[2] = pz * c->zoom;
|
|
||||||
|
|
||||||
|
// what if p->p[4] == 0?
|
||||||
// pz < 0 == The point is behind us; do not display?
|
// pz < 0 == The point is behind us; do not display?
|
||||||
return pz <= 0 ? 0 : 1;
|
if (p[2] < c->near || p[2] > c->far)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
10
camera.h
10
camera.h
@ -7,18 +7,16 @@ typedef struct _camera_t camera_t;
|
|||||||
extern camera_t *
|
extern camera_t *
|
||||||
camera_new(
|
camera_new(
|
||||||
v3_t eye,
|
v3_t eye,
|
||||||
float phi,
|
v3_t lookat,
|
||||||
float theta,
|
v3_t up
|
||||||
float psi
|
|
||||||
);
|
);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
camera_setup(
|
camera_setup(
|
||||||
camera_t * const c,
|
camera_t * const c,
|
||||||
v3_t eye,
|
v3_t eye,
|
||||||
float phi,
|
v3_t lookat,
|
||||||
float theta,
|
v3_t up
|
||||||
float psi
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Transform a XYZ point into a screen point.
|
/** Transform a XYZ point into a screen point.
|
||||||
|
@ -669,9 +669,9 @@ int main(
|
|||||||
|
|
||||||
|
|
||||||
// looking at (0,0,0)
|
// looking at (0,0,0)
|
||||||
v3_t eye = { { 100, 20, 50 } };
|
v3_t eye = { { -100, 40, 50 } };
|
||||||
v3_t lookat = { { 0, 0, 0 } };
|
v3_t lookat = { { 0, 0, 0 } };
|
||||||
v3_t up = { { 0, 0, 1 } };
|
v3_t up = { { 0, -1, 0 } };
|
||||||
const camera_t * const cam = camera_new(eye, lookat, up);
|
const camera_t * const cam = camera_new(eye, lookat, up);
|
||||||
|
|
||||||
printf("<svg xmlns=\"http://www.w3.org/2000/svg\">\n");
|
printf("<svg xmlns=\"http://www.w3.org/2000/svg\">\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user