~zjm/Moon3D

ref: 0fe31db4998f636b8f65ca790b75c0585ba47d86 Moon3D/src/3d/image/project.c -rw-r--r-- 3.4 KiB
0fe31db4Zack Michener refactor camera/projection to avoid globals 5 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include "project.h"
#include "../../arraylist.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include "camera.h"

static Transform *deviceTransform = NULL;

void InitDeviceTransform(unsigned int width, unsigned int height)
{
	// Move canonical volume to origin
	deviceTransform = malloc(sizeof(Transform));
	*deviceTransform = Translation(V(1, 1, 0));

	// Scale to viewport size
	Scale(deviceTransform, 0.5*(width-1), 0.5*(height-1), 1);
}

Projection *NewOrthoProjection(AABBox vol)
{
	Projection *projection = malloc(sizeof(Projection));

	projection->ortho.type = ORTHO;
	projection->ortho.near = vol.near;
	projection->ortho.far = vol.far;
	projection->ortho.left = vol.left;
	projection->ortho.right = vol.right;
	projection->ortho.bottom = vol.bottom;
	projection->ortho.top = vol.top;

	return projection;
}

Projection *NewPerspectiveProjection(double fov, double aspect, double near, double far)
/* field of view is in degrees */
{
	Projection *projection = malloc(sizeof(Projection));

	projection->perspective.type = PERSPECTIVE;
	projection->perspective.near = near;
	projection->perspective.far = far;
	projection->perspective.fov = Rad(fov);
	projection->perspective.aspect = aspect;

	return projection;
}

Transform OrthoTransform(Projection *projection)
{
	Transform t;

	assert(projection->ortho.type == ORTHO);

	t = Identity();

	// translate to canonical view volume
	Translate(&t, V(
			-(projection->ortho.right + projection->ortho.left) / 2,
			-(projection->ortho.top + projection->ortho.bottom) / 2,
			-projection->ortho.near));

	// scale to canonical view volume
	Scale(&t,
			2 / (projection->ortho.right - projection->ortho.left),
			2 / (projection->ortho.top - projection->ortho.bottom),
			1 / (projection->ortho.near - projection->ortho.far));

	return t;
}

Transform PerspectiveTransform(Projection *projection)
{
	Transform op, t;

	assert(projection->perspective.type == PERSPECTIVE);

	t = Identity();

	// perspective transform into canonical view volume
	op = Identity();
	op.m[0][0] = 1/(projection->perspective.aspect * tan(projection->perspective.fov/2));
	op.m[1][1] = 1/tan(projection->perspective.fov/2);
	op.m[2][2] = (projection->perspective.far + projection->perspective.near)
			/ (projection->perspective.far - projection->perspective.near);
	op.m[3][3] = 0;
	op.m[2][3] = (2*projection->perspective.far*projection->perspective.near)
			/ (projection->perspective.far - projection->perspective.near);
	op.m[3][2] = -1;
	AddTransform(op, &t);

	return t;
}

Transform CameraTransform(Camera *camera)
{
	Transform t = Translation(NegVec(camera->position));
	AddTransform(AlignCameraToAxis(camera), &t);
	AddTransform(camera->transform, &t);

	return t;
}

Transform GetProjectionTransform(Camera *camera, Projection *projection)
{
	Transform t = CameraTransform(camera);
	if (projection->ortho.type == ORTHO) {
		AddTransform(OrthoTransform(projection), &t);
	} else {
		AddTransform(PerspectiveTransform(projection), &t);
	}
	return t;
}

Vector ProjectPoint(Vertex p, Transform t)
{
	return ApplyTransform(t, p);
}

Vertex ViewmapPoint(Vertex p)
{
	assert(deviceTransform != NULL);
	return Homogenize(ApplyTransform(*deviceTransform, p));
}

Polygon *ProjectPolygon(Polygon *polygon, Transform t)
{
	return FromPolygon(polygon, t);
}

void ViewmapPolygon(Polygon *polygon)
{
	assert(deviceTransform != NULL);
	for (int i = 0; i < NumVertices(polygon); i++) {
		CommitTransform(*deviceTransform, PolygonVertex(polygon, i));
	}
}