/// <summary> /// Append a scene object part report to an input StringBuilder /// </summary> /// <returns></returns> /// <param name='sb'></param> /// <param name='sop'</param> /// <param name='showFull'> /// If true then information on each inventory item will be shown. /// If false then only summary inventory information is shown. /// </param> private StringBuilder AddScenePartReport(StringBuilder sb, SceneObjectPart sop, bool showFull) { ConsoleDisplayList cdl = new ConsoleDisplayList(); cdl.AddRow("Name", sop.Name); cdl.AddRow("Description", sop.Description); cdl.AddRow("Local ID", sop.LocalId); cdl.AddRow("UUID", sop.UUID); cdl.AddRow("Location", string.Format("{0} @ {1}", sop.AbsolutePosition, sop.ParentGroup.Scene.Name)); cdl.AddRow( "Parent", sop.IsRoot ? "Is Root" : string.Format("{0} {1}", sop.ParentGroup.Name, sop.ParentGroup.UUID)); cdl.AddRow("Link number", sop.LinkNum); cdl.AddRow("Flags", sop.Flags); if (showFull) { PrimitiveBaseShape s = sop.Shape; cdl.AddRow("FlexiDrag", s.FlexiDrag); cdl.AddRow("FlexiEntry", s.FlexiEntry); cdl.AddRow("FlexiForce", string.Format("<{0},{1},{2}>", s.FlexiForceX, s.FlexiForceY, s.FlexiForceZ)); cdl.AddRow("FlexiGravity", s.FlexiGravity); cdl.AddRow("FlexiSoftness", s.FlexiSoftness); cdl.AddRow("HollowShape", s.HollowShape); cdl.AddRow( "LightColor", string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA)); cdl.AddRow("LightCutoff", s.LightCutoff); cdl.AddRow("LightEntry", s.LightEntry); cdl.AddRow("LightFalloff", s.LightFalloff); cdl.AddRow("LightIntensity", s.LightIntensity); cdl.AddRow("LightRadius", s.LightRadius); cdl.AddRow("Location (relative)", sop.RelativePosition); cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a")); cdl.AddRow("PathBegin", s.PathBegin); cdl.AddRow("PathEnd", s.PathEnd); cdl.AddRow("PathCurve", s.PathCurve); cdl.AddRow("PathRadiusOffset", s.PathRadiusOffset); cdl.AddRow("PathRevolutions", s.PathRevolutions); cdl.AddRow("PathScale", string.Format("<{0},{1}>", s.PathScaleX, s.PathScaleY)); cdl.AddRow("PathSkew", string.Format("<{0},{1}>", s.PathShearX, s.PathShearY)); cdl.AddRow("FlexiDrag", s.PathSkew); cdl.AddRow("PathTaper", string.Format("<{0},{1}>", s.PathTaperX, s.PathTaperY)); cdl.AddRow("PathTwist", s.PathTwist); cdl.AddRow("PathTwistBegin", s.PathTwistBegin); cdl.AddRow("PCode", s.PCode); cdl.AddRow("ProfileBegin", s.ProfileBegin); cdl.AddRow("ProfileEnd", s.ProfileEnd); cdl.AddRow("ProfileHollow", s.ProfileHollow); cdl.AddRow("ProfileShape", s.ProfileShape); cdl.AddRow("ProjectionAmbiance", s.ProjectionAmbiance); cdl.AddRow("ProjectionEntry", s.ProjectionEntry); cdl.AddRow("ProjectionFocus", s.ProjectionFocus); cdl.AddRow("ProjectionFOV", s.ProjectionFOV); cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID); cdl.AddRow("Rotation (Relative)", sop.RotationOffset); cdl.AddRow("Rotation (World)", sop.GetWorldRotation()); cdl.AddRow("Scale", s.Scale); cdl.AddRow( "SculptData", string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a")); cdl.AddRow("SculptEntry", s.SculptEntry); cdl.AddRow("SculptTexture", s.SculptTexture); cdl.AddRow("SculptType", s.SculptType); cdl.AddRow("State", s.State); // TODO, unpack and display texture entries //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures. } object itemsOutput; if (showFull) { StringBuilder itemsSb = new StringBuilder("\n"); itemsOutput = AddScenePartItemsReport(itemsSb, sop.Inventory).ToString(); } else { itemsOutput = sop.Inventory.Count; } cdl.AddRow("Items", itemsOutput); return sb.Append(cdl.ToString()); }
private DetectedObject CreateDetObject(SceneObjectPart obj) { DetectedObject detobj = new DetectedObject(); detobj.keyUUID = obj.UUID; detobj.nameStr = obj.Name; detobj.ownerUUID = obj.OwnerID; detobj.posVector = obj.AbsolutePosition; detobj.rotQuat = obj.GetWorldRotation(); detobj.velVector = obj.Velocity; detobj.colliderType = 0; detobj.groupUUID = obj.GroupID; detobj.linkNumber = 0; return detobj; }
/// <summary> /// Delink the given prim from this group. The delinked prim is established as /// an independent SceneObjectGroup. /// </summary> /// <param name="partID"></param> /// <param name="sendEvents"></param> /// <returns>The object group of the newly delinked prim.</returns> public SceneObjectGroup DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents) { // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); Quaternion worldRot = linkPart.GetWorldRotation(); // Remove the part from this object m_scene.SceneGraph.DeLinkPartFromEntity(this, linkPart); /* this is already done in DeLinkPartFromEntity if (m_partsList.Count == 1 && RootPart != null) //Single prim is left RootPart.LinkNum = 0; else { lock (m_partsLock) { foreach (SceneObjectPart p in m_partsList) { if (p.LinkNum > linkPart.LinkNum) p.LinkNum--; } } } */ linkPart.SetParentLocalId(0); linkPart.LinkNum = 0; if (linkPart.PhysActor != null) { m_scene.SceneGraph.PhysicsScene.RemovePrim(linkPart.PhysActor); // linkPart.PhysActor.delink(); } // We need to reset the child part's position // ready for life as a separate object after being a part of another object Quaternion parentRot = m_rootPart.RotationOffset; Vector3 axPos = linkPart.OffsetPosition; axPos *= parentRot; linkPart.SetOffsetPosition(axPos); linkPart.FixGroupPosition(AbsolutePosition + linkPart.OffsetPosition,false); linkPart.FixOffsetPosition(Vector3.Zero, false); linkPart.RotationOffset = worldRot; SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart, Scene); m_scene.SceneGraph.DelinkPartToScene(objectGroup); if (sendEvents) linkPart.TriggerScriptChangedEvent(Changed.LINK); linkPart.Rezzed = RootPart.Rezzed; //This is already set multiple places, no need to do it again //HasGroupChanged = true; //We need to send this so that we don't have issues with the client not realizing that the prims were unlinked ScheduleGroupUpdate(PrimUpdateFlags.FullUpdate); return objectGroup; }
/// <summary> /// Delink the given prim from this group. The delinked prim is established as /// an independent SceneObjectGroup. /// </summary> /// <remarks> /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race /// condition. But currently there is no /// alternative method that does take a lock to delink a single prim. /// </remarks> /// <param name="partID"></param> /// <param name="sendEvents"></param> /// <returns>The object group of the newly delinked prim.</returns> public SceneObjectGroup DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents) { // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); linkPart.ClearUndoState(); Vector3 worldPos = linkPart.GetWorldPosition(); Quaternion worldRot = linkPart.GetWorldRotation(); // Remove the part from this object lock (m_parts.SyncRoot) { m_parts.Remove(linkPart.UUID); SceneObjectPart[] parts = m_parts.GetArray(); // Rejigger the linknum's of the remaining SOP's to fill any gap if (parts.Length == 1 && RootPart != null) { // Single prim left RootPart.LinkNum = 0; } else { for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; if (part.LinkNum > linkPart.LinkNum) part.LinkNum--; } } } linkPart.ParentID = 0; linkPart.LinkNum = 0; PhysicsActor linkPartPa = linkPart.PhysActor; // Remove the SOP from the physical scene. // If the new SOG is physical, it is re-created later. // (There is a problem here in that we have not yet told the physics // engine about the delink. Someday, linksets should be made first // class objects in the physics engine interface). if (linkPartPa != null) m_scene.PhysicsScene.RemovePrim(linkPartPa); // We need to reset the child part's position // ready for life as a separate object after being a part of another object /* This commented out code seems to recompute what GetWorldPosition already does. * Replace with a call to GetWorldPosition (before unlinking) Quaternion parentRot = m_rootPart.RotationOffset; Vector3 axPos = linkPart.OffsetPosition; axPos *= parentRot; linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; linkPart.OffsetPosition = new Vector3(0, 0, 0); */ linkPart.GroupPosition = worldPos; linkPart.OffsetPosition = Vector3.Zero; linkPart.RotationOffset = worldRot; // Create a new SOG to go around this unlinked and unattached SOP SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); m_scene.AddNewSceneObject(objectGroup, true); if (sendEvents) linkPart.TriggerScriptChangedEvent(Changed.LINK); linkPart.Rezzed = RootPart.Rezzed; // When we delete a group, we currently have to force persist to the database if the object id has changed // (since delete works by deleting all rows which have a given object id) objectGroup.HasGroupChangedDueToDelink = true; return objectGroup; }
private LSL_Rotation GetPartRot(SceneObjectPart part) { Quaternion q; if (part.LinkNum == 0 || part.LinkNum == 1) // unlinked or root prim { if (part.ParentGroup.AttachmentPoint != 0) { ScenePresence avatar = World.GetScenePresence(part.ParentGroup.AttachedAvatar); if (avatar != null) { if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) q = avatar.CameraRotation; // Mouselook else q = avatar.Rotation; // Currently infrequently updated so may be inaccurate } else q = part.ParentGroup.GroupRotation; // Likely never get here but just in case } else q = part.ParentGroup.GroupRotation; // just the group rotation return new LSL_Rotation(q.X, q.Y, q.Z, q.W); } q = part.GetWorldRotation(); return new LSL_Rotation(q.X, q.Y, q.Z, q.W); }
/// <summary> /// Delink the given prim from this group. The delinked prim is established as /// an independent SceneObjectGroup. /// </summary> /// <param name="partID"></param> /// <param name="sendEvents"></param> /// <returns>The object group of the newly delinked prim.</returns> public SceneObjectGroup DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents) { // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); linkPart.ClearUndoState(); Quaternion worldRot = linkPart.GetWorldRotation(); // Remove the part from this object lock (m_parts) { m_parts.Remove(linkPart.UUID); } if (m_parts.Count == 1 && RootPart != null) //Single prim is left RootPart.LinkNum = 0; else { foreach (SceneObjectPart p in m_parts.Values) { if (p.LinkNum > linkPart.LinkNum) p.LinkNum--; } } linkPart.ParentID = 0; linkPart.LinkNum = 0; if (linkPart.PhysActor != null) { m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); } // We need to reset the child part's position // ready for life as a separate object after being a part of another object Quaternion parentRot = m_rootPart.RotationOffset; Vector3 axPos = linkPart.OffsetPosition; axPos *= parentRot; linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; linkPart.OffsetPosition = new Vector3(0, 0, 0); linkPart.RotationOffset = worldRot; SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); m_scene.AddNewSceneObject(objectGroup, true); if (sendEvents) linkPart.TriggerScriptChangedEvent(Changed.LINK); linkPart.Rezzed = RootPart.Rezzed; //HasGroupChanged = true; //ScheduleGroupForFullUpdate(); return objectGroup; }
/// <summary> /// Delink the given prim from this group. The delinked prim is established as /// an independent SceneObjectGroup. /// </summary> /// <param name="partID"></param> /// <param name="sendEvents"></param> /// <returns>The object group of the newly delinked prim.</returns> public SceneObjectGroup DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents) { // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); linkPart.ClearUndoState(); Quaternion worldRot = linkPart.GetWorldRotation(); // Remove the part from this object lock (m_parts.SyncRoot) { m_parts.Remove(linkPart.UUID); SceneObjectPart[] parts = m_parts.GetArray(); if (parts.Length == 1 && RootPart != null) { // Single prim left RootPart.LinkNum = 0; } else { for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; if (part.LinkNum > linkPart.LinkNum) part.LinkNum--; } } } linkPart.ParentID = 0; linkPart.LinkNum = 0; if (linkPart.PhysActor != null) { m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); } // We need to reset the child part's position // ready for life as a separate object after being a part of another object Quaternion parentRot = m_rootPart.RotationOffset; Vector3 axPos = linkPart.OffsetPosition; axPos *= parentRot; linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; linkPart.OffsetPosition = new Vector3(0, 0, 0); linkPart.RotationOffset = worldRot; SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); m_scene.AddNewSceneObject(objectGroup, true); if (sendEvents) linkPart.TriggerScriptChangedEvent(Changed.LINK); linkPart.Rezzed = RootPart.Rezzed; // When we delete a group, we currently have to force persist to the database if the object id has changed // (since delete works by deleting all rows which have a given object id) objectGroup.HasGroupChangedDueToDelink = true; return objectGroup; }
/// <summary> /// Delink the given prim from this group. The delinked prim is established as /// an independent SceneObjectGroup. /// </summary> /// <remarks> /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race /// condition. But currently there is no /// alternative method that does take a lock to delink a single prim. /// </remarks> /// <param name="partID"></param> /// <param name="sendEvents"></param> /// <returns>The object group of the newly delinked prim.</returns> public SceneObjectGroup DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents) { // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); linkPart.ClearUndoState(); Vector3 worldPos = linkPart.GetWorldPosition(); Quaternion worldRot = linkPart.GetWorldRotation(); // Remove the part from this object lock (m_parts.SyncRoot) { m_parts.Remove(linkPart.UUID); SceneObjectPart[] parts = m_parts.GetArray(); // Rejigger the linknum's of the remaining SOP's to fill any gap if (parts.Length == 1 && RootPart != null) { // Single prim left RootPart.LinkNum = 0; } else { for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; if (part.LinkNum > linkPart.LinkNum) part.LinkNum--; } } } linkPart.ParentID = 0; linkPart.LinkNum = 0; PhysicsActor linkPartPa = linkPart.PhysActor; // Remove the SOP from the physical scene. // If the new SOG is physical, it is re-created later. // (There is a problem here in that we have not yet told the physics // engine about the delink. Someday, linksets should be made first // class objects in the physics engine interface). if (linkPartPa != null) m_scene.PhysicsScene.RemovePrim(linkPartPa); // We need to reset the child part's position // ready for life as a separate object after being a part of another object /* This commented out code seems to recompute what GetWorldPosition already does. * Replace with a call to GetWorldPosition (before unlinking) Quaternion parentRot = m_rootPart.RotationOffset; Vector3 axPos = linkPart.OffsetPosition; axPos *= parentRot; linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; linkPart.OffsetPosition = new Vector3(0, 0, 0); */ linkPart.GroupPosition = worldPos; linkPart.OffsetPosition = Vector3.Zero; linkPart.RotationOffset = worldRot; // Create a new SOG to go around this unlinked and unattached SOP SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); m_scene.AddNewSceneObject(objectGroup, true); if (sendEvents) linkPart.TriggerScriptChangedEvent(Changed.LINK); linkPart.Rezzed = RootPart.Rezzed; // We must persist the delinked group to the database immediately, for safety. The problem // is that although in memory the new group has a new SceneGroupID, in the database it // still has the parent group's SceneGroupID (until the next backup). This means that if the // parent group is deleted then the delinked group will also be deleted from the database. // This problem will disappear if the region remains alive long enough for another backup, // since at that time the delinked group's new SceneGroupID will be written to the database. // But if the region crashes before that then the prims will be permanently gone, and this must // not happen. (We can't use a just-in-time trick like GroupContainsForeignPrims in this case // because the delinked group doesn't know when the source group is deleted.) m_scene.ForceSceneObjectBackup(objectGroup); return objectGroup; }
public void DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents, bool sendGroupUpdate) { linkPart.ClearUndoState(); // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); Quaternion worldRot = linkPart.GetWorldRotation(); // Remove the part from this object lock (m_parts) { m_parts.Remove(linkPart.UUID); _partsByLocalId.Remove(linkPart.LocalId); if (m_parts.Count == 1 && RootPart != null) //Single prim is left { RootPart.LinkNum = 0; } else { foreach (SceneObjectPart p in m_parts.Values) { if (p.LinkNum > linkPart.LinkNum) p.LinkNum--; } } } linkPart.ParentID = 0; linkPart.LinkNum = 0; // We need to reset the child part's position // ready for life as a separate object after being a part of another object Quaternion parentRot = m_rootPart.RotationOffset; Vector3 axPos = linkPart.OffsetPosition; axPos *= parentRot; Vector3 groupPosition = AbsolutePosition + axPos; linkPart.SetGroupPositionDirect(groupPosition); linkPart.SetOffsetPositionDirect(Vector3.Zero); linkPart.SetRotationOffsetDirect(worldRot); SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); PhysicsActor partActor = linkPart.PhysActor; if (partActor != null) { partActor.DelinkFromParent(groupPosition, worldRot); } m_scene.AddNewSceneObject(objectGroup, true); if (sendEvents) linkPart.TriggerScriptChangedEvent(Changed.LINK); linkPart.Rezzed = RootPart.Rezzed; //Rebuild the bounding box ClearBoundingBoxCache(); // Update the ServerWeight/LandImpact and StreamingCost RecalcPrimWeights(); if (sendGroupUpdate) { HasGroupChanged = true; ScheduleGroupForFullUpdate(); objectGroup.ScheduleGroupForFullUpdate(); } }
private void SitRayCastfoundTop(SceneObjectPart part, Vector3 collisionPoint, Vector3 collisionNormal) { Vector3 partpos = part.AbsolutePosition; Vector3 contactpos = collisionPoint - partpos; // contact relative to part Quaternion partrot = part.GetWorldRotation(); contactpos *= Quaternion.Inverse(partrot); // contact in part coords // collisionNormal *= Quaternion.Inverse(partrot); Quaternion rot = Vector3.RotationBetween(contactpos, new Vector3(1, 0, 0)); // angle with part z axis rot = Quaternion.CreateFromAxisAngle(contactpos,0); Vector3 avasize = new Vector3(0.37f, 0.37f, m_appearance.AvatarHeight * 0.5f); avasize *= rot; // contactpos.Z += avasize.Z + 0.15f; SendSitResponse(m_requestedSitTargetUUID, contactpos, rot); }
/* not in use public void SitRayHorizontal(SceneObjectPart part) { // Next, try to raycast from the avatar position to fwd Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset; Vector3 StartRayCastPosition = CameraPosition; Vector3 direction = EndRayCastPosition - StartRayCastPosition; float distance = direction.Length(); direction /= distance; m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastHorizontalResponse); } public void SitRayCastHorizontalResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal) { SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID); if (part != null) { if (hitYN) { if (localid == m_requestedSitTargetID) { SitRaycastFindEdge(part,collisionPoint, normal); m_log.DebugFormat("[SIT]: Raycast Horizontal Position succeeded at point: {0}, normal:{1}", collisionPoint, normal); // Next, try to raycast from the camera position Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset; Vector3 StartRayCastPosition = CameraPosition; Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition); float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition); //m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastResponseAvatarPosition); } else { ControllingClient.SendAlertMessage("Sit position not accessable."); m_requestedSitTargetUUID = UUID.Zero; m_requestedSitTargetID = 0; m_requestedSitOffset = Vector3.Zero; } } else { ControllingClient.SendAlertMessage("Sit position not accessable."); m_requestedSitTargetUUID = UUID.Zero; m_requestedSitTargetID = 0; m_requestedSitOffset = Vector3.Zero; } } else { ControllingClient.SendAlertMessage("Sit position no longer exists"); m_requestedSitTargetUUID = UUID.Zero; m_requestedSitTargetID = 0; m_requestedSitOffset = Vector3.Zero; } } */ private void SitRaycastFoundPath(SceneObjectPart part, Vector3 collisionPoint, Vector3 collisionNormal) { // go to top of part, above nearest point Vector3 partscale = part.Scale * part.GetWorldRotation(); // part AABB if (partscale.Z <0 ) partscale.Z = -partscale.Z; if (part.GetPrimType() == PrimType.SPHERE) { Vector3 contactpos = new Vector3(0,0,partscale.Z); SendSitResponse(m_requestedSitTargetUUID, contactpos, Quaternion.Identity); return; } collisionPoint.Z += partscale.Z; collisionNormal.Z += 0.5f; Vector3 EndRayCastPosition = part.AbsolutePosition; Vector3 StartRayCastPosition = collisionPoint; Vector3 direction = EndRayCastPosition - StartRayCastPosition; float distance = direction.Length(); direction /= distance; m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastfindTop); }