28QSSGRenderRay::RayData QSSGRenderRay::createRayData(
const QMatrix4x4 &globalTransform,
29 const QSSGRenderRay &ray)
31 using DirectionOp = RayData::DirectionOp;
32 QMatrix4x4 originTransform = globalTransform.inverted();
33 QVector3D transformedOrigin = QSSGUtils::mat44::transform(originTransform, ray.origin);
34 float *outOriginTransformPtr(originTransform.data());
35 outOriginTransformPtr[12] = outOriginTransformPtr[13] = outOriginTransformPtr[14] = 0.0f;
36 const QVector3D &transformedDirection = QSSGUtils::mat44::rotate(originTransform, ray.direction).normalized();
37 static auto getInverseAndDirOp = [](
const QVector3D &dir, QVector3D &invDir, DirectionOp (&dirOp)[3]) {
38 for (
int i = 0; i != 3; ++i) {
39 const float axisDir = dir[i];
40 dirOp[i] = qFuzzyIsNull(axisDir) ? DirectionOp::Zero : ((axisDir < -std::numeric_limits<
float>::epsilon())
42 : DirectionOp::Normal);
43 invDir[i] = qFuzzyIsNull(axisDir) ? 0.0f : (1.0f / axisDir);
47 QVector3D transformedDirectionInvers;
48 getInverseAndDirOp(transformedDirection, transformedDirectionInvers, dirOp);
49 return RayData{ globalTransform, ray, transformedOrigin, transformedDirectionInvers,
50 transformedDirection, { dirOp[0], dirOp[1], dirOp[2] } };
53QSSGRenderRay::IntersectionResult QSSGRenderRay::createIntersectionResult(
const QSSGRenderRay::RayData &data,
56 Q_ASSERT(hit.intersects());
57 Q_ASSERT(hit.bounds !=
nullptr);
58 const QSSGBounds3 &bounds = *hit.bounds;
60 const QVector3D &scaledDir = data.direction * hit.min;
61 const QVector3D &localPosition = scaledDir + data.origin;
63 const QVector3D &globalPosition = QSSGUtils::mat44::transform(data.globalTransform, localPosition);
64 const QVector3D &cameraToLocal = data.ray.origin - globalPosition;
65 const float rayLenSquared = QSSGUtils::vec3::magnitudeSquared(cameraToLocal);
67 const auto &boundsMin = bounds.minimum;
68 const auto &boundsMax = bounds.maximum;
69 const float xRange = boundsMax.x() - boundsMin.x();
70 const float yRange = boundsMax.y() - boundsMin.y();
71 const QVector2D uvCoords{((localPosition[0] - boundsMin.x()) / xRange), ((localPosition[1] - boundsMin.y()) / yRange)};
74 return IntersectionResult(rayLenSquared, uvCoords, globalPosition, localPosition, QVector3D(), QVector3D());
77QSSGRenderRay::HitResult QSSGRenderRay::intersectWithAABBv2(
const QSSGRenderRay::RayData &data,
78 const QSSGBounds3 &bounds)
89 float tmax = std::numeric_limits<
float>::max();
90 float tmin = std::numeric_limits<
float>::min();
92 const QVector3D *
const barray[] { &bounds.minimum, &bounds.maximum };
94 for (
int axis = 0; axis != 3; ++axis) {
95 origin = data.origin[axis];
96 const bool zeroDir = (data.dirOp[axis] == RayData::DirectionOp::Zero);
97 if (zeroDir && (origin < bounds.minimum[axis] || origin > bounds.maximum[axis])) {
100 return { -1.0f, -1.0f,
nullptr };
104 tmax = std::min(((*barray[1-quint8(data.dirOp[axis])])[axis] - origin) * data.directionInvers[axis], tmax);
105 tmin = std::max(((*barray[quint8(data.dirOp[axis])])[axis] - origin) * data.directionInvers[axis], tmin);
109 return { tmin, tmax, &bounds };
115bool QSSGRenderRay::triangleIntersect(
const QSSGRenderRay &ray,
123 const float epsilon = std::numeric_limits<
float>::epsilon();
126 const QVector3D edge1 = v1 - v0;
127 const QVector3D edge2 = v2 - v0;
130 const QVector3D P = QVector3D::crossProduct(ray.direction, edge2);
133 const float determinant = QVector3D::dotProduct(edge1, P);
138 if (determinant > epsilon) {
140 const QVector3D T = ray.origin - v0;
143 u = QVector3D::dotProduct(T, P);
144 if (u < 0.0f || u > determinant)
148 Q = QVector3D::crossProduct(T, edge1);
151 v = QVector3D::dotProduct(ray.direction, Q);
152 if (v < 0.0f || ((u + v) > determinant))
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170else{
175 const float invDeterminant = 1.0f / determinant;
178 const float t = QVector3D::dotProduct(edge2, Q) * invDeterminant;
181 normal = QVector3D::crossProduct(edge1, edge2).normalized();
191void QSSGRenderRay::intersectWithBVH(
const RayData &data,
192 const QSSGMeshBVHNode *bvh,
193 const QSSGRenderMesh *mesh,
194 QVector<IntersectionResult> &intersections,
197 if (!bvh || !mesh || !mesh->bvh)
201 if (bvh->count != 0) {
203 auto results = intersectWithBVHTriangles(data, mesh->bvh->triangles(), bvh->offset, bvh->count);
204 if (!results.isEmpty())
205 intersections.append(results);
209 auto hit = QSSGRenderRay::intersectWithAABBv2(data, bvh->left->boundingData);
210 if (hit.intersects())
211 intersectWithBVH(data,
static_cast<
const QSSGMeshBVHNode *>(bvh->left), mesh, intersections, depth + 1);
213 hit = QSSGRenderRay::intersectWithAABBv2(data, bvh->right->boundingData);
214 if (hit.intersects())
215 intersectWithBVH(data,
static_cast<
const QSSGMeshBVHNode *>(bvh->right), mesh, intersections, depth + 1);
220QVector<QSSGRenderRay::IntersectionResult> QSSGRenderRay::intersectWithBVHTriangles(
const RayData &data,
221 const QSSGMeshBVHTriangles &bvhTriangles,
225 Q_ASSERT(bvhTriangles.size() >= size_t(triangleOffset + triangleCount));
227 QVector<QSSGRenderRay::IntersectionResult> results;
229 for (
int i = triangleOffset; i < triangleCount + triangleOffset; ++i) {
230 const auto &triangle = bvhTriangles[i];
232 QSSGRenderRay relativeRay(data.origin, data.direction);
238 const bool intersects = triangleIntersect(relativeRay,
246 const float w = 1.0f - u - v;
247 const QVector3D localIntersectionPoint = w * triangle.vertex1 +
248 u * triangle.vertex2 +
249 v * triangle.vertex3;
251 const QVector2D uvCoordinate = w * triangle.uvCoord1 +
252 u * triangle.uvCoord2 +
253 v * triangle.uvCoord3;
255 const QVector3D sceneIntersectionPos = QSSGUtils::mat44::transform(data.globalTransform,
256 localIntersectionPoint);
257 const QVector3D hitVector = data.ray.origin - sceneIntersectionPos;
259 const float rayLengthSquared = QSSGUtils::vec3::magnitudeSquared(hitVector);
262 const QMatrix3x3 normalMatrix = data.globalTransform.normalMatrix();
263 const QVector3D sceneNormal = QSSGUtils::mat33::transform(normalMatrix, normal);
265 results.append(IntersectionResult(rayLengthSquared,
267 sceneIntersectionPos,
268 localIntersectionPoint,
278std::optional<QVector2D> QSSGRenderRay::relative(
const QMatrix4x4 &inGlobalTransform,
279 const QSSGBounds3 &inBounds,
280 QSSGRenderBasisPlanes inPlane)
const
282 QMatrix4x4 theOriginTransform = inGlobalTransform.inverted();
284 QVector3D theTransformedOrigin = QSSGUtils::mat44::transform(theOriginTransform, origin);
285 float *outOriginTransformPtr(theOriginTransform.data());
286 outOriginTransformPtr[12] = outOriginTransformPtr[13] = outOriginTransformPtr[14] = 0.0f;
287 QVector3D theTransformedDirection = QSSGUtils::mat44::rotate(theOriginTransform, direction);
291 QVector3D theDirection(0, 0, 1);
292 QVector3D theRight(1, 0, 0);
293 QVector3D theUp(0, 1, 0);
295 case QSSGRenderBasisPlanes::XY:
297 case QSSGRenderBasisPlanes::XZ:
298 theDirection = QVector3D(0, 1, 0);
299 theUp = QVector3D(0, 0, 1);
301 case QSSGRenderBasisPlanes::YZ:
302 theDirection = QVector3D(1, 0, 0);
303 theRight = QVector3D(0, 0, 1);
306 QSSGPlane thePlane(theDirection,
307 QVector3D::dotProduct(theDirection, theTransformedDirection) > 0.0f
308 ? QVector3D::dotProduct(theDirection, inBounds.maximum)
309 : QVector3D::dotProduct(theDirection, inBounds.minimum));
311 const QSSGRenderRay relativeRay(theTransformedOrigin, theTransformedDirection);
312 std::optional<QVector3D> localIsect = QSSGRenderRay::intersect(thePlane, relativeRay);
313 if (localIsect.has_value()) {
314 float xRange = QVector3D::dotProduct(theRight, inBounds.maximum) - QVector3D::dotProduct(theRight, inBounds.minimum);
315 float yRange = QVector3D::dotProduct(theUp, inBounds.maximum) - QVector3D::dotProduct(theUp, inBounds.minimum);
316 float xOrigin = xRange / 2.0f + QVector3D::dotProduct(theRight, inBounds.minimum);
317 float yOrigin = yRange / 2.0f + QVector3D::dotProduct(theUp, inBounds.minimum);
318 return QVector2D((QVector3D::dotProduct(theRight, *localIsect) - xOrigin) / xRange,
319 (QVector3D::dotProduct(theUp, *localIsect) - yOrigin) / yRange);