public bool Raycast(FRay ray, out float closestDistance) { // Convert the ray to local space of this node since all of our raycasts are local. FRay localRay = WMath.TransformRay(ray, Transform.Position, Transform.LocalScale, Transform.Rotation.Inverted()); bool bHit = false; if (m_actorMesh != null) { bHit = m_actorMesh.Raycast(localRay, out closestDistance, true); } else { bHit = WMath.RayIntersectsAABB(localRay, m_objRender.GetAABB().Min, m_objRender.GetAABB().Max, out closestDistance); } if (bHit) { // Convert the hit point back to world space... Vector3 localHitPoint = localRay.Origin + (localRay.Direction * closestDistance); localHitPoint = Vector3.Transform(localHitPoint + Transform.Position, Transform.Rotation); // Now get the distance from the original ray origin and the new worldspace hit point. closestDistance = (localHitPoint - ray.Origin).Length; } return(bHit); }
public bool Raycast(FRay ray, out float closestDistance) { // Convert the ray to local space of this node since all of our raycasts are local. FRay localRay; if (DisableRotationAndScaleForRaycasting) { localRay = WMath.TransformRay(ray, Transform.Position, Vector3.One, Quaternion.Identity); } else { localRay = WMath.TransformRay(ray, Transform.Position, VisualScale, Transform.Rotation.Inverted().ToSinglePrecision()); } closestDistance = float.MaxValue; bool bHit = false; if (m_actorMeshes.Count > 0) { foreach (var actor_mesh in m_actorMeshes) { bHit = actor_mesh.Raycast(localRay, out closestDistance, true); if (bHit) { break; } } } else if (m_objRender != null) { if (m_objRender.FaceCullingEnabled && m_objRender.GetAABB().Contains(localRay.Origin)) { // If the camera is inside an OBJ render that has backface culling on, the actor won't actually be visible, so don't select it. return(false); } bHit = WMath.RayIntersectsAABB(localRay, m_objRender.GetAABB().Min, m_objRender.GetAABB().Max, out closestDistance); if (bHit) { // Convert the hit point back to world space... Vector3 localHitPoint = localRay.Origin + (localRay.Direction * closestDistance); Vector3 globalHitPoint = Transform.Position + Vector3.Transform(localHitPoint, Transform.Rotation.ToSinglePrecision()); // Now get the distance from the original ray origin and the new worldspace hit point. closestDistance = (globalHitPoint - ray.Origin).Length; } } return(bHit); }
public bool CheckSelectedAxes(FRay ray) { // Convert the ray into local space so we can use axis-aligned checks, this solves the checking problem // when the gizmo is rotated due to being in Local mode. FRay localRay = new FRay(); localRay.Direction = Vector3.Transform(ray.Direction, m_rotation.Inverted()); localRay.Origin = Vector3.Transform(ray.Origin - m_position, m_rotation.Inverted()); //m_lineBatcher.DrawLine(localRay.Origin, localRay.Origin + (localRay.Direction * 10000), WLinearColor.White, 25, 5); List <AxisDistanceResult> results = new List <AxisDistanceResult>(); if (m_mode == FTransformMode.Translation) { FAABox[] translationAABB = GetAABBBoundsForMode(FTransformMode.Translation); for (int i = 0; i < translationAABB.Length; i++) { float intersectDist; if (WMath.RayIntersectsAABB(localRay, translationAABB[i].Min, translationAABB[i].Max, out intersectDist)) { results.Add(new AxisDistanceResult((FSelectedAxes)(i + 1), intersectDist)); } } } else if (m_mode == FTransformMode.Rotation) { // We'll use a combination of AABB and Distance checks to give us the quarter-circles we need. FAABox[] rotationAABB = GetAABBBoundsForMode(FTransformMode.Rotation); float screenScale = 0f; for (int i = 0; i < 3; i++) { screenScale += m_scale[i]; } screenScale /= 3f; for (int i = 0; i < rotationAABB.Length; i++) { float intersectDist; if (WMath.RayIntersectsAABB(localRay, rotationAABB[i].Min, rotationAABB[i].Max, out intersectDist)) { Vector3 intersectPoint = localRay.Origin + (localRay.Direction * intersectDist); // Convert this aabb check into a radius check so we clip it by the semi-circles // that the rotation tool actually is. if (intersectPoint.Length > 105f * screenScale) { continue; } results.Add(new AxisDistanceResult((FSelectedAxes)(i + 1), intersectDist)); } } } else if (m_mode == FTransformMode.Scale) { FAABox[] scaleAABB = GetAABBBoundsForMode(FTransformMode.Scale); for (int i = 0; i < scaleAABB.Length; i++) { float intersectDist; if (WMath.RayIntersectsAABB(localRay, scaleAABB[i].Min, scaleAABB[i].Max, out intersectDist)) { // Special-case here to give the center scale point overriding priority. Because we intersected // it, we can just override its distance to zero to make it clickable through the other bounding boxes. if ((FSelectedAxes)i + 1 == FSelectedAxes.All) { intersectDist = 0f; } results.Add(new AxisDistanceResult((FSelectedAxes)(i + 1), intersectDist)); } } } if (results.Count == 0) { m_selectedAxes = FSelectedAxes.None; return(false); } // If we get an intersection, sort them by the closest intersection distance. results.Sort((x, y) => x.Distance.CompareTo(y.Distance)); m_selectedAxes = results[0].Axis; // Store where the mouse hit on the first frame in world space. This means converting the ray back to worldspace. Vector3 localHitPoint = localRay.Origin + (localRay.Direction * results[0].Distance); m_hitPoint = Vector3.Transform(localHitPoint, m_rotation) + m_position; return(true); }