private static HitRecord GetTriangleHit(Ray r, dWorldBuffer world, dGPUMesh mesh, float nearerThan) { Triangle t = new Triangle(); float currentNearestDist = nearerThan; int NcurrentIndex = -1; int material = 0; float Ndet = 0; for (int i = 0; i < mesh.triangleCount; i++) { t = mesh.GetTriangle(i, world); Vec3 tuVec = t.uVector(); Vec3 tvVec = t.vVector(); Vec3 pVec = Vec3.cross(r.b, tvVec); float det = Vec3.dot(tuVec, pVec); if (XMath.Abs(det) < nearerThan) { float invDet = 1.0f / det; Vec3 tVec = r.a - t.Vert0; float u = Vec3.dot(tVec, pVec) * invDet; Vec3 qVec = Vec3.cross(tVec, tuVec); float v = Vec3.dot(r.b, qVec) * invDet; if (u > 0 && u <= 1.0f && v > 0 && u + v <= 1.0f) { float temp = Vec3.dot(tvVec, qVec) * invDet; if (temp < currentNearestDist) { currentNearestDist = temp; NcurrentIndex = i; Ndet = det; material = t.MaterialID; } } } } if (NcurrentIndex == -1) { return(new HitRecord(float.MaxValue, new Vec3(), new Vec3(), false, -1, -1)); } else { if (Ndet < 0) { return(new HitRecord(currentNearestDist, r.pointAtParameter(currentNearestDist), -t.faceNormal(), true, material, NcurrentIndex)); } else { return(new HitRecord(currentNearestDist, r.pointAtParameter(currentNearestDist), t.faceNormal(), false, material, NcurrentIndex)); } } }
public Triangle GetTriangle(int index, dWorldBuffer world) { int triangleIndex = index * 3; int vertexStartIndex0 = world.triangles[triangleIndex] * 3; int vertexStartIndex1 = world.triangles[triangleIndex + 1] * 3; int vertexStartIndex2 = world.triangles[triangleIndex + 2] * 3; Vec3 Vert0 = new Vec3(world.verticies[vertexStartIndex0], world.verticies[vertexStartIndex0 + 1], world.verticies[vertexStartIndex0 + 2]) + position; Vec3 Vert1 = new Vec3(world.verticies[vertexStartIndex1], world.verticies[vertexStartIndex1 + 1], world.verticies[vertexStartIndex1 + 2]) + position; Vec3 Vert2 = new Vec3(world.verticies[vertexStartIndex2], world.verticies[vertexStartIndex2 + 1], world.verticies[vertexStartIndex2 + 2]) + position; return(new Triangle(Vert0, Vert1, Vert2, world.triangleMaterials[index])); }
public static void RenderKernel(Index2 id, dFramebuffer framebuffer, dWorldBuffer world, Camera camera, int rngOffset) { int x = id.X; int y = id.Y; int index = ((y * camera.width) + x); //there is probably a better way to do this, but it seems to work. seed = the tick * a large prime xor (index + 1) * even larger prime XorShift64Star rng = new XorShift64Star((((ulong)(rngOffset + 1) * 3727177) ^ ((ulong)(index + 1) * 113013596393))); //XorShift64Star rng = new XorShift64Star(); Ray ray = camera.GetRay(x + rng.NextFloat(), y + rng.NextFloat()); ColorRay(index, ray, framebuffer, world, rng, camera); }
private static HitRecord GetWorldHit(Ray r, dWorldBuffer world, float minT) { HitRecord rec = GetSphereHit(r, world.spheres, minT); HitRecord vRec = world.VoxelChunk.hit(r, minT, rec.t); HitRecord triRec = GetMeshHit(r, world, vRec.t); if (rec.t < vRec.t && rec.t < triRec.t) { return(rec); } else if (vRec.t < rec.t && vRec.t < triRec.t) { return(vRec); } else { return(triRec); } }
private static HitRecord GetMeshHit(Ray r, dWorldBuffer world, float nearerThan) { float dist = nearerThan; HitRecord rec = new HitRecord(float.MaxValue, new Vec3(), new Vec3(), false, -1, -1); for (int i = 0; i < world.meshes.Length; i++) { if (world.meshes[i].aabb.hit(r, nearerThan, dist)) { HitRecord meshHit = GetTriangleHit(r, world, world.meshes[i], dist); if (meshHit.t < dist) { dist = meshHit.t; rec = meshHit; } } } return(rec); }
public static void PerPixelRayIntersectionMethod(Index2 pixel, CanvasData data, dWorldBuffer world, Camera camera) { int x = pixel.X; int y = pixel.Y; Ray ray = camera.GetRay(x, y); HitRecord hit = default; hit.t = float.MaxValue; for (int i = 0; i < world.meshes.Length; i++) { if (world.meshes[i].aabb.hit(ray, 0.001f, hit.t)) { HitRecord meshHit = GetTriangleHit(ray, world, world.meshes[i], hit.t); if (meshHit.drawableID != -1) { hit = meshHit; data.setColor(pixel, getDebugColor(meshHit.drawableID)); } } } }
private static void ColorRay(int index, Ray ray, dFramebuffer framebuffer, dWorldBuffer world, XorShift64Star rng, Camera camera) { Vec3 attenuation = new Vec3(1f, 1f, 1f); Vec3 lighting = new Vec3(); Ray working = ray; bool attenuationHasValue = false; float minT = 0.1f; for (int i = 0; i < camera.maxBounces; i++) { HitRecord rec = GetWorldHit(working, world, minT); if (rec.materialID == -1) { if (i == 0 || attenuationHasValue) { framebuffer.DrawableIDBuffer[index] = -2; } float t = 0.5f * (working.b.y + 1.0f); attenuation *= (1.0f - t) * new Vec3(1.0f, 1.0f, 1.0f) + t * new Vec3(0.5f, 0.7f, 1.0f); break; } else { if (i == 0) { framebuffer.ZBuffer[index] = rec.t; framebuffer.DrawableIDBuffer[index] = rec.drawableID; } ScatterRecord sRec = Scatter(working, rec, rng, world.materials, minT); if (sRec.materialID != -1) { attenuationHasValue = sRec.mirrorSkyLightingFix; attenuation *= sRec.attenuation; working = sRec.scatterRay; } else { framebuffer.DrawableIDBuffer[index] = -1; break; } } for (int j = 0; j < world.lightSphereIDs.Length; j++) { Sphere s = world.spheres[world.lightSphereIDs[j]]; Vec3 lightDir = s.center - rec.p; HitRecord shadowRec = GetWorldHit(new Ray(rec.p, lightDir), world, minT); if (shadowRec.materialID != -1 && (shadowRec.p - rec.p).length() > lightDir.length() - (s.radius * 1.1f)) // the second part of this IF could probably be much more efficent { MaterialData material = world.materials[shadowRec.materialID]; if (material.type != 1) { lightDir = Vec3.unitVector(lightDir); lighting += material.color * XMath.Max(0.0f, Vec3.dot(lightDir, rec.normal)); lighting *= XMath.Pow(XMath.Max(0.0f, Vec3.dot(-Vec3.reflect(rec.normal, -lightDir), ray.b)), material.reflectivity) * material.color; } } } } int rIndex = index * 3; int gIndex = rIndex + 1; int bIndex = rIndex + 2; framebuffer.ColorFrameBuffer[rIndex] = attenuation.x; framebuffer.ColorFrameBuffer[gIndex] = attenuation.y; framebuffer.ColorFrameBuffer[bIndex] = attenuation.z; framebuffer.LightingFrameBuffer[rIndex] = lighting.x; framebuffer.LightingFrameBuffer[gIndex] = lighting.y; framebuffer.LightingFrameBuffer[bIndex] = lighting.z; }