1 // Copyright Contributors to the Open Shading Language project.
2 // SPDX-License-Identifier: BSD-3-Clause
3 // https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
4 
5 
6 #include <optix.h>
7 
8 #if (OPTIX_VERSION < 70000)
9 #include <optixu/optixu_aabb_namespace.h>
10 #include <optixu/optixu_math_namespace.h>
11 #include <optixu/optixu_vector_types.h>
12 
13 #include <OSL/oslconfig.h>
14 #include <OSL/shaderglobals.h>
15 #include <OSL/dual.h>
16 #include <OSL/dual_vec.h>
17 #include <OpenImageIO/fmath.h>
18 
19 using namespace optix;
20 using OSL::Dual2;
21 using OSL::Vec3;
22 
23 
24 rtDeclareVariable (float4, sphere, , );
25 rtDeclareVariable (float,  r2, , );
26 rtDeclareVariable (float,  a, , );
27 
28 rtDeclareVariable (float3, texcoord,         attribute texcoord, );
29 rtDeclareVariable (float3, geometric_normal, attribute geometric_normal, );
30 rtDeclareVariable (float3, shading_normal,   attribute shading_normal, );
31 rtDeclareVariable (float,  surface_area,     attribute surface_area, );
32 
33 rtDeclareVariable (float3, dPdu, attribute dPdu, );
34 rtDeclareVariable (float3, dPdv, attribute dPdv, );
35 
36 rtDeclareVariable (optix::Ray, ray, rtCurrentRay, );
37 
38 
39 static __device__ __inline__
calc_uv()40 void calc_uv()
41 {
42     Dual2<Vec3> n (Vec3 (shading_normal.x, shading_normal.y, shading_normal.z));
43 
44     Dual2<float> nx(n.val().x, n.dx().x, n.dy().x);
45     Dual2<float> ny(n.val().y, n.dx().y, n.dy().y);
46     Dual2<float> nz(n.val().z, n.dx().z, n.dy().z);
47     Dual2<float> u = (fast_atan2(nx, nz) + Dual2<float>(M_PI)) * 0.5f * float(M_1_PI);
48     Dual2<float> v = fast_acos(ny) * float(M_1_PI);
49     float xz2 = nx.val() * nx.val() + nz.val() * nz.val();
50     if (xz2 > 0.0f) {
51         const float PI = float(M_PI);
52         const float TWOPI = float(2 * M_PI);
53         float xz = sqrtf(xz2);
54         float inv = 1.0f / xz;
55         dPdu.x = -TWOPI * nx.val();
56         dPdu.y = TWOPI * nz.val();
57         dPdu.z = 0.0f;
58         dPdv.x = -PI * nz.val() * inv * ny.val();
59         dPdv.y = -PI * nx.val() * inv * ny.val();
60         dPdv.z = PI * xz;
61     } else {
62         // pick arbitrary axes for poles to avoid division by 0
63         if (ny.val() > 0.0f) {
64             dPdu = make_float3 (0.0f, 0.0f, 1.0f);
65             dPdv = make_float3 (1.0f, 0.0f, 0.0f);
66         } else {
67             dPdu = make_float3 ( 0.0f, 0.0f, 1.0f);
68             dPdv = make_float3 (-1.0f, 0.0f, 0.0f);
69         }
70     }
71     texcoord = make_float3 (u.val(), v.val(), 0.0f);
72 }
73 
74 
75 // Intersection adapted from testrender/raytracer.h
intersect(void)76 RT_PROGRAM void intersect (void)
77 {
78     float3 c   = make_float3(sphere);
79     float3 oc  = c - ray.origin;
80     float  b   = dot(oc, ray.direction);
81     float  det = b * b - dot(oc, oc) + r2;
82 
83     if (det >= 0.0f) {
84         det = sqrtf(det);
85         float x = b - det;
86         float y = b + det;
87 
88         // NB: this does not included the 'self' check from
89         // the testrender sphere intersection
90         float t = (x > 0) ? x : ((y > 0) ? y : 0);
91 
92         if (rtPotentialIntersection(t)) {
93             float3 P = ray.origin + ray.direction * t;
94             float3 N = normalize (P - c);
95             shading_normal = geometric_normal = N;
96             surface_area = a;
97 
98             // Calculate the texture coordinates and derivatives
99             calc_uv();
100 
101             rtReportIntersection(0);
102         }
103     }
104 }
105 
106 
bounds(int,float result[6])107 RT_PROGRAM void bounds (int, float result[6])
108 {
109     const float3 center = make_float3(sphere);
110     const float3 radius = make_float3(sphere.w);
111 
112     optix::Aabb* aabb = reinterpret_cast<optix::Aabb*>(result);
113 
114     if (radius.x > 0.0f && !isinf(radius.x)) {
115         aabb->m_min = center - radius;
116         aabb->m_max = center + radius;
117     } else {
118         aabb->invalidate();
119     }
120 }
121 
122 #else //#if (OPTIX_VERSION < 70000)
123 
124 #include "wrapper.h"
125 #include "rend_lib.h"
126 #include "render_params.h"
127 
128 
129 static __device__ __inline__
calc_uv(float3 shading_normal,float & u,float & v,float3 & dPdu,float3 & dPdv)130 void calc_uv (float3 shading_normal, float& u, float& v, float3& dPdu, float3& dPdv)
131 {
132     const float3 n = shading_normal;
133 
134     const float nx = n.x;
135     const float ny = n.y;
136     const float nz = n.z;
137 
138     u = (atan2(nx, nz) + M_PI) * 0.5f * float(M_1_PI);
139     v = acos(ny) * float(M_1_PI);
140 
141     float xz2 = nx * nx + nz * nz;
142     if (xz2 > 0.0f) {
143         const float PI = float(M_PI);
144         const float TWOPI = float(2 * M_PI);
145         float xz = sqrtf(xz2);
146         float inv = 1.0f / xz;
147         dPdu = make_float3 (-TWOPI * nx,
148                              TWOPI * nz,
149                              0.0f);
150         dPdv = make_float3 (-PI * nz * inv * ny,
151                             -PI * nx * inv * ny,
152                              PI * xz);
153     } else {
154         // pick arbitrary axes for poles to avoid division by 0
155         if (ny > 0.0f) {
156             dPdu = make_float3 (0.0f, 0.0f, 1.0f);
157             dPdv = make_float3 (1.0f, 0.0f, 0.0f);
158         } else {
159             dPdu = make_float3 ( 0.0f, 0.0f, 1.0f);
160             dPdv = make_float3 (-1.0f, 0.0f, 0.0f);
161         }
162     }
163 }
164 
165 
166 extern "C" __device__
__direct_callable__sphere_shaderglobals(const unsigned int idx,const float t_hit,const float3 ray_origin,const float3 ray_direction,ShaderGlobals * sg)167 void __direct_callable__sphere_shaderglobals (const unsigned int idx,
168                                               const float        t_hit,
169                                               const float3       ray_origin,
170                                               const float3       ray_direction,
171                                               ShaderGlobals     *sg)
172 {
173     const GenericData *g_data     = reinterpret_cast<const GenericData *>(optixGetSbtDataPointer());
174     const SphereParams *g_spheres = reinterpret_cast<const SphereParams *>(g_data->data);
175     const SphereParams &sphere    = g_spheres[idx];
176     const float3 P = ray_origin + t_hit * ray_direction;
177 
178     sg->N = sg->Ng = normalize (P - sphere.c);
179     sg->surfacearea = sphere.a;
180     sg->shaderID    = sphere.shaderID;
181 
182     calc_uv(sg->N, sg->u, sg->v, sg->dPdu, sg->dPdv);
183 }
184 
185 
__intersection__sphere()186 extern "C" __global__ void __intersection__sphere ()
187 {
188     const GenericData *g_data     = reinterpret_cast<const GenericData *>(optixGetSbtDataPointer());
189     const SphereParams *g_spheres = reinterpret_cast<const SphereParams *>(g_data->data);
190     const unsigned int idx        = optixGetPrimitiveIndex();
191     const SphereParams &sphere    = g_spheres[idx];
192     const float3 ray_origin       = optixGetObjectRayOrigin();
193     const float3 ray_direction    = optixGetObjectRayDirection();
194 
195     float3 oc  = sphere.c - ray_origin;
196     float  b   = dot(oc, ray_direction);
197     float  det = b * b - dot(oc, oc) + sphere.r2;
198     if (det >= 0.0f) {
199         det = sqrtf(det);
200         float x = b - det;
201         float y = b + det;
202 
203         // NB: this does not included the 'self' check from
204         // the testrender sphere intersection
205         float t = (x > 0) ? x : ((y > 0) ? y : 0);
206 
207         if (t < optixGetRayTmax())
208             optixReportIntersection(t, RAYTRACER_HIT_SPHERE);
209     }
210 }
211 
212 #endif //#if (OPTIX_VERSION < 70000)
213