bool Ray::InsideGeometry(const void* vertexData, unsigned vertexSize, unsigned vertexStart, unsigned vertexCount) const { float currentFrontFace = M_INFINITY; float currentBackFace = M_INFINITY; const unsigned char* vertices = ((const unsigned char*)vertexData) + vertexStart * vertexSize; unsigned index = 0; while (index + 2 < vertexCount) { const Vector3& v0 = *((const Vector3*)(&vertices[index * vertexSize])); const Vector3& v1 = *((const Vector3*)(&vertices[(index + 1) * vertexSize])); const Vector3& v2 = *((const Vector3*)(&vertices[(index + 2) * vertexSize])); float frontFaceDistance = HitDistance(v0, v1, v2); float backFaceDistance = HitDistance(v2, v1, v0); currentFrontFace = Min(frontFaceDistance > 0.0f ? frontFaceDistance : M_INFINITY, currentFrontFace); // A backwards face is just a regular one, with the vertices in the opposite order. This essentially checks backfaces by // checking reversed frontfaces currentBackFace = Min(backFaceDistance > 0.0f ? backFaceDistance : M_INFINITY, currentBackFace); index += 3; } // If the closest face is a backface, that means that the ray originates from the inside of the geometry // NOTE: there may be cases where both are equal, as in, no collision to either. This is prevented in the most likely case // (ray doesnt hit either) by this conditional if (currentFrontFace != M_INFINITY || currentBackFace != M_INFINITY) return currentBackFace < currentFrontFace; // It is still possible for two triangles to be equally distant from the triangle, however, this is extremely unlikely. // As such, it is safe to assume they are not return false; }
bool ORay::InsideGeometry(const void* vertexData, unsigned vertexSize, const void* indexData, unsigned indexSize, unsigned indexStart, unsigned indexCount) const { float currentFrontFace = INFINITY; float currentBackFace = INFINITY; const unsigned char* vertices = (const unsigned char*)vertexData; // 16-bit indices if (indexSize == sizeof(unsigned short)) { const unsigned short* indices = ((const unsigned short*)indexData) + indexStart; const unsigned short* indicesEnd = indices + indexCount; while (indices < indicesEnd) { const OVector3& v0 = *((const OVector3*)(&vertices[indices[0] * vertexSize])); const OVector3& v1 = *((const OVector3*)(&vertices[indices[1] * vertexSize])); const OVector3& v2 = *((const OVector3*)(&vertices[indices[2] * vertexSize])); float frontFaceDistance = HitDistance(v0, v1, v2); float backFaceDistance = HitDistance(v2, v1, v0); currentFrontFace = OMin2<float32>(frontFaceDistance > 0.0f ? frontFaceDistance : INFINITY, currentFrontFace); // A backwards face is just a regular one, with the vertices in the opposite order. This essentially checks backfaces by // checking reversed frontfaces currentBackFace = OMin2<float32>(backFaceDistance > 0.0f ? backFaceDistance : INFINITY, currentBackFace); indices += 3; } } // 32-bit indices else { const unsigned* indices = ((const unsigned*)indexData) + indexStart; const unsigned* indicesEnd = indices + indexCount; while (indices < indicesEnd) { const OVector3& v0 = *((const OVector3*)(&vertices[indices[0] * vertexSize])); const OVector3& v1 = *((const OVector3*)(&vertices[indices[1] * vertexSize])); const OVector3& v2 = *((const OVector3*)(&vertices[indices[2] * vertexSize])); float32 frontFaceDistance = HitDistance(v0, v1, v2); float32 backFaceDistance = HitDistance(v2, v1, v0); currentFrontFace = OMin2<float32>(frontFaceDistance > 0.0f ? frontFaceDistance : INFINITY, currentFrontFace); // A backwards face is just a regular one, with the vertices in the opposite order. This essentially checks backfaces by // checking reversed frontfaces currentBackFace = OMin2<float32>(backFaceDistance > 0.0f ? backFaceDistance : INFINITY, currentBackFace); indices += 3; } } // If the closest face is a backface, that means that the ORay originates from the inside of the geometry // NOTE: there may be cases where both are equal, as in, no collision to either. This is prevented in the most likely case // (ORay doesnt hit either) by this conditional if (currentFrontFace != INFINITY || currentBackFace != INFINITY) return currentBackFace < currentFrontFace; // It is still possible for two triangles to be equally distant from the triangle, however, this is extremely unlikely. // As such, it is safe to assume they are not return false; }
float Ray::HitDistance(const Frustum& frustum, bool solidInside) const { float maxOutside = 0.0f; float minInside = M_INFINITY; bool allInside = true; for (unsigned i = 0; i < NUM_FRUSTUM_PLANES; ++i) { const Plane& plane = frustum.planes_[i]; float distance = HitDistance(frustum.planes_[i]); if (plane.Distance(origin_) < 0.0f) { maxOutside = Max(maxOutside, distance); allInside = false; } else minInside = Min(minInside, distance); } if (allInside) return solidInside ? 0.0f : minInside; else if (maxOutside <= minInside) return maxOutside; else return M_INFINITY; }
float ORay::HitDistance(const OFrustum& frustum, bool solidInside) const { float maxOutside = 0.0f; float minInside = INFINITY; bool allInside = true; for (unsigned i = 0; i < ONLY_FRUSTUM_PLANES_NUM; ++i) { const OPlane& plane = frustum.planes[i]; float distance = HitDistance(frustum.planes[i]); if (plane.Distance(m_origin) < 0.0f) { maxOutside = OMax2<float32>(maxOutside, distance); allInside = false; } else minInside = OMin2<float32>(minInside, distance); } if (allInside) return solidInside ? 0.0f : minInside; else if (maxOutside <= minInside) return maxOutside; else return INFINITY; }
float Ray::HitDistance(const Frustum& frustum, bool solidInside) const { float maxOutside = 0.0f; float minInside = M_INFINITY; bool allInside = true; for (const auto& plane : frustum.planes_) { float distance = HitDistance(plane); if (plane.Distance(origin_) < 0.0f) { maxOutside = Max(maxOutside, distance); allInside = false; } else minInside = Min(minInside, distance); } if (allInside) return solidInside ? 0.0f : minInside; else if (maxOutside <= minInside) return maxOutside; else return M_INFINITY; }
float Ray::HitDistance(const void* vertexData, unsigned vertexSize, const void* indexData, unsigned indexSize, unsigned indexStart, unsigned indexCount, Vector3* outNormal) const { float nearest = M_INFINITY; const unsigned char* vertices = (const unsigned char*)vertexData; // 16-bit indices if (indexSize == sizeof(unsigned short)) { const unsigned short* indices = ((const unsigned short*)indexData) + indexStart; const unsigned short* indicesEnd = indices + indexCount; while (indices < indicesEnd) { const Vector3& v0 = *((const Vector3*)(&vertices[indices[0] * vertexSize])); const Vector3& v1 = *((const Vector3*)(&vertices[indices[1] * vertexSize])); const Vector3& v2 = *((const Vector3*)(&vertices[indices[2] * vertexSize])); nearest = Min(nearest, HitDistance(v0, v1, v2, outNormal)); indices += 3; } } // 32-bit indices else { const unsigned* indices = ((const unsigned*)indexData) + indexStart; const unsigned* indicesEnd = indices + indexCount; while (indices < indicesEnd) { const Vector3& v0 = *((const Vector3*)(&vertices[indices[0] * vertexSize])); const Vector3& v1 = *((const Vector3*)(&vertices[indices[1] * vertexSize])); const Vector3& v2 = *((const Vector3*)(&vertices[indices[2] * vertexSize])); nearest = Min(nearest, HitDistance(v0, v1, v2, outNormal)); indices += 3; } } return nearest; }
float Ray::HitDistance(const void* vertexData, unsigned vertexSize, unsigned vertexStart, unsigned vertexCount, Vector3* outNormal) const { float nearest = M_INFINITY; const unsigned char* vertices = ((const unsigned char*)vertexData) + vertexStart * vertexSize; unsigned index = 0; while (index + 2 < vertexCount) { const Vector3& v0 = *((const Vector3*)(&vertices[index * vertexSize])); const Vector3& v1 = *((const Vector3*)(&vertices[(index + 1) * vertexSize])); const Vector3& v2 = *((const Vector3*)(&vertices[(index + 2) * vertexSize])); nearest = Min(nearest, HitDistance(v0, v1, v2, outNormal)); index += 3; } return nearest; }
float Ray::HitDistance(const void* vertexData, unsigned vertexStride, unsigned vertexStart, unsigned vertexCount, Vector3* outNormal, Vector2* outUV, unsigned uvOffset) const { float nearest = M_INFINITY; const unsigned char* vertices = ((const unsigned char*)vertexData) + vertexStart * vertexStride; unsigned index = 0, nearestIdx = M_MAX_UNSIGNED; Vector3 barycentric; Vector3* outBary = outUV ? &barycentric : 0; while (index + 2 < vertexCount) { const Vector3& v0 = *((const Vector3*)(&vertices[index * vertexStride])); const Vector3& v1 = *((const Vector3*)(&vertices[(index + 1) * vertexStride])); const Vector3& v2 = *((const Vector3*)(&vertices[(index + 2) * vertexStride])); float distance = HitDistance(v0, v1, v2, outNormal, outBary); if (distance < nearest) { nearestIdx = index; nearest = distance; } index += 3; } if (outUV) { if (nearestIdx == M_MAX_UNSIGNED) *outUV = Vector2::ZERO; else { // Interpolate the UV coordinate using barycentric coordinate const Vector2& uv0 = *((const Vector2*)(&vertices[uvOffset + nearestIdx * vertexStride])); const Vector2& uv1 = *((const Vector2*)(&vertices[uvOffset + (nearestIdx + 1) * vertexStride])); const Vector2& uv2 = *((const Vector2*)(&vertices[uvOffset + (nearestIdx + 2) * vertexStride])); *outUV = Vector2(uv0.x_ * barycentric.x_ + uv1.x_ * barycentric.y_ + uv2.x_ * barycentric.z_, uv0.y_ * barycentric.x_ + uv1.y_ * barycentric.y_ + uv2.y_ * barycentric.z_); } } return nearest; }
float Ray::HitDistance(const Vector3& v0, const Vector3& v1, const Vector3& v2) const { return HitDistance(v0, v1, v2, 0); }
float Ray::HitDistance(const void* vertexData, unsigned vertexStride, const void* indexData, unsigned indexSize, unsigned indexStart, unsigned indexCount, Vector3* outNormal, Vector2* outUV, unsigned uvOffset) const { float nearest = M_INFINITY; const unsigned char* vertices = (const unsigned char*)vertexData; Vector3 barycentric; Vector3* outBary = outUV ? &barycentric : 0; // 16-bit indices if (indexSize == sizeof(unsigned short)) { const unsigned short* indices = ((const unsigned short*)indexData) + indexStart; const unsigned short* indicesEnd = indices + indexCount; const unsigned short* nearestIndices = 0; while (indices < indicesEnd) { const Vector3& v0 = *((const Vector3*)(&vertices[indices[0] * vertexStride])); const Vector3& v1 = *((const Vector3*)(&vertices[indices[1] * vertexStride])); const Vector3& v2 = *((const Vector3*)(&vertices[indices[2] * vertexStride])); float distance = HitDistance(v0, v1, v2, outNormal, outBary); if (distance < nearest) { nearestIndices = indices; nearest = distance; } indices += 3; } if (outUV) { if (nearestIndices == 0) *outUV = Vector2::ZERO; else { // Interpolate the UV coordinate using barycentric coordinate const Vector2& uv0 = *((const Vector2*)(&vertices[uvOffset + nearestIndices[0] * vertexStride])); const Vector2& uv1 = *((const Vector2*)(&vertices[uvOffset + nearestIndices[1] * vertexStride])); const Vector2& uv2 = *((const Vector2*)(&vertices[uvOffset + nearestIndices[2] * vertexStride])); *outUV = Vector2(uv0.x_ * barycentric.x_ + uv1.x_ * barycentric.y_ + uv2.x_ * barycentric.z_, uv0.y_ * barycentric.x_ + uv1.y_ * barycentric.y_ + uv2.y_ * barycentric.z_); } } } // 32-bit indices else { const unsigned* indices = ((const unsigned*)indexData) + indexStart; const unsigned* indicesEnd = indices + indexCount; const unsigned* nearestIndices = 0; while (indices < indicesEnd) { const Vector3& v0 = *((const Vector3*)(&vertices[indices[0] * vertexStride])); const Vector3& v1 = *((const Vector3*)(&vertices[indices[1] * vertexStride])); const Vector3& v2 = *((const Vector3*)(&vertices[indices[2] * vertexStride])); float distance = HitDistance(v0, v1, v2, outNormal, outBary); if (distance < nearest) { nearestIndices = indices; nearest = distance; } indices += 3; } if (outUV) { if (nearestIndices == 0) *outUV = Vector2::ZERO; else { // Interpolate the UV coordinate using barycentric coordinate const Vector2& uv0 = *((const Vector2*)(&vertices[uvOffset + nearestIndices[0] * vertexStride])); const Vector2& uv1 = *((const Vector2*)(&vertices[uvOffset + nearestIndices[1] * vertexStride])); const Vector2& uv2 = *((const Vector2*)(&vertices[uvOffset + nearestIndices[2] * vertexStride])); *outUV = Vector2(uv0.x_ * barycentric.x_ + uv1.x_ * barycentric.y_ + uv2.x_ * barycentric.z_, uv0.y_ * barycentric.x_ + uv1.y_ * barycentric.y_ + uv2.y_ * barycentric.z_); } } } return nearest; }