papercraft/camera.c

103 lines
1.7 KiB
C
Raw Normal View History

2017-09-27 03:37:22 +02:00
/** \file
* 3D camera equation.
*
* Given a camera matrix and a XYZ point, returns the 2D coordinate
* of the point.
*/
#include <stdio.h>
#include <stdlib.h>
#include "camera.h"
struct _camera_t
{
float zoom;
float eye_z;
float r[3][3];
};
camera_t *
camera_new(
float eye_z,
float phi,
float theta,
float psi
)
{
camera_t * c = calloc(1, sizeof(*c));
if (!c)
return NULL;
c->zoom = 1024;
camera_setup(c, eye_z, phi, theta, psi);
return c;
}
void
camera_setup(
camera_t * const c,
float eye_z,
float phi,
float theta,
float psi
)
{
const float sx = sin(phi);
const float cx = cos(phi);
const float sy = sin(theta);
const float cy = cos(theta);
const float sz = sin(psi);
const float cz = cos(psi);
c->r[0][0] = cy * cz;
c->r[0][1] = (-cy * sz) + (sx * sy * cz);
c->r[0][2] = ( sx * sz) + (cx * sy * cz);
c->r[1][0] = cx * sz;
c->r[1][1] = ( cx * cz) + (sx * sy * sz);
c->r[1][2] = (-sx * cz) + (cx * sy * sz);
c->r[2][0] = -sy;
c->r[2][1] = sx * cy;
c->r[2][2] = cx * cy;
c->eye_z = eye_z;
}
/** Transform a XYZ point into a screen point.
*
* Returns 0 if this is behind us. Perhaps it should do a z buffer?
*/
int
camera_project(
const camera_t * const c,
const v3_t * const v,
v3_t * const v_out
)
{
v3_t p = { .p = { 0, 0, c->eye_z } };
for (int i = 0 ; i < 3 ; i++)
for (int j = 0 ; j < 3 ; j++)
p.p[i] += c->r[i][j] * v->p[j];
// what if p->p[2] == 0?
// Transform to screen coordinate frame,
// is this rotating?
float px = p.p[1] / p.p[2];
float py = p.p[0] / p.p[2];
float pz = p.p[2];
// 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;
// pz < 0 == The point is behind us; do not display?
return pz <= 0 ? 0 : 1;
}