/
redgpu
/
ispc
Обзор
Документация
Войти
/
redgpu
/
ispc
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
trunk-artifacts
examples/cpu/rt/rt.ispc
285 строк
9 KB
Dmitry Babokin
Remove the phrase "All rights reserved."
01 апр 2023, 03:48
01 апр 2023, 03:48
33bd2b4
Код
Авторство
О чём код?
/* Copyright (c) 2010-2023, Intel Corporation SPDX-License-Identifier: BSD-3-Clause */ #define bool int typedef float<3> float3; struct Ray { float3 origin, dir, invDir; uniform unsigned int dirIsNeg[3]; float mint, maxt; int hitId; }; struct Triangle { float p[3][4]; int id; int pad[3]; }; struct LinearBVHNode { float bounds[2][3]; unsigned int offset; // num primitives for leaf, second child for interior unsigned int8 nPrimitives; unsigned int8 splitAxis; unsigned int16 pad; }; static inline float3 Cross(const float3 v1, const float3 v2) { float v1x = v1.x, v1y = v1.y, v1z = v1.z; float v2x = v2.x, v2y = v2.y, v2z = v2.z; float3 ret; ret.x = (v1y * v2z) - (v1z * v2y); ret.y = (v1z * v2x) - (v1x * v2z); ret.z = (v1x * v2y) - (v1y * v2x); return ret; } static inline float Dot(const float3 a, const float3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; } static void generateRay(uniform const float raster2camera[4][4], uniform const float camera2world[4][4], float x, float y, Ray &ray) { ray.mint = 0.f; ray.maxt = 1e30f; ray.hitId = 0; // transform raster coordinate (x, y, 0) to camera space float camx = raster2camera[0][0] * x + raster2camera[0][1] * y + raster2camera[0][3]; float camy = raster2camera[1][0] * x + raster2camera[1][1] * y + raster2camera[1][3]; float camz = raster2camera[2][3]; float camw = raster2camera[3][3]; camx /= camw; camy /= camw; camz /= camw; ray.dir.x = camera2world[0][0] * camx + camera2world[0][1] * camy + camera2world[0][2] * camz; ray.dir.y = camera2world[1][0] * camx + camera2world[1][1] * camy + camera2world[1][2] * camz; ray.dir.z = camera2world[2][0] * camx + camera2world[2][1] * camy + camera2world[2][2] * camz; ray.origin.x = camera2world[0][3] / camera2world[3][3]; ray.origin.y = camera2world[1][3] / camera2world[3][3]; ray.origin.z = camera2world[2][3] / camera2world[3][3]; ray.invDir = 1.f / ray.dir; ray.dirIsNeg[0] = any(ray.invDir.x < 0) ? 1 : 0; ray.dirIsNeg[1] = any(ray.invDir.y < 0) ? 1 : 0; ray.dirIsNeg[2] = any(ray.invDir.z < 0) ? 1 : 0; } static bool BBoxIntersect(const uniform float bounds[2][3], const Ray &ray) { uniform float3 bounds0 = { bounds[0][0], bounds[0][1], bounds[0][2] }; uniform float3 bounds1 = { bounds[1][0], bounds[1][1], bounds[1][2] }; float t0 = ray.mint, t1 = ray.maxt; // Check all three axis-aligned slabs. Don't try to early out; it's // not worth the trouble float3 tNear = (bounds0 - ray.origin) * ray.invDir; float3 tFar = (bounds1 - ray.origin) * ray.invDir; if (tNear.x > tFar.x) { float tmp = tNear.x; tNear.x = tFar.x; tFar.x = tmp; } t0 = max(tNear.x, t0); t1 = min(tFar.x, t1); if (tNear.y > tFar.y) { float tmp = tNear.y; tNear.y = tFar.y; tFar.y = tmp; } t0 = max(tNear.y, t0); t1 = min(tFar.y, t1); if (tNear.z > tFar.z) { float tmp = tNear.z; tNear.z = tFar.z; tFar.z = tmp; } t0 = max(tNear.z, t0); t1 = min(tFar.z, t1); return (t0 <= t1); } static bool TriIntersect(const uniform Triangle &tri, Ray &ray) { uniform float3 p0 = { tri.p[0][0], tri.p[0][1], tri.p[0][2] }; uniform float3 p1 = { tri.p[1][0], tri.p[1][1], tri.p[1][2] }; uniform float3 p2 = { tri.p[2][0], tri.p[2][1], tri.p[2][2] }; uniform float3 e1 = p1 - p0; uniform float3 e2 = p2 - p0; float3 s1 = Cross(ray.dir, e2); float divisor = Dot(s1, e1); bool hit = true; if (divisor == 0.) hit = false; float invDivisor = 1.f / divisor; // Compute first barycentric coordinate float3 d = ray.origin - p0; float b1 = Dot(d, s1) * invDivisor; if (b1 < 0. || b1 > 1.) hit = false; // Compute second barycentric coordinate float3 s2 = Cross(d, e1); float b2 = Dot(ray.dir, s2) * invDivisor; if (b2 < 0. || b1 + b2 > 1.) hit = false; // Compute _t_ to intersection point float t = Dot(e2, s2) * invDivisor; if (t < ray.mint || t > ray.maxt) hit = false; if (hit) { ray.maxt = t; ray.hitId = tri.id; } return hit; } bool BVHIntersect(const uniform LinearBVHNode nodes[], const uniform Triangle tris[], Ray &r) { Ray ray = r; bool hit = false; // Follow ray through BVH nodes to find primitive intersections uniform int todoOffset = 0, nodeNum = 0; uniform int todo[64]; while (true) { // Check ray against BVH node uniform LinearBVHNode node = nodes[nodeNum]; if (any(BBoxIntersect(node.bounds, ray))) { uniform unsigned int nPrimitives = node.nPrimitives; if (nPrimitives > 0) { // Intersect ray with primitives in leaf BVH node uniform unsigned int primitivesOffset = node.offset; for (uniform unsigned int i = 0; i < nPrimitives; ++i) { if (TriIntersect(tris[primitivesOffset+i], ray)) hit = true; } if (todoOffset == 0) break; nodeNum = todo[--todoOffset]; } else { // Put far BVH node on _todo_ stack, advance to near node if (r.dirIsNeg[node.splitAxis]) { todo[todoOffset++] = nodeNum + 1; nodeNum = node.offset; } else { todo[todoOffset++] = node.offset; nodeNum = nodeNum + 1; } } } else { if (todoOffset == 0) break; nodeNum = todo[--todoOffset]; } } r.maxt = ray.maxt; r.hitId = ray.hitId; return hit; } static void raytrace_tile(uniform int x0, uniform int x1, uniform int y0, uniform int y1, uniform int width, uniform int height, uniform int baseWidth, uniform int baseHeight, const uniform float raster2camera[4][4], const uniform float camera2world[4][4], uniform float image[], uniform int id[], const uniform LinearBVHNode nodes[], const uniform Triangle triangles[]) { uniform float widthScale = (float)(baseWidth) / (float)(width); uniform float heightScale = (float)(baseHeight) / (float)(height); foreach_tiled (y = y0 ... y1, x = x0 ... x1) { Ray ray; generateRay(raster2camera, camera2world, x*widthScale, y*heightScale, ray); BVHIntersect(nodes, triangles, ray); int offset = y * width + x; #pragma ignore warning(perf) image[offset] = ray.maxt; #pragma ignore warning(perf) id[offset] = ray.hitId; } } export void raytrace_ispc(uniform int width, uniform int height, uniform int baseWidth, uniform int baseHeight, const uniform float raster2camera[4][4], const uniform float camera2world[4][4], uniform float image[], uniform int id[], const uniform LinearBVHNode nodes[], const uniform Triangle triangles[]) { raytrace_tile(0, width, 0, height, width, height, baseWidth, baseHeight, raster2camera, camera2world, image, id, nodes, triangles); } task void raytrace_tile_task(uniform int width, uniform int height, uniform int baseWidth, uniform int baseHeight, const uniform float raster2camera[4][4], const uniform float camera2world[4][4], uniform float image[], uniform int id[], const uniform LinearBVHNode nodes[], const uniform Triangle triangles[]) { uniform int dx = 16, dy = 16; // must match dx, dy below uniform int xBuckets = (width + (dx-1)) / dx; uniform int x0 = (taskIndex % xBuckets) * dx; uniform int x1 = min(x0 + dx, width); uniform int y0 = (taskIndex / xBuckets) * dy; uniform int y1 = min(y0 + dy, height); raytrace_tile(x0, x1, y0, y1, width, height, baseWidth, baseHeight, raster2camera, camera2world, image, id, nodes, triangles); } export void raytrace_ispc_tasks(uniform int width, uniform int height, uniform int baseWidth, uniform int baseHeight, const uniform float raster2camera[4][4], const uniform float camera2world[4][4], uniform float image[], uniform int id[], const uniform LinearBVHNode nodes[], const uniform Triangle triangles[]) { uniform int dx = 16, dy = 16; uniform int xBuckets = (width + (dx-1)) / dx; uniform int yBuckets = (height + (dy-1)) / dy; uniform int nTasks = xBuckets * yBuckets; launch[nTasks] raytrace_tile_task(width, height, baseWidth, baseHeight, raster2camera, camera2world, image, id, nodes, triangles); }