e276548b |
1 | // Created on: 2013-10-16 |
2 | // Created by: Denis BOGOLEPOV |
3 | // Copyright (c) 2013 OPEN CASCADE SAS |
4 | // |
5 | // The content of this file is subject to the Open CASCADE Technology Public |
6 | // License Version 6.5 (the "License"). You may not use the content of this file |
7 | // except in compliance with the License. Please obtain a copy of the License |
8 | // at http://www.opencascade.org and read it completely before using this file. |
9 | // |
10 | // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its |
11 | // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. |
12 | // |
13 | // The Original Code and all software distributed under the License is |
14 | // distributed on an "AS IS" basis, without warranty of any kind, and the |
15 | // Initial Developer hereby disclaims all such warranties, including without |
16 | // limitation, any warranties of merchantability, fitness for a particular |
17 | // purpose or non-infringement. Please see the License for the specific terms |
18 | // and conditions governing the rights and limitations under the License. |
19 | |
20 | #ifdef HAVE_CONFIG_H |
21 | #include <config.h> |
22 | #endif |
23 | |
24 | #ifdef HAVE_OPENCL |
25 | |
26 | #define EOL "\n" |
27 | |
28 | extern const char THE_RAY_TRACE_OPENCL_SOURCE[] = |
29 | |
30 | ///////////////////////////////////////////////////////////////////////////////////////// |
31 | // Specific data types |
32 | EOL |
33 | //! Stores ray parameters. |
34 | EOL" typedef struct __SRay" |
35 | EOL" {" |
36 | EOL" float4 Origin;" |
37 | EOL" float4 Direct;" |
38 | EOL" }" |
39 | EOL" SRay;" |
40 | EOL |
41 | //! Stores parameters of intersection point. |
42 | EOL" typedef struct __SIntersect" |
43 | EOL" {" |
44 | EOL" float4 Normal;" |
45 | EOL" float Time;" |
46 | EOL" float U;" |
47 | EOL" float V;" |
48 | EOL" }" |
49 | EOL" SIntersect;" |
50 | EOL |
51 | EOL |
52 | ///////////////////////////////////////////////////////////////////////////////////////// |
53 | // Some useful vector constants |
54 | EOL |
55 | EOL" #define ZERO ( float4 )( 0.f, 0.f, 0.f, 0.f )" |
56 | EOL" #define UNIT ( float4 )( 1.f, 1.f, 1.f, 0.f )" |
57 | EOL |
58 | EOL" #define AXIS_X ( float4 )( 1.f, 0.f, 0.f, 0.f )" |
59 | EOL" #define AXIS_Y ( float4 )( 0.f, 1.f, 0.f, 0.f )" |
60 | EOL" #define AXIS_Z ( float4 )( 0.f, 0.f, 1.f, 0.f )" |
61 | EOL |
62 | EOL |
63 | ///////////////////////////////////////////////////////////////////////////////////////// |
64 | // Support functions |
65 | EOL |
66 | // ======================================================================= |
67 | // function : GenerateRay |
68 | // purpose : Generates primary ray for current work item |
69 | // ======================================================================= |
70 | EOL" void GenerateRay (SRay* theRay," |
71 | EOL" const float theX," |
72 | EOL" const float theY," |
73 | EOL" const int theSizeX," |
74 | EOL" const int theSizeY," |
75 | EOL" const float16 theOrigins," |
76 | EOL" const float16 theDirects)" |
77 | EOL" {" |
78 | EOL" float2 aPixel = (float2) (theX / (float)theSizeX," |
79 | EOL" theY / (float)theSizeY);" |
80 | EOL |
81 | EOL" float4 aP0 = mix (theOrigins.lo.lo, theOrigins.lo.hi, aPixel.x);" |
82 | EOL" float4 aP1 = mix (theOrigins.hi.lo, theOrigins.hi.hi, aPixel.x);" |
83 | EOL |
84 | EOL" theRay->Origin = mix (aP0, aP1, aPixel.y);" |
85 | EOL |
86 | EOL" aP0 = mix (theDirects.lo.lo, theDirects.lo.hi, aPixel.x);" |
87 | EOL" aP1 = mix (theDirects.hi.lo, theDirects.hi.hi, aPixel.x);" |
88 | EOL |
89 | EOL" theRay->Direct = mix (aP0, aP1, aPixel.y);" |
90 | EOL" }" |
91 | EOL |
92 | EOL |
93 | ///////////////////////////////////////////////////////////////////////////////////////// |
94 | // Functions for compute ray-object intersection |
95 | EOL |
96 | EOL" #define _OOEPS_ exp2( -80.0f )" |
97 | EOL |
98 | // ======================================================================= |
99 | // function : IntersectSphere |
100 | // purpose : Computes ray-sphere intersection |
101 | // ======================================================================= |
102 | EOL" bool IntersectSphere (const SRay* theRay, float theRadius, float* theTime)" |
103 | EOL" {" |
104 | EOL" float aDdotD = dot (theRay->Direct.xyz, theRay->Direct.xyz);" |
105 | EOL" float aDdotO = dot (theRay->Direct.xyz, theRay->Origin.xyz);" |
106 | EOL" float aOdotO = dot (theRay->Origin.xyz, theRay->Origin.xyz);" |
107 | EOL |
108 | EOL" float aD = aDdotO * aDdotO - aDdotD * (aOdotO - theRadius * theRadius);" |
109 | EOL |
110 | EOL" if (aD > 0.f)" |
111 | EOL" {" |
112 | EOL" *theTime = (-aDdotO + native_sqrt (aD)) * (1.f / aDdotD);" |
113 | EOL |
114 | EOL" return *theTime > 0.f;" |
115 | EOL" }" |
116 | EOL |
117 | EOL" return false;" |
118 | EOL" }" |
119 | EOL |
120 | // ======================================================================= |
121 | // function : IntersectBox |
122 | // purpose : Computes ray-box intersection (slab test) |
123 | // ======================================================================= |
124 | EOL" bool IntersectBox (const SRay* theRay," |
125 | EOL" float4 theMinPoint," |
126 | EOL" float4 theMaxPoint," |
127 | EOL" float* theTimeStart," |
128 | EOL" float* theTimeFinal)" |
129 | EOL" {" |
130 | EOL" const float4 aInvDirect = (float4)(" |
131 | EOL" 1.f / (fabs (theRay->Direct.x) > _OOEPS_ ?" |
132 | EOL" theRay->Direct.x : copysign (_OOEPS_, theRay->Direct.x))," |
133 | EOL" 1.f / (fabs (theRay->Direct.y) > _OOEPS_ ?" |
134 | EOL" theRay->Direct.y : copysign (_OOEPS_, theRay->Direct.y))," |
135 | EOL" 1.f / (fabs (theRay->Direct.z) > _OOEPS_ ?" |
136 | EOL" theRay->Direct.z : copysign (_OOEPS_, theRay->Direct.z))," |
137 | EOL" 0.f);" |
138 | EOL |
139 | EOL" const float4 aTime0 = (theMinPoint - theRay->Origin) * aInvDirect;" |
140 | EOL" const float4 aTime1 = (theMaxPoint - theRay->Origin) * aInvDirect;" |
141 | EOL |
142 | EOL" const float4 aTimeMax = max (aTime0, aTime1);" |
143 | EOL" const float4 aTimeMin = min (aTime0, aTime1);" |
144 | EOL |
145 | EOL" *theTimeFinal = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));" |
146 | EOL" *theTimeStart = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));" |
147 | EOL |
148 | EOL" return (*theTimeStart <= *theTimeFinal) & (*theTimeFinal >= 0.f);" |
149 | EOL" }" |
150 | EOL |
151 | // ======================================================================= |
152 | // function : IntersectNodes |
153 | // purpose : Computes intersection of ray with two child nodes (boxes) |
154 | // ======================================================================= |
155 | EOL" void IntersectNodes (const SRay* theRay," |
156 | EOL" float4 theMinPoint0," |
157 | EOL" float4 theMaxPoint0," |
158 | EOL" float4 theMinPoint1," |
159 | EOL" float4 theMaxPoint1," |
160 | EOL" float* theTimeStart0," |
161 | EOL" float* theTimeStart1," |
162 | EOL" float theMaxTime)" |
163 | EOL" {" |
164 | EOL" const float4 aInvDirect = (float4)(" |
165 | EOL" 1.f / (fabs (theRay->Direct.x) > _OOEPS_ ?" |
166 | EOL" theRay->Direct.x : copysign (_OOEPS_, theRay->Direct.x))," |
167 | EOL" 1.f / (fabs (theRay->Direct.y) > _OOEPS_ ?" |
168 | EOL" theRay->Direct.y : copysign (_OOEPS_, theRay->Direct.y))," |
169 | EOL" 1.f / (fabs (theRay->Direct.z) > _OOEPS_ ?" |
170 | EOL" theRay->Direct.z : copysign (_OOEPS_, theRay->Direct.z))," |
171 | EOL" 0.f);" |
172 | EOL |
173 | EOL" float4 aTime0 = (theMinPoint0 - theRay->Origin) * aInvDirect;" |
174 | EOL" float4 aTime1 = (theMaxPoint0 - theRay->Origin) * aInvDirect;" |
175 | EOL |
176 | EOL" float4 aTimeMax = max (aTime0, aTime1);" |
177 | EOL" float4 aTimeMin = min (aTime0, aTime1);" |
178 | EOL |
179 | EOL" aTime0 = (theMinPoint1 - theRay->Origin) * aInvDirect;" |
180 | EOL" aTime1 = (theMaxPoint1 - theRay->Origin) * aInvDirect;" |
181 | EOL |
182 | EOL" float aTimeFinal = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));" |
183 | EOL" float aTimeStart = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));" |
184 | EOL |
185 | EOL" aTimeMax = max (aTime0, aTime1);" |
186 | EOL" aTimeMin = min (aTime0, aTime1);" |
187 | EOL |
188 | EOL" *theTimeStart0 = (aTimeStart <= aTimeFinal) & (aTimeFinal >= 0.f) & (aTimeStart <= theMaxTime)" |
189 | EOL" ? aTimeStart : -MAXFLOAT;" |
190 | EOL |
191 | EOL" aTimeFinal = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));" |
192 | EOL" aTimeStart = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));" |
193 | EOL |
194 | EOL" *theTimeStart1 = (aTimeStart <= aTimeFinal) & (aTimeFinal >= 0.f) & (aTimeStart <= theMaxTime)" |
195 | EOL" ? aTimeStart : -MAXFLOAT;" |
196 | EOL" }" |
197 | EOL |
198 | // ======================================================================= |
199 | // function : IntersectTriangle |
200 | // purpose : Computes ray-triangle intersection (branchless version) |
201 | // ======================================================================= |
202 | EOL" bool IntersectTriangle (const SRay* theRay," |
203 | EOL" const float4 thePoint0," |
204 | EOL" const float4 thePoint1," |
205 | EOL" const float4 thePoint2," |
206 | EOL" float4* theNormal," |
207 | EOL" float* theTime," |
208 | EOL" float* theU," |
209 | EOL" float* theV)" |
210 | EOL" {" |
211 | EOL" const float4 aEdge0 = thePoint1 - thePoint0;" |
212 | EOL" const float4 aEdge1 = thePoint0 - thePoint2;" |
213 | EOL |
214 | EOL" *theNormal = cross (aEdge1, aEdge0);" |
215 | EOL |
216 | EOL" const float4 aEdge2 = (1.f / dot (*theNormal, theRay->Direct)) * (thePoint0 - theRay->Origin);" |
217 | EOL |
218 | EOL" *theTime = dot (*theNormal, aEdge2);" |
219 | EOL |
220 | EOL" const float4 theInc = cross (theRay->Direct, aEdge2);" |
221 | EOL |
222 | EOL" *theU = dot (theInc, aEdge1);" |
223 | EOL" *theV = dot (theInc, aEdge0);" |
224 | EOL |
225 | EOL" return (*theTime > 0) & (*theU >= 0.f) & (*theV >= 0.f) & (*theU + *theV <= 1.f);" |
226 | EOL" }" |
227 | EOL |
228 | ///////////////////////////////////////////////////////////////////////////////////////// |
229 | // Support shading functions |
230 | EOL |
231 | EOL" const sampler_t EnvironmentSampler =" |
232 | EOL" CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_REPEAT | CLK_FILTER_LINEAR;" |
233 | EOL |
234 | // ======================================================================= |
235 | // function : SmoothNormal |
236 | // purpose : Interpolates normal across the triangle |
237 | // ======================================================================= |
238 | EOL" float4 SmoothNormal (__global float4* theNormals," |
239 | EOL" const SIntersect* theHit," |
240 | EOL" const int4 theIndices)" |
241 | EOL" {" |
242 | EOL" float4 aNormal0 = theNormals[theIndices.x]," |
243 | EOL" aNormal1 = theNormals[theIndices.y]," |
244 | EOL" aNormal2 = theNormals[theIndices.z];" |
245 | EOL |
246 | EOL" return fast_normalize (aNormal1 * theHit->U +" |
247 | EOL" aNormal2 * theHit->V +" |
248 | EOL" aNormal0 * (1.f - theHit->U - theHit->V));" |
249 | EOL" }" |
250 | EOL |
251 | // ======================================================================= |
252 | // function : Shade |
253 | // purpose : Computes Phong-based illumination |
254 | // ======================================================================= |
255 | EOL" float4 Shade (__global float4* theMaterials," |
256 | EOL" const float4 theLight," |
257 | EOL" const float4 theView," |
258 | EOL" const float4 theNormal," |
259 | EOL" const float4 theIntens," |
260 | EOL" const float theTranspr," |
261 | EOL" const int theMatIndex)" |
262 | EOL" {" |
263 | EOL" float aLambert = dot (theNormal, theLight);" |
264 | EOL |
265 | EOL" aLambert = theTranspr > 0.f ? fabs (aLambert) : aLambert;" |
266 | EOL |
267 | EOL" if (aLambert > 0.f)" |
268 | EOL" {" |
269 | EOL" const float4 aMatDiff = theMaterials[7 * theMatIndex + 1];" |
270 | EOL" const float4 aMatSpec = theMaterials[7 * theMatIndex + 2];" |
271 | EOL |
272 | EOL" const float4 aReflect = 2.f * dot (theLight, theNormal) * theNormal - theLight;" |
273 | EOL |
274 | EOL" const float aSpecular = pow (max (dot (aReflect.xyz, theView.xyz), 0.f), aMatSpec.w);" |
275 | EOL |
276 | EOL" return theIntens * (aMatDiff * aLambert + aMatSpec * aSpecular);" |
277 | EOL" }" |
278 | EOL |
279 | EOL" return ZERO;" |
280 | EOL" }" |
281 | EOL |
282 | // ======================================================================= |
283 | // function : Lat-long |
284 | // purpose : Converts world direction to environment texture coordinates |
285 | // ======================================================================= |
286 | EOL" float2 Latlong (const float4 theDirect)" |
287 | EOL" {" |
288 | EOL" float aPsi = acos( -theDirect.y );" |
289 | EOL" float aPhi = atan2( theDirect.z, theDirect.x );" |
290 | EOL |
291 | EOL" aPhi = (aPhi < 0) ? (aPhi + 2.f * M_PI_F) : aPhi;" |
292 | EOL |
293 | EOL" return (float2) (aPhi / (2.f * M_PI_F), aPsi / M_PI_F);" |
294 | EOL" }" |
295 | EOL |
296 | ///////////////////////////////////////////////////////////////////////////////////////// |
297 | // Core ray tracing function |
298 | EOL |
299 | // ======================================================================= |
300 | // function : push |
301 | // purpose : Pushes BVH node index to local stack |
302 | // ======================================================================= |
303 | EOL" void push (uint* theStack, char* thePos, const uint theValue)" |
304 | EOL" {" |
305 | EOL" (*thePos)++;" |
306 | EOL" theStack[*thePos] = theValue;" |
307 | EOL" }" |
308 | EOL |
309 | // ======================================================================= |
310 | // function : pop |
311 | // purpose : Pops BVH node index from local stack |
312 | // ======================================================================= |
313 | EOL" void pop (uint* theStack, char* thePos, uint* theValue)" |
314 | EOL" {" |
315 | EOL" *theValue = theStack[*thePos];" |
316 | EOL" (*thePos)--;" |
317 | EOL" }" |
318 | EOL |
319 | // #define BVH_MINIMIZE_MEM_LOADS |
320 | EOL |
321 | // ======================================================================= |
322 | // function : Traverse |
323 | // purpose : Finds intersection with nearest triangle |
324 | // ======================================================================= |
325 | EOL" int4 Traverse (const SRay* theRay," |
326 | EOL" __global int4* theIndices," |
327 | EOL" __global float4* theVertices," |
328 | EOL" __global float4* theNodeMinPoints," |
329 | EOL" __global float4* theNodeMaxPoints," |
330 | EOL" __global int4* theNodeDataRecords," |
331 | EOL" SIntersect* theHit)" |
332 | EOL" {" |
333 | EOL" uint aStack [32];" |
334 | EOL" char aHead = -1;" |
335 | EOL |
336 | EOL" uint aNode = 0;" // root node |
337 | EOL |
338 | EOL" float aTimeMin1;" |
339 | EOL" float aTimeMin2;" |
340 | EOL |
341 | EOL" float4 aNodeMinLft;" |
342 | EOL" float4 aNodeMaxLft;" |
343 | EOL" float4 aNodeMinRgh;" |
344 | EOL" float4 aNodeMaxRgh;" |
345 | EOL |
346 | EOL" #ifdef BVH_MINIMIZE_MEM_LOADS" |
347 | EOL" aNodeMinLft = theNodeMinPoints[aNode];" |
348 | EOL" aNodeMaxLft = theNodeMaxPoints[aNode];" |
349 | EOL" #endif" |
350 | EOL |
351 | EOL" int4 aTriangleIndex = (int4) (-1);" |
352 | EOL |
353 | EOL" theHit->Time = MAXFLOAT;" |
354 | EOL |
355 | EOL" #ifdef BVH_MINIMIZE_MEM_LOADS" |
356 | EOL" int3 aData = (int3) (1," |
357 | EOL" as_int (aNodeMinLft.w)," |
358 | EOL" as_int (aNodeMaxLft.w));" |
359 | EOL |
360 | EOL" aData = aData.y < 0 ? -aData : aData;" |
361 | EOL" #endif" |
362 | EOL |
363 | EOL" while (true)" |
364 | EOL" {" |
365 | EOL" #ifndef BVH_MINIMIZE_MEM_LOADS" |
366 | EOL" int3 aData = theNodeDataRecords[aNode].xyz;" |
367 | EOL" #endif" |
368 | EOL |
369 | EOL" if (aData.x != 1)" // if inner node |
370 | EOL" {" |
371 | EOL" aNodeMinLft = theNodeMinPoints[aData.y];" |
372 | EOL" aNodeMinRgh = theNodeMinPoints[aData.z];" |
373 | EOL" aNodeMaxLft = theNodeMaxPoints[aData.y];" |
374 | EOL" aNodeMaxRgh = theNodeMaxPoints[aData.z];" |
375 | EOL |
376 | EOL" IntersectNodes (theRay," |
377 | EOL" aNodeMinLft," |
378 | EOL" aNodeMaxLft," |
379 | EOL" aNodeMinRgh," |
380 | EOL" aNodeMaxRgh," |
381 | EOL" &aTimeMin1," |
382 | EOL" &aTimeMin2," |
383 | EOL" theHit->Time);" |
384 | EOL |
385 | EOL" const bool aHitLft = (aTimeMin1 != -MAXFLOAT);" |
386 | EOL" const bool aHitRgh = (aTimeMin2 != -MAXFLOAT);" |
387 | EOL |
388 | EOL" if (aHitLft & aHitRgh)" |
389 | EOL" {" |
390 | EOL" aNode = (aTimeMin1 < aTimeMin2) ? aData.y : aData.z;" |
391 | EOL |
392 | EOL" push (aStack, &aHead, (aTimeMin1 < aTimeMin2) ? aData.z : aData.y);" |
393 | EOL |
394 | EOL" #ifdef BVH_MINIMIZE_MEM_LOADS" |
395 | EOL" aData = (int3) (1," |
396 | EOL" as_int (aTimeMin1 < aTimeMin2 ? aNodeMinLft.w : aNodeMinRgh.w)," |
397 | EOL" as_int (aTimeMin1 < aTimeMin2 ? aNodeMaxLft.w : aNodeMaxRgh.w));" |
398 | EOL |
399 | EOL" aData = aData.y < 0 ? -aData : aData;" |
400 | EOL" #endif" |
401 | EOL" }" |
402 | EOL" else" |
403 | EOL" {" |
404 | EOL" if (aHitLft | aHitRgh)" |
405 | EOL" {" |
406 | EOL" aNode = aHitLft ? aData.y : aData.z;" |
407 | EOL |
408 | EOL" #ifdef BVH_MINIMIZE_MEM_LOADS" |
409 | EOL" aData = (int3) (1," |
410 | EOL" as_int (aHitLft ? aNodeMinLft.w : aNodeMinRgh.w)," |
411 | EOL" as_int (aHitLft ? aNodeMaxLft.w : aNodeMaxRgh.w));" |
412 | EOL |
413 | EOL" aData = aData.y < 0 ? -aData : aData;" |
414 | EOL" #endif" |
415 | EOL" }" |
416 | EOL" else" |
417 | EOL" {" |
418 | EOL" if (aHead < 0)" |
419 | EOL" return aTriangleIndex;" |
420 | EOL |
421 | EOL" pop (aStack, &aHead, &aNode);" |
422 | EOL |
423 | EOL" #ifdef BVH_MINIMIZE_MEM_LOADS" |
424 | EOL" aData = theNodeDataRecords[aNode].xyz;" |
425 | EOL" #endif" |
426 | EOL" }" |
427 | EOL" }" |
428 | EOL" }" |
429 | EOL" else " // if leaf node |
430 | EOL" {" |
431 | EOL" for (int nTri = aData.y; nTri <= aData.z; ++nTri)" |
432 | EOL" {" |
433 | EOL" int4 anIndex = theIndices[nTri];" |
434 | EOL |
435 | EOL" const float4 aP0 = theVertices[anIndex.x];" |
436 | EOL" const float4 aP1 = theVertices[anIndex.y];" |
437 | EOL" const float4 aP2 = theVertices[anIndex.z];" |
438 | EOL |
439 | EOL" float4 aNormal;" |
440 | EOL |
441 | EOL" float aTime, aU, aV;" |
442 | EOL |
443 | EOL" if (IntersectTriangle (theRay, aP0, aP1, aP2, &aNormal, &aTime, &aU, &aV) & (aTime < theHit->Time))" |
444 | EOL" {" |
445 | EOL" aTriangleIndex = anIndex;" |
446 | EOL" theHit->Normal = aNormal;" |
447 | EOL" theHit->Time = aTime;" |
448 | EOL" theHit->U = aU;" |
449 | EOL" theHit->V = aV;" |
450 | EOL" }" |
451 | EOL" }" |
452 | EOL |
453 | EOL" if (aHead < 0)" |
454 | EOL" return aTriangleIndex;" |
455 | EOL |
456 | EOL" pop (aStack, &aHead, &aNode);" |
457 | EOL |
458 | EOL" #ifdef BVH_MINIMIZE_MEM_LOADS" |
459 | EOL" aData = theNodeDataRecords[aNode].xyz;" |
460 | EOL" #endif" |
461 | EOL" }" |
462 | EOL" }" |
463 | EOL |
464 | EOL" return aTriangleIndex;" |
465 | EOL" }" |
466 | EOL |
467 | EOL" #define TRANSPARENT_SHADOW_" |
468 | EOL |
469 | // ======================================================================= |
470 | // function : TraverseShadow |
471 | // purpose : Finds intersection with any triangle |
472 | // ======================================================================= |
473 | EOL" float TraverseShadow (const SRay* theRay," |
474 | EOL" __global int4* theIndices," |
475 | EOL" __global float4* theVertices," |
476 | EOL" __global float4* materials," |
477 | EOL" __global float4* theNodeMinPoints," |
478 | EOL" __global float4* theNodeMaxPoints," |
479 | EOL" __global int4* theNodeDataRecords," |
480 | EOL" float theDistance)" |
481 | EOL" {" |
482 | EOL" uint aStack [32];" |
483 | EOL" char aHead = -1;" |
484 | EOL |
485 | EOL" uint aNode = 0;" // root node |
486 | EOL |
487 | EOL" float aFactor = 1.f;" // light attenuation factor |
488 | EOL |
489 | EOL" float aTimeMin1;" |
490 | EOL" float aTimeMin2;" |
491 | EOL |
492 | EOL" while (true)" |
493 | EOL" {" |
494 | EOL" int3 aData = theNodeDataRecords[aNode].xyz;" |
495 | EOL |
496 | EOL" if (aData.x != 1)" // if inner node |
497 | EOL" {" |
498 | EOL" IntersectNodes (theRay," |
499 | EOL" theNodeMinPoints[aData.y]," |
500 | EOL" theNodeMaxPoints[aData.y]," |
501 | EOL" theNodeMinPoints[aData.z]," |
502 | EOL" theNodeMaxPoints[aData.z]," |
503 | EOL" &aTimeMin1," |
504 | EOL" &aTimeMin2," |
505 | EOL" theDistance);" |
506 | EOL |
507 | EOL" const bool aHitLft = (aTimeMin1 != -MAXFLOAT);" |
508 | EOL" const bool aHitRgh = (aTimeMin2 != -MAXFLOAT);" |
509 | EOL |
510 | EOL" if (aHitLft & aHitRgh)" |
511 | EOL" {" |
512 | EOL" aNode = (aTimeMin1 < aTimeMin2) ? aData.y : aData.z;" |
513 | EOL |
514 | EOL" push (aStack, &aHead, (aTimeMin1 < aTimeMin2) ? aData.z : aData.y);" |
515 | EOL" }" |
516 | EOL" else" |
517 | EOL" {" |
518 | EOL" if (aHitLft | aHitRgh)" |
519 | EOL" {" |
520 | EOL" aNode = aHitLft ? aData.y : aData.z;" |
521 | EOL" }" |
522 | EOL" else" |
523 | EOL" {" |
524 | EOL" if (aHead < 0)" |
525 | EOL" return aFactor;" |
526 | EOL |
527 | EOL" pop (aStack, &aHead, &aNode);" |
528 | EOL" }" |
529 | EOL" }" |
530 | EOL" }" |
531 | EOL" else " // if leaf node |
532 | EOL" {" |
533 | EOL" for (int nTri = aData.y; nTri <= aData.z; ++nTri)" |
534 | EOL" {" |
535 | EOL" int4 anIndex = theIndices[nTri];" |
536 | EOL |
537 | EOL" const float4 aP0 = theVertices[anIndex.x];" |
538 | EOL" const float4 aP1 = theVertices[anIndex.y];" |
539 | EOL" const float4 aP2 = theVertices[anIndex.z];" |
540 | EOL |
541 | EOL" float4 aNormal;" |
542 | EOL |
543 | EOL" float aTime, aU, aV;" |
544 | EOL |
545 | EOL" if (IntersectTriangle (theRay, aP0, aP1, aP2, &aNormal, &aTime, &aU, &aV) & (aTime < theDistance))" |
546 | EOL" {" |
547 | EOL" #ifdef TRANSPARENT_SHADOW" |
548 | EOL" aFactor *= materials[7 * index.w + 6].x;" |
549 | EOL |
550 | EOL" if (aFactor < 0.1f)" |
551 | EOL" return aFactor;" |
552 | EOL" #else" |
553 | EOL" return 0.f;" |
554 | EOL" #endif" |
555 | EOL" }" |
556 | EOL" }" |
557 | EOL |
558 | EOL" if (aHead < 0)" |
559 | EOL" return aFactor;" |
560 | EOL |
561 | EOL" pop (aStack, &aHead, &aNode);" |
562 | EOL" }" |
563 | EOL" }" |
564 | EOL |
565 | EOL" return aFactor;" |
566 | EOL" }" |
567 | EOL |
568 | EOL" #define _MAX_DEPTH_ 5" |
569 | EOL |
570 | EOL" #define _MAT_SIZE_ 7" |
571 | EOL |
572 | EOL" #define _LGH_SIZE_ 3" |
573 | EOL |
574 | // ======================================================================= |
575 | // function : Raytrace |
576 | // purpose : Computes color of specified ray |
577 | // ======================================================================= |
578 | EOL" float4 Raytrace (SRay* theRay," |
579 | EOL" __read_only image2d_t theEnvMap," |
580 | EOL" __global float4* theNodeMinPoints," |
581 | EOL" __global float4* theNodeMaxPoints," |
582 | EOL" __global int4* theNodeDataRecords," |
583 | EOL" __global float4* theLightSources," |
584 | EOL" __global float4* theMaterials," |
585 | EOL" __global float4* theVertices," |
586 | EOL" __global float4* theNormals," |
587 | EOL" __global int4* theIndices," |
588 | EOL" const int theLightCount," |
589 | EOL" const float theEpsilon," |
590 | EOL" const float theRadius," |
591 | EOL" const int isShadows," |
592 | EOL" const int isReflect)" |
593 | EOL" {" |
594 | EOL" float4 aResult = (float4) (0.f, 0.f, 0.f, 0.f);" |
595 | EOL" float4 aWeight = (float4) (1.f, 1.f, 1.f, 1.f);" |
596 | EOL |
597 | EOL" SIntersect aHit;" |
598 | EOL |
599 | EOL" for (int aDepth = 0; aDepth < _MAX_DEPTH_; ++aDepth)" |
600 | EOL" {" |
601 | EOL" int4 aTriangle = Traverse (theRay," |
602 | EOL" theIndices," |
603 | EOL" theVertices," |
604 | EOL" theNodeMinPoints," |
605 | EOL" theNodeMaxPoints," |
606 | EOL" theNodeDataRecords," |
607 | EOL" &aHit);" |
608 | EOL |
609 | EOL" if (aTriangle.x < 0.f)" |
610 | EOL" {" |
611 | EOL" float aTime;" |
612 | EOL |
613 | EOL" if (aWeight.w != 0.f || !IntersectSphere (theRay, theRadius, &aTime))" |
614 | EOL" break;" |
615 | EOL |
616 | EOL" float2 aTexCoord = Latlong (fma (theRay->Direct, (float4) (aTime), theRay->Origin) * (1.f / theRadius));" |
617 | EOL |
618 | EOL" aResult += aWeight * read_imagef (theEnvMap, EnvironmentSampler, aTexCoord);" |
619 | EOL |
620 | EOL" return (float4) (aResult.x," |
621 | EOL" aResult.y," |
622 | EOL" aResult.z," |
623 | EOL" aWeight.w);" |
624 | EOL" }" |
625 | EOL |
626 | EOL" " // Compute geometric normal |
627 | EOL" float4 aGeomNormal = aHit.Normal; aGeomNormal = fast_normalize (aGeomNormal);" |
628 | EOL |
629 | EOL" " // Compute interpolated normal |
630 | EOL" float4 aNormal = SmoothNormal (theNormals, &aHit, aTriangle);" |
631 | EOL |
632 | EOL" " // Compute intersection point |
633 | EOL" float4 aPoint = theRay->Direct * aHit.Time + theRay->Origin;" |
634 | EOL |
635 | EOL" float4 aMaterAmb = theMaterials [_MAT_SIZE_ * aTriangle.w + 0];" |
636 | EOL" float4 aMaterTrn = theMaterials [_MAT_SIZE_ * aTriangle.w + 6];" |
637 | EOL |
638 | EOL" for (int nLight = 0; nLight < theLightCount; ++nLight)" |
639 | EOL" {" |
640 | EOL" float4 aLightAmbient = theLightSources [_LGH_SIZE_ * nLight];" |
641 | EOL |
642 | EOL" aResult += aWeight * aLightAmbient * aMaterAmb *" |
643 | EOL" (aMaterTrn.x * max (fabs (dot (theRay->Direct, aNormal)), 0.5f));" |
644 | EOL |
645 | EOL" if (aLightAmbient.w < 0.f)" // 'ambient' light |
646 | EOL" {" |
647 | EOL" continue;" // 'ambient' light has no another luminances |
648 | EOL" }" |
649 | EOL |
650 | EOL" float4 aLightPosition = theLightSources [_LGH_SIZE_ * nLight + 2];" |
651 | EOL |
652 | EOL" SRay aShadow;" |
653 | EOL" aShadow.Direct = aLightPosition;" |
654 | EOL |
655 | EOL" float aLightDistance = MAXFLOAT;" |
656 | EOL" if (aLightPosition.w != 0.f)" |
657 | EOL" {" |
658 | EOL" aLightDistance = length (aLightPosition - aPoint);" |
659 | EOL" aShadow.Direct = (aLightPosition - aPoint) * (1.f / aLightDistance);" |
660 | EOL" }" |
661 | EOL |
662 | EOL" aShadow.Origin = aPoint + aShadow.Direct * theEpsilon +" |
663 | EOL" aGeomNormal * copysign (theEpsilon, dot (aGeomNormal, aShadow.Direct));" |
664 | EOL |
665 | EOL" float aFactor = 1.f;" |
666 | EOL |
667 | EOL" if (isShadows)" |
668 | EOL" {" |
669 | EOL" aFactor = TraverseShadow (&aShadow," |
670 | EOL" theIndices," |
671 | EOL" theVertices," |
672 | EOL" theMaterials," |
673 | EOL" theNodeMinPoints," |
674 | EOL" theNodeMaxPoints," |
675 | EOL" theNodeDataRecords," |
676 | EOL" aLightDistance);" |
677 | EOL" }" |
678 | EOL |
679 | EOL" aResult += (aMaterTrn.x * aFactor) * aWeight * Shade (theMaterials," |
680 | EOL" aShadow.Direct," |
681 | EOL" -theRay->Direct," |
682 | EOL" aNormal," |
683 | EOL" UNIT," |
684 | EOL" aMaterTrn.y," |
685 | EOL" aTriangle.w);" |
686 | EOL" }" |
687 | EOL |
688 | EOL" if (aMaterTrn.y > 0.f)" |
689 | EOL" {" |
690 | EOL" aWeight *= aMaterTrn.y;" |
691 | EOL" }" |
692 | EOL" else" |
693 | EOL" {" |
694 | EOL" float4 aMaterRef = theMaterials [_MAT_SIZE_ * aTriangle.w + 4];" |
695 | EOL" aWeight *= isReflect ? aMaterRef : ZERO;" |
696 | EOL |
697 | EOL" theRay->Direct -= 2.f * dot (theRay->Direct, aNormal) * aNormal;" |
698 | EOL |
699 | EOL" float aDdotN = dot (theRay->Direct, aGeomNormal);" |
700 | EOL" if (aDdotN < 0.f)" |
701 | EOL" theRay->Direct -= aDdotN * aGeomNormal;" |
702 | EOL" }" |
703 | EOL |
704 | EOL" if (aWeight.x < 0.1f && aWeight.y < 0.1f && aWeight.z < 0.1f)" |
705 | EOL" {" |
706 | EOL" return (float4) (aResult.x," |
707 | EOL" aResult.y," |
708 | EOL" aResult.z," |
709 | EOL" aWeight.w);" |
710 | EOL" }" |
711 | EOL |
712 | EOL" theRay->Origin = theRay->Direct * theEpsilon + aPoint;" |
713 | EOL" }" |
714 | EOL |
715 | EOL" return (float4) (aResult.x," |
716 | EOL" aResult.y," |
717 | EOL" aResult.z," |
718 | EOL" aWeight.w);" |
719 | EOL" }" |
720 | EOL |
721 | EOL |
722 | /////////////////////////////////////////////////////////////////////////////// |
723 | // Ray tracing kernel functions |
724 | EOL |
725 | // ======================================================================= |
726 | // function : Main |
727 | // purpose : Computes pixel color using ray-tracing |
728 | // ======================================================================= |
729 | EOL" __kernel void Main (__write_only image2d_t theOutput," |
730 | EOL" __read_only image2d_t theEnvMap," |
731 | EOL" __global float4* theNodeMinPoints," |
732 | EOL" __global float4* theNodeMaxPoints," |
733 | EOL" __global int4* theNodeDataRecords," |
734 | EOL" __global float4* theLightSources," |
735 | EOL" __global float4* theMaterials," |
736 | EOL" __global float4* theVertices," |
737 | EOL" __global float4* theNormals," |
738 | EOL" __global int4* theIndices," |
739 | EOL" const float16 theOrigins," |
740 | EOL" const float16 theDirects," |
741 | EOL" const int theLightCount," |
742 | EOL" const float theEpsilon," |
743 | EOL" const float theRadius," |
744 | EOL" const int isShadows," |
745 | EOL" const int isReflect," |
746 | EOL" const int theSizeX," |
747 | EOL" const int theSizeY)" |
748 | EOL" {" |
749 | EOL" const int aX = get_global_id (0);" |
750 | EOL" const int aY = get_global_id (1);" |
751 | EOL |
752 | EOL" if (aX >= theSizeX || aY >= theSizeY)" |
753 | EOL" return;" |
754 | EOL |
755 | EOL" private SRay aRay;" |
756 | EOL |
757 | EOL" GenerateRay (&aRay," |
758 | EOL" aX," |
759 | EOL" aY," |
760 | EOL" theSizeX," |
761 | EOL" theSizeY," |
762 | EOL" theOrigins," |
763 | EOL" theDirects);" |
764 | EOL |
765 | EOL" float4 aBoxMin = theNodeMinPoints[0] - (float4) (theEpsilon, theEpsilon, theEpsilon, 0.f);" |
766 | EOL" float4 aBoxMax = theNodeMaxPoints[0] + (float4) (theEpsilon, theEpsilon, theEpsilon, 0.f);" |
767 | EOL |
768 | EOL" float aTimeStart;" |
769 | EOL" float aTimeFinal;" |
770 | EOL |
771 | EOL" float4 aColor = (float4) (0.f, 0.f, 0.f, 1.f);" |
772 | EOL |
773 | EOL" if (IntersectBox (&aRay, aBoxMin, aBoxMax, &aTimeStart, &aTimeFinal))" |
774 | EOL" {" |
775 | EOL" aRay.Origin = fma (aRay.Direct, (float4) (aTimeStart), aRay.Origin);" |
776 | EOL |
777 | EOL" aColor = Raytrace (&aRay," |
778 | EOL" theEnvMap," |
779 | EOL" theNodeMinPoints," |
780 | EOL" theNodeMaxPoints," |
781 | EOL" theNodeDataRecords," |
782 | EOL" theLightSources," |
783 | EOL" theMaterials," |
784 | EOL" theVertices," |
785 | EOL" theNormals," |
786 | EOL" theIndices," |
787 | EOL" theLightCount," |
788 | EOL" theEpsilon," |
789 | EOL" theRadius," |
790 | EOL" isShadows," |
791 | EOL" isReflect);" |
792 | EOL" }" |
793 | EOL |
794 | EOL" write_imagef (theOutput, (int2) (aX, aY), aColor);" |
795 | EOL" }" |
796 | EOL |
797 | EOL" const sampler_t OutputSampler =" |
798 | EOL" CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;" |
799 | EOL |
800 | EOL" #define _LUM_DELTA_ 0.075f" |
801 | EOL |
802 | EOL" #define AA_MAX 0.559017f" |
803 | EOL" #define AA_MIN 0.186339f" |
804 | EOL |
805 | // ======================================================================= |
806 | // function : MainAntialiased |
807 | // purpose : Performs adaptive sub-pixel rendering |
808 | // ======================================================================= |
809 | EOL" __kernel void MainAntialiased ( __read_only image2d_t theInput," |
810 | EOL" __write_only image2d_t theOutput," |
811 | EOL" __read_only image2d_t theEnvMap," |
812 | EOL" __global float4* theNodeMinPoints," |
813 | EOL" __global float4* theNodeMaxPoints," |
814 | EOL" __global int4* theNodeDataRecords," |
815 | EOL" __global float4* theLightSources," |
816 | EOL" __global float4* theMaterials," |
817 | EOL" __global float4* theVertices," |
818 | EOL" __global float4* theNormals," |
819 | EOL" __global int4* theIndices," |
820 | EOL" const float16 theOrigins," |
821 | EOL" const float16 theDirects," |
822 | EOL" const int theLightCount," |
823 | EOL" const float theEpsilon," |
824 | EOL" const float theRadius," |
825 | EOL" const int isShadows," |
826 | EOL" const int isReflect," |
827 | EOL" const int theSizeX," |
828 | EOL" const int theSizeY )" |
829 | EOL" {" |
830 | EOL" const int aX = get_global_id (0);" |
831 | EOL" const int aY = get_global_id (1);" |
832 | EOL |
833 | EOL" if (aX >= theSizeX || aY >= theSizeY)" |
834 | EOL" return;" |
835 | EOL |
836 | EOL" float4 aClr0 = read_imagef (theInput, OutputSampler, (float2) (aX + 0, aY + 0));" |
837 | EOL" float4 aClr1 = read_imagef (theInput, OutputSampler, (float2) (aX + 0, aY - 1));" |
838 | EOL" float4 aClr2 = read_imagef (theInput, OutputSampler, (float2) (aX + 0, aY + 1));" |
839 | EOL |
840 | EOL" float4 aClr3 = read_imagef (theInput, OutputSampler, (float2) (aX + 1, aY + 0));" |
841 | EOL" float4 aClr4 = read_imagef (theInput, OutputSampler, (float2) (aX + 1, aY - 1));" |
842 | EOL" float4 aClr5 = read_imagef (theInput, OutputSampler, (float2) (aX + 1, aY + 1));" |
843 | EOL |
844 | EOL" float4 aClr6 = read_imagef (theInput, OutputSampler, (float2) (aX - 1, aY + 0));" |
845 | EOL" float4 aClr7 = read_imagef (theInput, OutputSampler, (float2) (aX - 1, aY - 1));" |
846 | EOL" float4 aClr8 = read_imagef (theInput, OutputSampler, (float2) (aX - 1, aY + 1));" |
847 | EOL |
848 | EOL" aClr1 = (aClr1.w == 1.f) ? -UNIT : aClr1;" |
849 | EOL" aClr2 = (aClr2.w == 1.f) ? -UNIT : aClr2;" |
850 | EOL" aClr3 = (aClr3.w == 1.f) ? -UNIT : aClr3;" |
851 | EOL" aClr4 = (aClr4.w == 1.f) ? -UNIT : aClr4;" |
852 | EOL" aClr5 = (aClr5.w == 1.f) ? -UNIT : aClr5;" |
853 | EOL" aClr6 = (aClr6.w == 1.f) ? -UNIT : aClr6;" |
854 | EOL" aClr7 = (aClr7.w == 1.f) ? -UNIT : aClr7;" |
855 | EOL" aClr8 = (aClr8.w == 1.f) ? -UNIT : aClr8;" |
856 | EOL |
857 | EOL" float aLum = (aClr0.w == 1.f) ? -1.f : (0.2126f * aClr0.x + 0.7152f * aClr0.y + 0.0722f * aClr0.z);" |
858 | EOL |
859 | EOL |
860 | EOL" bool render = fabs (0.2126f * aClr1.x + 0.7152f * aClr1.y + 0.0722f * aClr1.z - aLum) > _LUM_DELTA_ ||" |
861 | EOL" fabs (0.2126f * aClr2.x + 0.7152f * aClr2.y + 0.0722f * aClr2.z - aLum) > _LUM_DELTA_ ||" |
862 | EOL" fabs (0.2126f * aClr3.x + 0.7152f * aClr3.y + 0.0722f * aClr3.z - aLum) > _LUM_DELTA_ ||" |
863 | EOL" fabs (0.2126f * aClr4.x + 0.7152f * aClr4.y + 0.0722f * aClr4.z - aLum) > _LUM_DELTA_ ||" |
864 | EOL" fabs (0.2126f * aClr5.x + 0.7152f * aClr5.y + 0.0722f * aClr5.z - aLum) > _LUM_DELTA_ ||" |
865 | EOL" fabs (0.2126f * aClr6.x + 0.7152f * aClr6.y + 0.0722f * aClr6.z - aLum) > _LUM_DELTA_ ||" |
866 | EOL" fabs (0.2126f * aClr7.x + 0.7152f * aClr7.y + 0.0722f * aClr7.z - aLum) > _LUM_DELTA_ ||" |
867 | EOL" fabs (0.2126f * aClr8.x + 0.7152f * aClr8.y + 0.0722f * aClr8.z - aLum) > _LUM_DELTA_;" |
868 | EOL |
869 | EOL" float4 aColor = aClr0;" |
870 | EOL |
871 | EOL" private SRay aRay;" |
872 | EOL |
873 | EOL" const float4 aBoxMin = theNodeMinPoints[0] - (float4) (theEpsilon, theEpsilon, theEpsilon, 0.f);" |
874 | EOL" const float4 aBoxMax = theNodeMaxPoints[0] + (float4) (theEpsilon, theEpsilon, theEpsilon, 0.f);" |
875 | EOL |
876 | EOL" if (render)" |
877 | EOL" {" |
878 | EOL" for (int aSample = 0; aSample <= 3; ++aSample)" |
879 | EOL" {" |
880 | EOL" float fX = aX, fY = aY;" |
881 | EOL |
882 | EOL" if (aSample == 0)" |
883 | EOL" {" |
884 | EOL" fX -= AA_MIN; fY -= AA_MAX;" |
885 | EOL" }" |
886 | EOL" else if (aSample == 1)" |
887 | EOL" {" |
888 | EOL" fX -= AA_MAX; fY += AA_MIN;" |
889 | EOL" }" |
890 | EOL" else if (aSample == 2)" |
891 | EOL" {" |
892 | EOL" fX += AA_MIN; fY += AA_MAX;" |
893 | EOL" }" |
894 | EOL" else" |
895 | EOL" {" |
896 | EOL" fX += AA_MAX; fY -= AA_MIN;" |
897 | EOL" }" |
898 | EOL |
899 | EOL" GenerateRay (&aRay," |
900 | EOL" fX," |
901 | EOL" fY," |
902 | EOL" theSizeX," |
903 | EOL" theSizeY," |
904 | EOL" theOrigins," |
905 | EOL" theDirects);" |
906 | EOL |
907 | EOL" float aTimeStart;" |
908 | EOL" float aTimeFinal;" |
909 | EOL |
910 | EOL" if (IntersectBox (&aRay, aBoxMin, aBoxMax, &aTimeStart, &aTimeFinal))" |
911 | EOL" {" |
912 | EOL" aRay.Origin = fma (aRay.Direct, (float4) (aTimeStart), aRay.Origin);" |
913 | EOL |
914 | EOL" aColor += Raytrace (&aRay," |
915 | EOL" theEnvMap," |
916 | EOL" theNodeMinPoints," |
917 | EOL" theNodeMaxPoints," |
918 | EOL" theNodeDataRecords," |
919 | EOL" theLightSources," |
920 | EOL" theMaterials," |
921 | EOL" theVertices," |
922 | EOL" theNormals," |
923 | EOL" theIndices," |
924 | EOL" theLightCount," |
925 | EOL" theEpsilon," |
926 | EOL" theRadius," |
927 | EOL" isShadows," |
928 | EOL" isReflect);" |
929 | EOL" }" |
930 | EOL" else" |
931 | EOL" aColor += (float4) (0.f, 0.f, 0.f, 1.f);" |
932 | EOL" }" |
933 | EOL |
934 | EOL" aColor *= 1.f / 5.f;" |
935 | EOL" }" |
936 | EOL |
937 | EOL" write_imagef (theOutput, (int2) (aX, aY), aColor);" |
938 | EOL" }"; |
939 | |
940 | #endif |