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