~zjm/Moon3D

ref: 0e81b821a0782674dbed435a58ad682e7aef0282 Moon3D/src/3d/image/project.c -rw-r--r-- 3.1 KiB
0e81b821Zack Michener wrap rendering objects in a RenderingContext struct 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
#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;
static AABBox *orthoVolume = NULL;
static Perspective *perspective = NULL;
static ProjectionMode mode = ORTHO;

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);
}

void SetOrtho(AABBox vol)
{
	if (orthoVolume != NULL) {
		free(orthoVolume);
	}
	orthoVolume = FromAABBox(&vol, Identity());
	mode = ORTHO;
}

void SetPerspective(double fov, double aspect, double near, double far)
/* field of view is in degrees */
{
	if (perspective != NULL) {
		free(perspective);
	}
	perspective = malloc(sizeof(Perspective));
	perspective->fov = Rad(fov);
	perspective->aspect = aspect;
	perspective->near = near;
	perspective->far = far;
	mode = PERSPECTIVE;
}

Transform OrthoProjection(void)
{
	Transform projection;

	assert(orthoVolume != NULL);

	projection = CameraTransform();

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

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

	return projection;
}

Transform PerspectiveProjection(void)
{
	Transform op, projection;

	assert(perspective != NULL);
	assert(perspective->near != perspective->far);

	projection = CameraTransform();

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

	return projection;
}

Transform CameraTransform(void)
{
	Camera *camera = GetCamera();
	assert(camera != NULL);

	Transform projection = Translation(NegVec(camera->position));
	AddTransform(AlignCameraToAxis(), &projection);
	AddTransform(camera->transform, &projection);

	return projection;
}

Transform GetProjection(void)
{
	if (mode == ORTHO) {
		return OrthoProjection();
	} else {
		return PerspectiveProjection();
	}
}

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

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

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

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