1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2019 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 // Authors: Asher Elmquist
13 // =============================================================================
14 //
15 // =============================================================================
16 
17 #ifndef CHSENSORDEVICEUTILS_H
18 #define CHSENSORDEVICEUTILS_H
19 
20 #include "chrono_sensor/optix/ChOptixDefinitions.h"
21 
22 #include <math_constants.h>
23 #include <optix.h>
24 
25 extern "C" {
26 __constant__ ContextParameters params;
27 }
28 
make_half4(const float4 & a)29 __device__ __inline__ half4 make_half4(const float4& a) {
30     return {__float2half(a.x), __float2half(a.y), __float2half(a.z), __float2half(a.w)};
31 }
32 
make_half4(const float & a,const float & b,const float & c,const float & d)33 __device__ __inline__ half4 make_half4(const float& a, const float& b, const float& c, const float& d) {
34     return {__float2half(a), __float2half(b), __float2half(c), __float2half(d)};
35 }
36 
make_color(const float3 & c)37 static __device__ __inline__ uchar4 make_color(const float3& c) {
38     return make_uchar4(static_cast<unsigned char>(__saturatef(c.x) * 255.9999f),
39                        static_cast<unsigned char>(__saturatef(c.y) * 255.9999f),
40                        static_cast<unsigned char>(__saturatef(c.z) * 255.9999f), 255);
41 }
42 
ints_as_pointer(unsigned int & a,unsigned int & b)43 static __device__ __inline__ void* ints_as_pointer(unsigned int& a, unsigned int& b) {
44     const unsigned long long ptr = static_cast<unsigned long long>(a) << 32 | b;
45     return reinterpret_cast<void*>(ptr);
46 }
47 
pointer_as_ints(void * ptr,unsigned int & a,unsigned int & b)48 static __device__ __inline__ void pointer_as_ints(void* ptr, unsigned int& a, unsigned int& b) {
49     const unsigned long long uptr = reinterpret_cast<unsigned long long>(ptr);
50     a = uptr >> 32;
51     b = uptr & 0x00000000ffffffff;
52 }
53 
sensor_rand(unsigned int seed)54 static __device__ __inline__ float sensor_rand(unsigned int seed) {
55     unsigned int next = (1103515245u * seed + 12345u) % 2147483648u;
56     return (float)(next) / (float)(2147483648u);
57 }
58 
sensor_next_rand(float & rand)59 static __device__ __inline__ float sensor_next_rand(float& rand) {
60     unsigned int next_seed = (unsigned int)(rand * 2147483648u);
61     float next_rand = sensor_rand(next_seed);
62     rand = next_rand;
63     return rand;
64 }
65 
getCameraPRD()66 __device__ __inline__ PerRayData_camera* getCameraPRD() {
67     unsigned int opt0 = optixGetPayload_0();
68     unsigned int opt1 = optixGetPayload_1();
69     return reinterpret_cast<PerRayData_camera*>(ints_as_pointer(opt0, opt1));
70 }
71 
getSemanticPRD()72 __device__ __inline__ PerRayData_semantic* getSemanticPRD() {
73     unsigned int opt0 = optixGetPayload_0();
74     unsigned int opt1 = optixGetPayload_1();
75     return reinterpret_cast<PerRayData_semantic*>(ints_as_pointer(opt0, opt1));
76 }
77 
getLidarPRD()78 __device__ __inline__ PerRayData_lidar* getLidarPRD() {
79     unsigned int opt0 = optixGetPayload_0();
80     unsigned int opt1 = optixGetPayload_1();
81     return reinterpret_cast<PerRayData_lidar*>(ints_as_pointer(opt0, opt1));
82 }
83 
getRadarPRD()84 __device__ __inline__ PerRayData_radar* getRadarPRD() {
85     unsigned int opt0 = optixGetPayload_0();
86     unsigned int opt1 = optixGetPayload_1();
87     return reinterpret_cast<PerRayData_radar*>(ints_as_pointer(opt0, opt1));
88 }
89 
getShadowPRD()90 __device__ __inline__ PerRayData_shadow* getShadowPRD() {
91     unsigned int opt0 = optixGetPayload_0();
92     unsigned int opt1 = optixGetPayload_1();
93     return reinterpret_cast<PerRayData_shadow*>(ints_as_pointer(opt0, opt1));
94 }
95 
default_camera_prd()96 __device__ __inline__ PerRayData_camera default_camera_prd() {
97     PerRayData_camera prd = {};
98     prd.color = make_float3(0.f, 0.f, 0.f);
99     prd.contrib_to_pixel = make_float3(1.f, 1.f, 1.f);
100     prd.rng = curandState_t();
101     prd.depth = 2;
102     prd.use_gi = false;
103     prd.albedo = make_float3(0.f, 0.f, 0.f);
104     prd.normal = make_float3(0.f, 0.f, 0.f);
105     return prd;
106 };
107 
default_semantic_prd()108 __device__ __inline__ PerRayData_semantic default_semantic_prd() {
109     PerRayData_semantic prd = {};
110     prd.class_id = 0;
111     prd.instance_id = 0;
112     return prd;
113 };
114 
default_shadow_prd()115 __device__ __inline__ PerRayData_shadow default_shadow_prd() {
116     PerRayData_shadow prd = {make_float3(1.f, 1.f, 1.f),  // default opacity amount
117                              3,                           // default depth
118                              0.f};                        // default distance remaining to light
119     return prd;
120 };
121 
default_lidar_prd()122 __device__ __inline__ PerRayData_lidar default_lidar_prd() {
123     PerRayData_lidar prd = {
124         0.f,  // default range
125         0.f   // default intensity
126     };
127     return prd;
128 };
default_radar_prd()129 __device__ __inline__ PerRayData_radar default_radar_prd() {
130     PerRayData_radar prd = {
131         0.f,  // default range
132         0.f   // default rcs
133     };
134     return prd;
135 };
136 
137 /// =======================
138 /// float3-float3 operators
139 /// =======================
140 __device__ __inline__ float3 operator+(const float3& a, const float3& b) {
141     return make_float3(a.x + b.x, a.y + b.y, a.z + b.z);
142 }
143 
144 __device__ __inline__ void operator+=(float3& a, const float3& b) {
145     a = a + b;
146 }
147 
148 __device__ __inline__ float3 operator-(const float3& a, const float3& b) {
149     return make_float3(a.x - b.x, a.y - b.y, a.z - b.z);
150 }
151 
152 __device__ __inline__ float3 operator-(const float3& a) {
153     return make_float3(-a.x, -a.y, -a.z);
154 }
155 
156 __device__ __inline__ float3 operator/(const float3& a, const float3& b) {
157     return make_float3(a.x / b.x, a.y / b.y, a.z / b.z);
158 }
159 
160 __device__ __inline__ float3 operator*(const float3& a, const float3& b) {
161     return make_float3(a.x * b.x, a.y * b.y, a.z * b.z);
162 }
163 
164 /// =======================
165 /// float4-float4 operators
166 /// =======================
167 __device__ __inline__ float4 operator+(const float4& a, const float4& b) {
168     return make_float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
169 }
170 
171 __device__ __inline__ void operator+=(float4& a, const float4& b) {
172     a = a + b;
173 }
174 
175 __device__ __inline__ float4 operator-(const float4& a, const float4& b) {
176     return make_float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
177 }
178 
179 __device__ __inline__ float4 operator-(const float4& a) {
180     return make_float4(-a.x, -a.y, -a.z, -a.w);
181 }
182 
183 __device__ __inline__ float4 operator/(const float4& a, const float4& b) {
184     return make_float4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
185 }
186 
187 __device__ __inline__ float4 operator*(const float4& a, const float4& b) {
188     return make_float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
189 }
190 
191 /// ================
192 /// vector functions
193 /// ================
Dot(const float4 & v1,const float4 & v2)194 __device__ __inline__ float Dot(const float4& v1, const float4& v2) {
195     return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w;
196 }
197 
Dot(const float3 & v1,const float3 & v2)198 __device__ __inline__ float Dot(const float3& v1, const float3& v2) {
199     return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
200 }
201 
Dot(const float2 & v1,const float2 & v2)202 __device__ __inline__ float Dot(const float2& v1, const float2& v2) {
203     return v1.x * v2.x + v1.y * v2.y;
204 }
205 
Cross(const float3 & v1,const float3 & v2)206 __device__ __inline__ float3 Cross(const float3& v1, const float3& v2) {
207     return make_float3(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x);
208 }
209 
Length(const float4 & v)210 __device__ __inline__ float Length(const float4& v) {
211     return sqrt(Dot(v, v));
212 }
213 
Length(const float3 & v)214 __device__ __inline__ float Length(const float3& v) {
215     return sqrt(Dot(v, v));
216 }
217 
Length(const float2 & v)218 __device__ __inline__ float Length(const float2& v) {
219     return sqrt(Dot(v, v));
220 }
221 
fmaxf(const float3 & a)222 __device__ __inline__ float fmaxf(const float3& a) {
223     return fmaxf(a.x, fmaxf(a.y, a.z));
224 }
225 
fminf(const float3 & a)226 __device__ __inline__ float fminf(const float3& a) {
227     return fminf(a.x, fminf(a.y, a.z));
228 }
229 
make_float3(const float & a)230 __device__ __inline__ float3 make_float3(const float& a) {
231     return make_float3(a, a, a);
232 }
233 
make_float3(const float4 & a)234 __device__ __inline__ float3 make_float3(const float4& a) {
235     return make_float3(a.x, a.y, a.z);
236 }
237 
Pow(const float3 & v,const float & a)238 __device__ __inline__ float3 Pow(const float3& v, const float& a) {
239     return make_float3(pow(v.x, a), pow(v.y, a), pow(v.z, a));
240 }
241 /// =======================
242 /// float3-float operators
243 /// =======================
244 __device__ __inline__ float3 operator*(const float& a, const float3& v) {
245     return make_float3(a * v.x, a * v.y, a * v.z);
246 }
247 
248 __device__ __inline__ float3 operator*(const float3& v, const float& a) {
249     return make_float3(a * v.x, a * v.y, a * v.z);
250 }
251 
252 __device__ __inline__ float3 operator/(const float3& v, const float& a) {
253     const float inv = 1 / a;
254     return make_float3(inv * v.x, inv * v.y, inv * v.z);
255 }
256 
normalize(const float3 & a)257 __device__ __inline__ float3 normalize(const float3& a) {
258     return a / Length(a);
259 }
260 
261 /// =======================
262 /// float4-float operators
263 /// =======================
264 __device__ __inline__ float4 operator*(const float& a, const float4& v) {
265     return make_float4(a * v.x, a * v.y, a * v.z, a * v.w);
266 }
267 
268 __device__ __inline__ float4 operator*(const float4& v, const float& a) {
269     return make_float4(a * v.x, a * v.y, a * v.z, a * v.w);
270 }
271 
272 __device__ __inline__ float4 operator/(const float4& v, const float& a) {
273     const float inv = 1 / a;
274     return make_float4(inv * v.x, inv * v.y, inv * v.z, inv * v.w);
275 }
276 
normalize(const float4 & a)277 __device__ __inline__ float4 normalize(const float4& a) {
278     return a / Length(a);
279 }
280 
281 /// ======================
282 /// float3-float functions
283 /// ======================
fmaxf(const float3 & a,const float3 & b)284 __device__ __inline__ float3 fmaxf(const float3& a, const float3& b) {
285     return make_float3(fmaxf(a.x, b.x), fmaxf(a.y, b.y), fmaxf(a.z, b.z));
286 }
287 
fminf(const float3 & a,const float3 & b)288 __device__ __inline__ float3 fminf(const float3& a, const float3& b) {
289     return make_float3(fminf(a.x, b.x), fminf(a.y, b.y), fminf(a.z, b.z));
290 }
291 
292 /// =======================
293 /// float2-float2 operators
294 /// =======================
295 __device__ __inline__ float2 operator+(const float2& a, const float2& b) {
296     return make_float2(a.x + b.x, a.y + b.y);
297 }
298 
299 __device__ __inline__ float2 operator-(const float2& a, const float2& b) {
300     return make_float2(a.x - b.x, a.y - b.y);
301 }
302 
303 __device__ __inline__ float2 operator-(const float2& a) {
304     return make_float2(-a.x, -a.y);
305 }
306 
307 __device__ __inline__ float2 operator/(const float2& a, const float2& b) {
308     return make_float2(a.x / b.x, a.y / b.y);
309 }
310 
311 /// =======================
312 /// float2-float operators
313 /// =======================
314 __device__ __inline__ float2 operator*(const float& a, const float2& v) {
315     return make_float2(a * v.x, a * v.y);
316 }
317 
318 __device__ __inline__ float2 operator*(const float2& v, const float& a) {
319     return make_float2(a * v.x, a * v.y);
320 }
321 
322 __device__ __inline__ float2 operator/(const float2& v, const float& a) {
323     const float inv = 1 / a;
324     return make_float2(inv * v.x, inv * v.y);
325 }
326 
327 /// ================
328 /// float2 functions
329 /// ================
make_float2(const float & a)330 __device__ __inline__ float2 make_float2(const float& a) {
331     return make_float2(a, a);
332 }
333 
make_float2(const int2 & a)334 __device__ __inline__ float2 make_float2(const int2& a) {
335     return make_float2((float)a.x, (float)a.y);
336 }
337 
normalize(const float2 & a)338 __device__ __inline__ float2 normalize(const float2& a) {
339     return a / Length(a);
340 }
341 
342 /// ================
343 /// clamp functions
344 /// ================
clamp(const float & a,const float & low,const float & high)345 __device__ __inline__ float clamp(const float& a, const float& low, const float& high) {
346     return max(low, min(a, high));
347 }
348 
clamp(const float2 & a,const float2 & low,const float2 & high)349 __device__ __inline__ float2 clamp(const float2& a, const float2& low, const float2& high) {
350     return make_float2(clamp(a.x, low.x, high.x), clamp(a.y, low.y, high.y));
351 }
352 
clamp(const float3 & a,const float3 & low,const float3 & high)353 __device__ __inline__ float3 clamp(const float3& a, const float3& low, const float3& high) {
354     return make_float3(clamp(a.x, low.x, high.x), clamp(a.y, low.y, high.y), clamp(a.z, low.z, high.z));
355 }
356 
357 /// ==================
358 /// graphics functions
359 /// ==================
360 __device__ __inline__ float fresnel_schlick(const float& cos,
361                                             const float& exp = 5.f,
362                                             const float& min = 0.f,
363                                             const float& max = 1.f) {
364     return clamp(min + (max - min) * powf(fmaxf(0.f, 1.f - cos), exp), min, max);
365 }
366 
fresnel_schlick(const float & cos,const float & exp,const float3 & min,const float3 & max)367 __device__ __inline__ float3 fresnel_schlick(const float& cos, const float& exp, const float3& min, const float3& max) {
368     return make_float3(fresnel_schlick(cos, exp, min.x, max.x), fresnel_schlick(cos, exp, min.y, max.y),
369                        fresnel_schlick(cos, exp, min.z, max.z));
370 }
371 
luminance(const float3 & color)372 __device__ __inline__ float luminance(const float3& color) {
373     const float3 l = {0.30f, 0.59f, 0.11f};
374     return Dot(color, l);
375 }
376 
377 // assumes v in coming into the surface
reflect(const float3 & v,const float3 & n)378 __device__ __inline__ float3 reflect(const float3& v, const float3& n) {
379     return 2 * Dot(n, -v) * n + v;
380 }
381 
refract(const float3 & v,const float3 & n,const float & n1,const float & n2)382 __device__ __inline__ float3 refract(const float3& v, const float3& n, const float& n1, const float& n2) {
383     float n_ratio = n1 / n2;
384     float cosi = -Dot(n, v);
385     return n_ratio * v + (n_ratio * cosi - sqrtf(max(0.f, 1 - n_ratio * n_ratio * cosi * cosi))) * n;
386 }
387 
basis_from_quaternion(const float4 & q,float3 & f,float3 & g,float3 & h)388 __device__ __inline__ void basis_from_quaternion(const float4& q, float3& f, float3& g, float3& h) {
389     const float e0e0 = q.x * q.x;
390     const float e1e1 = q.y * q.y;
391     const float e2e2 = q.z * q.z;
392     const float e3e3 = q.w * q.w;
393     const float e0e1 = q.x * q.y;
394     const float e0e2 = q.x * q.z;
395     const float e0e3 = q.x * q.w;
396     const float e1e2 = q.y * q.z;
397     const float e1e3 = q.y * q.w;
398     const float e2e3 = q.z * q.w;
399     f = make_float3((e0e0 + e1e1) * 2 - 1, (e1e2 + e0e3) * 2, (e1e3 - e0e2) * 2);
400     g = make_float3((e1e2 - e0e3) * 2, (e0e0 + e2e2) * 2 - 1, (e2e3 + e0e1) * 2);
401     h = make_float3((e1e3 + e0e2) * 2, (e2e3 - e0e1) * 2, (e0e0 + e3e3) * 2 - 1);
402 }
403 
lerp(const float & a,const float & b,const float & t)404 __device__ __inline__ float lerp(const float& a, const float& b, const float& t) {
405     return a + t * (b - a);
406 }
407 
lerp(const float2 & a,const float2 & b,const float & t)408 __device__ __inline__ float2 lerp(const float2& a, const float2& b, const float& t) {
409     return a + t * (b - a);
410 }
411 
lerp(const float3 & a,const float3 & b,const float & t)412 __device__ __inline__ float3 lerp(const float3& a, const float3& b, const float& t) {
413     return a + t * (b - a);
414 }
415 
lerp(const float4 & a,const float4 & b,const float & t)416 __device__ __inline__ float4 lerp(const float4& a, const float4& b, const float& t) {
417     return a + t * (b - a);
418 }
419 
nlerp(const float2 & a,const float2 & b,const float & t)420 __device__ __inline__ float2 nlerp(const float2& a, const float2& b, const float& t) {
421     return normalize(lerp(a, b, t));
422 }
423 
nlerp(const float3 & a,const float3 & b,const float & t)424 __device__ __inline__ float3 nlerp(const float3& a, const float3& b, const float& t) {
425     return normalize(lerp(a, b, t));
426 }
427 
nlerp(const float4 & a,const float4 & b,const float & t)428 __device__ __inline__ float4 nlerp(const float4& a, const float4& b, const float& t) {
429     return normalize(lerp(a, b, t));
430 }
431 
sample_hemisphere_dir(const float & z1,const float & z2,const float3 & normal)432 __device__ __inline__ float3 sample_hemisphere_dir(const float& z1, const float& z2, const float3& normal) {
433     const float radius = sqrtf(z1);
434     const float theta = 2.f * CUDART_PI_F * z2;
435     float x = radius * cosf(theta);
436     float y = radius * sinf(theta);
437     float z = sqrtf(fmaxf(0.f, 1.f - x * x - y * y));
438     float3 binormal = make_float3(0);
439 
440     // Prevent normal = (0, 0, 1)
441     if (fabs(normal.x) > fabs(normal.z)) {
442         binormal.x = -normal.y;
443         binormal.y = normal.x;
444         binormal.z = 0;
445     } else {
446         binormal.x = 0;
447         binormal.y = -normal.z;
448         binormal.z = normal.y;
449     }
450 
451     // float3 binormal = make_float3(-normal.y, normal.x, 0);
452     float3 tangent = Cross(normal, binormal);
453     return x * tangent + y * binormal + z * normal;
454 }
455 
456 #endif
457