This repository has been archived by the owner on Jan 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tracer.py
154 lines (120 loc) · 4.97 KB
/
tracer.py
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import numpy
from transformations import Affine, rotation_matrix
class Tracer(object):
"""
A Tracer instance represents the shape of a three-dimensional body.
It is also associated with OpenCL code (templates) that can be used
to compute the intersection of a ray and this object and an exterior
normal at that intersection.
"""
def __init__(self, position=(0,0,0), **affine_kwargs):
# setting this to, e.g., id(obj), causes a tracer function to be
# generated for each instance, instead of one per Tracer (sub)class
self.unique_tracer_id = ""
self.coordinates = Affine(translation=position, **affine_kwargs)
def _function_name_prefix(self):
return self.__class__.__name__+self.unique_tracer_id
@property
def tracer_function_name(self):
return self._function_name_prefix() + '_tracer'
@property
def normal_function_name(self):
return self._function_name_prefix() + '_normal'
@property
def tracer_kernel_name(self):
return self._function_name_prefix() + '_tracer_kernel'
@property
def shadow_kernel_name(self):
return self._function_name_prefix() + '_shadow_kernel'
@property
def normal_kernel_name(self):
return self._function_name_prefix() + '_normal_kernel'
def template_file_name(self):
return 'objects/%s.cl' % self.template_name()
def template_name(self):
return self.__class__.__name__
def _make_code(self, macro, template_env):
s = "{% import '" + self.template_file_name() + "' as a %}" + \
("{{ a.%s }}\n" % macro)
return template_env.from_string(s).render(obj=self)
def make_functions(self, template_env):
"""
Make necessary OpenCL functions for tracing objects of this class
Returns a dictionary OpenCL function name -> function contents
"""
return { \
self.tracer_function_name : \
self._make_code('tracer_function(obj)', template_env),
self.normal_function_name : \
self._make_code('normal_function(obj)', template_env)
}
def make_kernels(self, template_env):
"""
Make necessary OpenCL kernels for tracing objects of this class
Returns a dictionary OpenCL kernel name -> function contents
"""
return { \
self.tracer_kernel_name : \
self._make_code('tracer_kernel(obj)', template_env),
self.shadow_kernel_name : \
self._make_code('shadow_kernel(obj)', template_env),
self.normal_kernel_name : \
self._make_code('normal_kernel(obj)', template_env)
}
def parameter_declarations(self):
return []
def parameter_values(self):
return [getattr(self, name) for _, name in self._typed_parameters()]
def parameter_declaration_string(self):
params = self.parameter_declarations()
if self.has_data():
params = [
"TRACER_DATA const float4 *vector_data",
"TRACER_DATA const int *integer_data"
] + params
return cl_parameter_string(params)
def parameter_types(self):
return [cl_type for cl_type, _ in self._typed_parameters()]
def parameter_names(self):
return [name for _, name in self._typed_parameters()]
def _typed_parameters(self):
for p in self.parameter_declarations():
cl_type, name = p.split()
yield((cl_type,name))
def has_data(self):
return hasattr(self, 'get_data')
def tracer_coordinate_system(self):
return Affine.identity()
def global_to_tracer_coordinate_transform(self):
return self.coordinates(self.tracer_coordinate_system())
@property
def auto_flip_normal(self):
"""
Automatically flip computed normal to correct direction?
"""
return False
@property
def convex(self):
return False
def linear_transform(self, linear=None, translation=None, **kwargs):
if translation is not None:
raise RuntimeError('translation not allowed')
transform = Affine(linear=linear, **kwargs).linear
self.coordinates = Affine(
linear=numpy.dot(transform, self.coordinates.linear),
translation=self.coordinates.translation)
return self
def rotate(self, axis, deg):
return self.linear_transform(rotation_axis=axis, rotation_deg=deg)
@property
def position(self):
return self.coordinates.translation
@position.setter
def position(self, value):
self.coordinates = Affine(
linear=self.coordinates.linear,
translation=value
)
def cl_parameter_string(params):
if len(params) == 0: return ''
else: return ', '.join([''] + params)