diff --git a/components/renderers/cpp/src/triangle_render.cu b/components/renderers/cpp/src/triangle_render.cu index 5887d8233a5f5333c0662bff570bd8a62caeb86b..e87a1009aa0589ce93f1ab70ebc3cb11acc25aef 100644 --- a/components/renderers/cpp/src/triangle_render.cu +++ b/components/renderers/cpp/src/triangle_render.cu @@ -11,6 +11,85 @@ using ftl::render::SplatParams; __device__ inline float length2(int dx, int dy) { return dx*dx + dy*dy; } +__device__ inline float cross(const float2 &a, const float2 &b) { + return a.x*b.y - a.y*b.x; +} + +__device__ inline bool within(float x) { + return 0.0f <= x <= 1.0f; +} + +__device__ inline bool operator==(const float2 &a, const float2 &b) { + return a.x == b.x && a.y == b.y; +} + +__device__ inline bool insideTriangle(const float2 &a, const float2 &b, const float2 &c, const float2 &p) +{ + float det = (b.y - c.y)*(a.x - c.x) + (c.x - b.x)*(a.y - c.y); + float factor_alpha = (b.y - c.y)*(p.x - c.x) + (c.x - b.x)*(p.y - c.y); + float factor_beta = (c.y - a.y)*(p.x - c.x) + (a.x - c.x)*(p.y - c.y); + float alpha = factor_alpha / det; + float beta = factor_beta / det; + float gamma = 1.0 - alpha - beta; + + return p == a || p == b || p == c || (within(alpha) && within(beta) && within(gamma)); +} + +__device__ inline void swap(short2 &a, short2 &b) { + short2 t = a; + a = b; + b = t; +} + +__device__ void drawLine(TextureObject<int> &depth_out, int y, int x1, int x2, float d) { + for (int x=x1; x<=x2; ++x) { + if (x < 0) continue; + if (x >= depth_out.width()) return; + atomicMin(&depth_out(x,y), int(d*1000.0f)); + } +} + +/** + * Calculate the signed area of a given triangle. + */ +__device__ static inline + float calculateSignedArea(const short2 &a, const short2 &b, const short2 &c) { + return 0.5f * (float(c.x - a.x) * float(b.y - a.y) - float(b.x - a.x) * float(c.y - a.y)); + } + +// CHECKITOUT +/** + * Helper function for calculating barycentric coordinates. + */ + __device__ static inline + float calculateBarycentricCoordinateValue(const short2 &a, const short2 &b, const short2 &c, const short2 (&tri)[3]) { + return calculateSignedArea(a,b,c) / calculateSignedArea(tri[0], tri[1], tri[2]); + } + + // CHECKITOUT + /** + * Calculate barycentric coordinates. + * TODO: Update to handle triangles coming in and not the array + */ +__device__ static + float3 calculateBarycentricCoordinate(const short2 (&tri)[3], const short2 &point) { + float beta = calculateBarycentricCoordinateValue(tri[0], point, tri[2], tri); + float gamma = calculateBarycentricCoordinateValue(tri[0], tri[1], point, tri); + float alpha = 1.0 - beta - gamma; + return make_float3(alpha, beta, gamma); + } + + // CHECKITOUT + /** + * Check if a barycentric coordinate is within the boundaries of a triangle. + */ + __host__ __device__ static + bool isBarycentricCoordInBounds(const float3 &barycentricCoord) { + return barycentricCoord.x >= 0.0 && barycentricCoord.x <= 1.0 && + barycentricCoord.y >= 0.0 && barycentricCoord.y <= 1.0 && + barycentricCoord.z >= 0.0 && barycentricCoord.z <= 1.0; + } + /* * Convert source screen position to output screen coordinates. */ @@ -30,15 +109,63 @@ __device__ inline float length2(int dx, int dy) { return dx*dx + dy*dy; } d[2] = depth_in.tex2D(x+A,y+(1-B)); // Is this triangle valid - if (fabs(d[0] - d[1]) > 0.04f || fabs(d[0] - d[2]) > 0.04f) return; + if (fabs(d[0] - d[1]) > 0.04f || fabs(d[0] - d[2]) > 0.04f || fabs(d[1] - d[2]) > 0.04f) return; if (d[0] < params.camera.minDepth || d[0] > params.camera.maxDepth) return; - short2 s[3]; - s[0] = screen.tex2D(x+A,y+B); - s[1] = screen.tex2D(x+(1-A),y+B); - s[2] = screen.tex2D(x+A,y+(1-B)); + short2 v[3]; + v[0] = screen.tex2D(x+A,y+B); + v[1] = screen.tex2D(x+(1-A),y+B); + v[2] = screen.tex2D(x+A,y+(1-B)); + + const int minX = min(v[0].x, min(v[1].x, v[2].x)); + const int minY = min(v[0].y, min(v[1].y, v[2].y)); + const int maxX = max(v[0].x, max(v[1].x, v[2].x)); + const int maxY = max(v[0].y, max(v[1].y, v[2].y)); + + //if ((maxX - minX) * (maxY - minY) > 200) return; + int incx = ((maxX - minX) / 20) + 1; + int incy = ((maxY - minY) / 20) + 1; + + float2 vs0 = make_float2(v[0].x, v[0].y); + float2 vs1 = make_float2(v[1].x, v[1].y); + float2 vs2 = make_float2(v[2].x, v[2].y); + + for (int sy=minY; sy <= maxY; sy+=incy) { + for (int sx=minX; sx <= maxX; sx+=incx) { + if (sx >= params.camera.width || sx < 0 || sy >= params.camera.height || sy < 0) continue; + //float2 q = make_float2(sx, sy); + //float s = det(q - vs0, vs1) / det(vs0, vs1); //cross(q, vs2) / cross(vs1, vs2); + //float t = det(vs0, q - vs1) / det(vs0, vs1); //cross(vs1, q) / cross(vs1, vs2); + + float3 baryCentricCoordinate = calculateBarycentricCoordinate(v, make_short2(sx, sy)); + + if (isBarycentricCoordInBounds(baryCentricCoordinate)) { + //if (s >= 0 && t >= 0 && ss+t <= 1) { + //if (insideTriangle(vs0,vs1,vs2, make_float2(sx,sy))) { + /*float dist1 = length2(sx - s[0].x, sy - s[0].y); + float dist2 = length2(sx - s[1].x, sy - s[1].y); + float dist3 = length2(sx - s[2].x, sy - s[2].y); + + float maxlen = max(dist1, max(dist2, dist3)); + if (maxlen > 0.0f) { + dist1 = 1.0f - dist1 / maxlen; + dist2 = 1.0f - dist2 / maxlen; + dist3 = 1.0f - dist3 / maxlen; + } + float new_depth = (maxlen == 0.0f) ? d[0] : (d[0]*dist1 + d[1]*dist2 + d[2]*dist3) / (dist1+dist2+dist3); + //if (new_depth < params.camera.minDepth || new_depth > params.camera.maxDepth) continue;*/ + + float new_depth = d[0]; + + atomicMin(&depth_out(sx,sy), int(new_depth*1000.0f)); + } + } + } + + + // OLD - const int dx = (A) ? -1 : 1; + /*const int dx = (A) ? -1 : 1; const int dy = (B) ? -1 : 1; s[1].x = (A) ? s[0].x - s[1].x : s[1].x - s[0].x; @@ -65,7 +192,7 @@ __device__ inline float length2(int dx, int dy) { return dx*dx + dy*dy; } atomicMin(&depth_out(dx*sx+s[0].x,dy*sy+s[0].y), int(new_depth*1000.0f)); } - } + }*/ } void ftl::cuda::triangle_render1(TextureObject<float> &depth_in, TextureObject<int> &depth_out, TextureObject<short2> &screen, const SplatParams ¶ms, cudaStream_t stream) {