private ContactResult[] ObjectIntersection(Vector3 rayStart, Vector3 rayEnd, bool includePhysical, bool includeNonPhysical, bool includePhantom) { Ray ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart)); List<ContactResult> contacts = new List<ContactResult>(); Vector3 ab = rayEnd - rayStart; World.ForEachSOG(delegate(SceneObjectGroup group) { if (m_host.ParentGroup == group) return; if (group.IsAttachment) return; if (group.RootPart.PhysActor == null) { if (!includePhantom) return; } else { if (group.RootPart.PhysActor.IsPhysical) { if (!includePhysical) return; } else { if (!includeNonPhysical) return; } } // Find the radius ouside of which we don't even need to hit test float minX; float maxX; float minY; float maxY; float minZ; float maxZ; float radius = 0.0f; group.GetAxisAlignedBoundingBoxRaw(out minX, out maxX, out minY, out maxY, out minZ, out maxZ); if (Math.Abs(minX) > radius) radius = Math.Abs(minX); if (Math.Abs(minY) > radius) radius = Math.Abs(minY); if (Math.Abs(minZ) > radius) radius = Math.Abs(minZ); if (Math.Abs(maxX) > radius) radius = Math.Abs(maxX); if (Math.Abs(maxY) > radius) radius = Math.Abs(maxY); if (Math.Abs(maxZ) > radius) radius = Math.Abs(maxZ); radius = radius*1.413f; Vector3 ac = group.AbsolutePosition - rayStart; // Vector3 bc = group.AbsolutePosition - rayEnd; double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); // Too far off ray, don't bother if (d > radius) return; // Behind ray, drop double d2 = Vector3.Dot(Vector3.Negate(ab), ac); if (d2 > 0) return; ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart)); EntityIntersection intersection = group.TestIntersection(ray, true, false); // Miss. if (!intersection.HitTF) return; Vector3 b1 = group.AbsolutePosition + new Vector3(minX, minY, minZ); Vector3 b2 = group.AbsolutePosition + new Vector3(maxX, maxY, maxZ); //m_log.DebugFormat("[LLCASTRAY]: min<{0},{1},{2}>, max<{3},{4},{5}> = hitp<{6},{7},{8}>", b1.X,b1.Y,b1.Z,b2.X,b2.Y,b2.Z,intersection.ipoint.X,intersection.ipoint.Y,intersection.ipoint.Z); if (!(intersection.ipoint.X >= b1.X && intersection.ipoint.X <= b2.X && intersection.ipoint.Y >= b1.Y && intersection.ipoint.Y <= b2.Y && intersection.ipoint.Z >= b1.Z && intersection.ipoint.Z <= b2.Z)) return; ContactResult result = new ContactResult (); result.ConsumerID = group.LocalId; result.Depth = intersection.distance; result.Normal = intersection.normal; result.Pos = intersection.ipoint; contacts.Add(result); }); return contacts.ToArray(); }
/// <summary> /// Gets a new rez location based on the raycast and the size of the object that is being rezzed. /// </summary> /// <param name="RayStart"></param> /// <param name="RayEnd"></param> /// <param name="RayTargetID"></param> /// <param name="rot"></param> /// <param name="bypassRayCast"></param> /// <param name="RayEndIsIntersection"></param> /// <param name="frontFacesOnly"></param> /// <param name="scale"></param> /// <param name="FaceCenter"></param> /// <returns></returns> public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter) { Vector3 dir = RayEnd - RayStart; float wheight = (float)RegionInfo.RegionSettings.WaterHeight; Vector3 wpos = Vector3.Zero; // Check for water surface intersection from above if ((RayStart.Z > wheight) && (RayEnd.Z < wheight)) { float ratio = (wheight - RayStart.Z) / dir.Z; wpos.X = RayStart.X + (ratio * dir.X); wpos.Y = RayStart.Y + (ratio * dir.Y); wpos.Z = wheight; } Vector3 pos = Vector3.Zero; if (RayEndIsIntersection != (byte)1) { float dist = dir.Length(); if (dist != 0) { Vector3 direction = dir * (1 / dist); dist += 1.0f; if (SupportsRayCastFiltered()) { RayFilterFlags rayfilter = RayFilterFlags.BackFaceCull; rayfilter |= RayFilterFlags.land; rayfilter |= RayFilterFlags.physical; rayfilter |= RayFilterFlags.nonphysical; rayfilter |= RayFilterFlags.LSLPhantom; // ubODE will only see volume detectors // get some more contacts ??? int physcount = 4; List<ContactResult> physresults = (List<ContactResult>)RayCastFiltered(RayStart, direction, dist, physcount, rayfilter); if (physresults != null && physresults.Count > 0) { // look for terrain ? if(RayTargetID == UUID.Zero) { foreach (ContactResult r in physresults) { if (r.ConsumerID == 0) { pos = r.Normal * scale; pos *= 0.5f; pos = r.Pos + pos; if (wpos.Z > pos.Z) pos = wpos; return pos; } } } else { foreach (ContactResult r in physresults) { SceneObjectPart part = GetSceneObjectPart(r.ConsumerID); if (part == null) continue; if (part.UUID == RayTargetID) { pos = r.Normal * scale; pos *= 0.5f; pos = r.Pos + pos; if (wpos.Z > pos.Z) pos = wpos; return pos; } } } // else the first we got pos = physresults[0].Normal * scale; pos *= 0.5f; pos = physresults[0].Pos + pos; if (wpos.Z > pos.Z) pos = wpos; return pos; } } if (RayTargetID != UUID.Zero) { SceneObjectPart target = GetSceneObjectPart(RayTargetID); Ray NewRay = new Ray(RayStart, direction); if (target != null) { pos = target.AbsolutePosition; // Ray Trace against target here EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); // Un-comment out the following line to Get Raytrace results printed to the console. // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); float ScaleOffset = 0.5f; // If we hit something if (ei.HitTF) { Vector3 scaleComponent = ei.AAfaceNormal; if (scaleComponent.X != 0) ScaleOffset = scale.X; if (scaleComponent.Y != 0) ScaleOffset = scale.Y; if (scaleComponent.Z != 0) ScaleOffset = scale.Z; ScaleOffset = Math.Abs(ScaleOffset); Vector3 intersectionpoint = ei.ipoint; Vector3 normal = ei.normal; // Set the position to the intersection point Vector3 offset = (normal * (ScaleOffset / 2f)); pos = (intersectionpoint + offset); //Seems to make no sense to do this as this call is used for rezzing from inventory as well, and with inventory items their size is not always 0.5f //And in cases when we weren't rezzing from inventory we were re-adding the 0.25 straight after calling this method // Un-offset the prim (it gets offset later by the consumer method) //pos.Z -= 0.25F; if (wpos.Z > pos.Z) pos = wpos; return pos; } } else { // We don't have a target here, so we're going to raytrace all the objects in the scene. EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(NewRay, true, false); // Un-comment the following line to print the raytrace results to the console. //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); if (ei.HitTF) { pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); } else { // fall back to our stupid functionality pos = RayEnd; } if (wpos.Z > pos.Z) pos = wpos; return pos; } } } } // fall back to our stupid functionality pos = RayEnd; //increase height so its above the ground. //should be getting the normal of the ground at the rez point and using that? pos.Z += scale.Z / 2f; // return pos; // check against posible water intercept if (wpos.Z > pos.Z) pos = wpos; return pos; }
public void getLineOfSight() { string pathID = getPathID(); PathFromTxToRy path = new PathFromTxToRy(this, transmitter.RootPart.AbsolutePosition, pathID); //Direction from transmitter to the reciever Vector3 direction = receiver.RootPart.AbsolutePosition - transmitter.RootPart.AbsolutePosition; //Ray vector from transmitter to the receiver Ray ray = new Ray(transmitter.RootPart.AbsolutePosition, direction); //Get the first object the ray hit EntityIntersectionWithPart intersection = findNextHit(ray, transmitter.RootPart); path.addNextPoint(receiver.RootPart.AbsolutePosition, receiver.RootPart.Material); path.reachesReceiver = true; if (!checkPathIsDrawn(path)) { pathHits[0].Add(pathID, path); } }
public EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters) { // We got a request from the inner_scene to raytrace along the Ray hRay // We're going to check all of the prim in this group for intersection with the ray // If we get a result, we're going to find the closest result to the origin of the ray // and send back the intersection information back to the innerscene. EntityIntersection result = new EntityIntersection(); SceneObjectPart[] parts = m_parts.GetArray(); // Find closest hit here float idist = float.MaxValue; for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; // Temporary commented to stop compiler warning //Vector3 partPosition = // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); Quaternion parentrotation = GroupRotation; // Telling the prim to raytrace. //EntityIntersection inter = part.TestIntersection(hRay, parentrotation); EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); if (inter.HitTF) { // We need to find the closest prim to return to the testcaller along the ray if (inter.distance < idist) { result.HitTF = true; result.ipoint = inter.ipoint; result.obj = part; result.normal = inter.normal; result.distance = inter.distance; idist = inter.distance; } } } return result; }
/// <summary> /// Duplicates object specified by localID at position raycasted against RayTargetObject using /// RayEnd and RayStart to determine what the angle of the ray is /// </summary> /// <param name="localID">ID of object to duplicate</param> /// <param name="dupeFlags"></param> /// <param name="AgentID">Agent doing the duplication</param> /// <param name="GroupID">Group of new object</param> /// <param name="RayTargetObj">The target of the Ray</param> /// <param name="RayEnd">The ending of the ray (farthest away point)</param> /// <param name="RayStart">The Beginning of the ray (closest point)</param> /// <param name="BypassRaycast">Bool to bypass raycasting</param> /// <param name="RayEndIsIntersection">The End specified is the place to add the object</param> /// <param name="CopyCenters">Position the object at the center of the face that it's colliding with</param> /// <param name="CopyRotates">Rotate the object the same as the localID object</param> public void doObjectDuplicateOnRay(uint localID, uint dupeFlags, UUID AgentID, UUID GroupID, UUID RayTargetObj, Vector3 RayEnd, Vector3 RayStart, bool BypassRaycast, bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates) { Vector3 pos; const bool frontFacesOnly = true; //m_log.Info("HITTARGET: " + RayTargetObj.ToString() + ", COPYTARGET: " + localID.ToString()); SceneObjectPart target = GetSceneObjectPart(localID); SceneObjectPart target2 = GetSceneObjectPart(RayTargetObj); if (target != null && target2 != null) { Vector3 direction = Vector3.Normalize(RayEnd - RayStart); Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z); Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z); pos = target2.AbsolutePosition; //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString()); // TODO: Raytrace better here //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection)); Ray NewRay = new Ray(AXOrigin, AXdirection); // Ray Trace against target here EntityIntersection ei = target2.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, CopyCenters); // Un-comment out the following line to Get Raytrace results printed to the console. //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); float ScaleOffset = 0.5f; // If we hit something if (ei.HitTF) { Vector3 scale = target.Scale; Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z); if (scaleComponent.X != 0) ScaleOffset = scale.X; if (scaleComponent.Y != 0) ScaleOffset = scale.Y; if (scaleComponent.Z != 0) ScaleOffset = scale.Z; ScaleOffset = Math.Abs(ScaleOffset); Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z); Vector3 offset = normal * (ScaleOffset / 2f); pos = intersectionpoint + offset; // stick in offset format from the original prim pos = pos - target.ParentGroup.AbsolutePosition; SceneObjectGroup copy; if (CopyRotates) { Quaternion worldRot = target2.GetWorldRotation(); // SceneObjectGroup obj = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot); copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot); //obj.Rotation = worldRot; //obj.UpdateGroupRotationR(worldRot); } else { copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, Quaternion.Identity); } if (copy != null) EventManager.TriggerObjectAddedToScene(copy); } } }
public EntityIntersection TestIntersectionOBB(Ray iray, Quaternion parentrot, bool frontFacesOnly, bool faceCenters) { // In this case we're using a rectangular prism, which has 6 faces and therefore 6 planes // This breaks down into the ray---> plane equation. // TODO: Change to take shape into account Vector3[] vertexes = new Vector3[8]; // float[] distance = new float[6]; Vector3[] FaceA = new Vector3[6]; // vertex A for Facei Vector3[] FaceB = new Vector3[6]; // vertex B for Facei Vector3[] FaceC = new Vector3[6]; // vertex C for Facei Vector3[] FaceD = new Vector3[6]; // vertex D for Facei Vector3[] normals = new Vector3[6]; // Normal for Facei Vector3[] AAfacenormals = new Vector3[6]; // Axis Aligned face normals AAfacenormals[0] = new Vector3(1, 0, 0); AAfacenormals[1] = new Vector3(0, 1, 0); AAfacenormals[2] = new Vector3(-1, 0, 0); AAfacenormals[3] = new Vector3(0, -1, 0); AAfacenormals[4] = new Vector3(0, 0, 1); AAfacenormals[5] = new Vector3(0, 0, -1); Vector3 AmBa = new Vector3(0, 0, 0); // Vertex A - Vertex B Vector3 AmBb = new Vector3(0, 0, 0); // Vertex B - Vertex C Vector3 cross = new Vector3(); Vector3 pos = GetWorldPosition(); Quaternion rot = GetWorldRotation(); // Variables prefixed with AX are Axiom.Math copies of the LL variety. Quaternion AXrot = rot; AXrot.Normalize(); Vector3 AXpos = pos; // tScale is the offset to derive the vertex based on the scale. // it's different for each vertex because we've got to rotate it // to get the world position of the vertex to produce the Oriented Bounding Box Vector3 tScale = Vector3.Zero; Vector3 AXscale = new Vector3(m_shape.Scale.X * 0.5f, m_shape.Scale.Y * 0.5f, m_shape.Scale.Z * 0.5f); //Vector3 pScale = (AXscale) - (AXrot.Inverse() * (AXscale)); //Vector3 nScale = (AXscale * -1) - (AXrot.Inverse() * (AXscale * -1)); // rScale is the rotated offset to find a vertex based on the scale and the world rotation. Vector3 rScale = new Vector3(); // Get Vertexes for Faces Stick them into ABCD for each Face // Form: Face<vertex>[face] that corresponds to the below diagram #region ABCD Face Vertex Map Comment Diagram // A _________ B // | | // | 4 top | // |_________| // C D // A _________ B // | Back | // | 3 | // |_________| // C D // A _________ B B _________ A // | Left | | Right | // | 0 | | 2 | // |_________| |_________| // C D D C // A _________ B // | Front | // | 1 | // |_________| // C D // C _________ D // | | // | 5 bot | // |_________| // A B #endregion #region Plane Decomposition of Oriented Bounding Box tScale = new Vector3(AXscale.X, -AXscale.Y, AXscale.Z); rScale = tScale * AXrot; vertexes[0] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); // vertexes[0].X = pos.X + vertexes[0].X; //vertexes[0].Y = pos.Y + vertexes[0].Y; //vertexes[0].Z = pos.Z + vertexes[0].Z; FaceA[0] = vertexes[0]; FaceB[3] = vertexes[0]; FaceA[4] = vertexes[0]; tScale = AXscale; rScale = tScale * AXrot; vertexes[1] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); // vertexes[1].X = pos.X + vertexes[1].X; // vertexes[1].Y = pos.Y + vertexes[1].Y; //vertexes[1].Z = pos.Z + vertexes[1].Z; FaceB[0] = vertexes[1]; FaceA[1] = vertexes[1]; FaceC[4] = vertexes[1]; tScale = new Vector3(AXscale.X, -AXscale.Y, -AXscale.Z); rScale = tScale * AXrot; vertexes[2] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); //vertexes[2].X = pos.X + vertexes[2].X; //vertexes[2].Y = pos.Y + vertexes[2].Y; //vertexes[2].Z = pos.Z + vertexes[2].Z; FaceC[0] = vertexes[2]; FaceD[3] = vertexes[2]; FaceC[5] = vertexes[2]; tScale = new Vector3(AXscale.X, AXscale.Y, -AXscale.Z); rScale = tScale * AXrot; vertexes[3] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); //vertexes[3].X = pos.X + vertexes[3].X; // vertexes[3].Y = pos.Y + vertexes[3].Y; // vertexes[3].Z = pos.Z + vertexes[3].Z; FaceD[0] = vertexes[3]; FaceC[1] = vertexes[3]; FaceA[5] = vertexes[3]; tScale = new Vector3(-AXscale.X, AXscale.Y, AXscale.Z); rScale = tScale * AXrot; vertexes[4] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); // vertexes[4].X = pos.X + vertexes[4].X; // vertexes[4].Y = pos.Y + vertexes[4].Y; // vertexes[4].Z = pos.Z + vertexes[4].Z; FaceB[1] = vertexes[4]; FaceA[2] = vertexes[4]; FaceD[4] = vertexes[4]; tScale = new Vector3(-AXscale.X, AXscale.Y, -AXscale.Z); rScale = tScale * AXrot; vertexes[5] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); // vertexes[5].X = pos.X + vertexes[5].X; // vertexes[5].Y = pos.Y + vertexes[5].Y; // vertexes[5].Z = pos.Z + vertexes[5].Z; FaceD[1] = vertexes[5]; FaceC[2] = vertexes[5]; FaceB[5] = vertexes[5]; tScale = new Vector3(-AXscale.X, -AXscale.Y, AXscale.Z); rScale = tScale * AXrot; vertexes[6] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); // vertexes[6].X = pos.X + vertexes[6].X; // vertexes[6].Y = pos.Y + vertexes[6].Y; // vertexes[6].Z = pos.Z + vertexes[6].Z; FaceB[2] = vertexes[6]; FaceA[3] = vertexes[6]; FaceB[4] = vertexes[6]; tScale = new Vector3(-AXscale.X, -AXscale.Y, -AXscale.Z); rScale = tScale * AXrot; vertexes[7] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); // vertexes[7].X = pos.X + vertexes[7].X; // vertexes[7].Y = pos.Y + vertexes[7].Y; // vertexes[7].Z = pos.Z + vertexes[7].Z; FaceD[2] = vertexes[7]; FaceC[3] = vertexes[7]; FaceD[5] = vertexes[7]; #endregion // Get our plane normals for (int i = 0; i < 6; i++) { //m_log.Info("[FACECALCULATION]: FaceA[" + i + "]=" + FaceA[i] + " FaceB[" + i + "]=" + FaceB[i] + " FaceC[" + i + "]=" + FaceC[i] + " FaceD[" + i + "]=" + FaceD[i]); // Our Plane direction AmBa = FaceA[i] - FaceB[i]; AmBb = FaceB[i] - FaceC[i]; cross = Vector3.Cross(AmBb, AmBa); // normalize the cross product to get the normal. normals[i] = cross / cross.Length(); //m_log.Info("[NORMALS]: normals[ " + i + "]" + normals[i].ToString()); //distance[i] = (normals[i].X * AmBa.X + normals[i].Y * AmBa.Y + normals[i].Z * AmBa.Z) * -1; } EntityIntersection result = new EntityIntersection(); result.distance = 1024; float c = 0; float a = 0; float d = 0; Vector3 q = new Vector3(); #region OBB Version 2 Experiment //float fmin = 999999; //float fmax = -999999; //float s = 0; //for (int i=0;i<6;i++) //{ //s = iray.Direction.Dot(normals[i]); //d = normals[i].Dot(FaceB[i]); //if (s == 0) //{ //if (iray.Origin.Dot(normals[i]) > d) //{ //return result; //} // else //{ //continue; //} //} //a = (d - iray.Origin.Dot(normals[i])) / s; //if (iray.Direction.Dot(normals[i]) < 0) //{ //if (a > fmax) //{ //if (a > fmin) //{ //return result; //} //fmax = a; //} //} //else //{ //if (a < fmin) //{ //if (a < 0 || a < fmax) //{ //return result; //} //fmin = a; //} //} //} //if (fmax > 0) // a= fmax; //else // a=fmin; //q = iray.Origin + a * iray.Direction; #endregion // Loop over faces (6 of them) for (int i = 0; i < 6; i++) { AmBa = FaceA[i] - FaceB[i]; AmBb = FaceB[i] - FaceC[i]; d = Vector3.Dot(normals[i], FaceB[i]); //if (faceCenters) //{ // c = normals[i].Dot(normals[i]); //} //else //{ c = Vector3.Dot(iray.Direction, normals[i]); //} if (c == 0) continue; a = (d - Vector3.Dot(iray.Origin, normals[i])) / c; if (a < 0) continue; // If the normal is pointing outside the object if (Vector3.Dot(iray.Direction, normals[i]) < 0 || !frontFacesOnly) { //if (faceCenters) //{ //(FaceA[i] + FaceB[i] + FaceC[1] + FaceD[i]) / 4f; // q = iray.Origin + a * normals[i]; //} //else //{ q = iray.Origin + iray.Direction * a; //} float distance2 = (float)GetDistanceTo(q, AXpos); // Is this the closest hit to the object's origin? //if (faceCenters) //{ // distance2 = (float)GetDistanceTo(q, iray.Origin); //} if (distance2 < result.distance) { result.distance = distance2; result.HitTF = true; result.ipoint = q; //m_log.Info("[FACE]:" + i.ToString()); //m_log.Info("[POINT]: " + q.ToString()); //m_log.Info("[DIST]: " + distance2.ToString()); if (faceCenters) { result.normal = AAfacenormals[i] * AXrot; Vector3 scaleComponent = AAfacenormals[i]; float ScaleOffset = 0.5f; if (scaleComponent.X != 0) ScaleOffset = AXscale.X; if (scaleComponent.Y != 0) ScaleOffset = AXscale.Y; if (scaleComponent.Z != 0) ScaleOffset = AXscale.Z; ScaleOffset = Math.Abs(ScaleOffset); Vector3 offset = result.normal * ScaleOffset; result.ipoint = AXpos + offset; ///pos = (intersectionpoint + offset); } else { result.normal = normals[i]; } result.AAfaceNormal = AAfacenormals[i]; } } } return result; }
protected internal EntityIntersection GetClosestIntersectingPrim(Ray hray, bool frontFacesOnly, bool faceCenters) { // Primitive Ray Tracing float closestDistance = 280f; EntityIntersection returnResult = new EntityIntersection(); List<EntityBase> EntityList = GetEntities(); foreach (EntityBase ent in EntityList) { if (ent is SceneObjectGroup) { SceneObjectGroup reportingG = (SceneObjectGroup)ent; EntityIntersection result = reportingG.TestIntersection(hray, frontFacesOnly, faceCenters); if (result.HitTF) { if (result.distance < closestDistance) { closestDistance = result.distance; returnResult = result; } } } } return returnResult; }
/// <summary> /// Duplicates object specified by localID at position raycasted against RayTargetObject using /// RayEnd and RayStart to determine what the angle of the ray is /// </summary> /// <param name="localID">ID of object to duplicate</param> /// <param name="dupeFlags"></param> /// <param name="AgentID">Agent doing the duplication</param> /// <param name="GroupID">Group of new object</param> /// <param name="RayTargetObj">The target of the Ray</param> /// <param name="RayEnd">The ending of the ray (farthest away point)</param> /// <param name="RayStart">The Beginning of the ray (closest point)</param> /// <param name="BypassRaycast">Bool to bypass raycasting</param> /// <param name="RayEndIsIntersection">The End specified is the place to add the object</param> /// <param name="CopyCenters">Position the object at the center of the face that it's colliding with</param> /// <param name="CopyRotates">Rotate the object the same as the localID object</param> public void doObjectDuplicateOnRay(uint localID, uint dupeFlags, UUID AgentID, UUID GroupID, UUID RayTargetObj, Vector3 RayEnd, Vector3 RayStart, bool BypassRaycast, bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates) { const bool frontFacesOnly = true; //MainConsole.Instance.Info("HITTARGET: " + RayTargetObj.ToString() + ", COPYTARGET: " + localID.ToString()); ISceneChildEntity target = m_parentScene.GetSceneObjectPart(localID); ISceneChildEntity target2 = m_parentScene.GetSceneObjectPart(RayTargetObj); IScenePresence Sp = GetScenePresence(AgentID); if (target != null && target2 != null) { Vector3 pos; if (EnableFakeRaycasting) { RayStart = Sp.CameraPosition; RayEnd = pos = target2.AbsolutePosition; } Vector3 direction = Vector3.Normalize(RayEnd - RayStart); Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z); Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z); if (target2.ParentEntity != null) { pos = target2.AbsolutePosition; // TODO: Raytrace better here //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), false, false); Ray NewRay = new Ray(AXOrigin, AXdirection); // Ray Trace against target here EntityIntersection ei = target2.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, CopyCenters); // Un-comment out the following line to Get Raytrace results printed to the console. //MainConsole.Instance.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); float ScaleOffset = 0.5f; // If we hit something if (ei.HitTF) { Vector3 scale = target.Scale; Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z); if (scaleComponent.X != 0) ScaleOffset = scale.X; if (scaleComponent.Y != 0) ScaleOffset = scale.Y; if (scaleComponent.Z != 0) ScaleOffset = scale.Z; ScaleOffset = Math.Abs(ScaleOffset); Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z); Vector3 offset = normal*(ScaleOffset/2f); pos = intersectionpoint + offset; // stick in offset format from the original prim pos = pos - target.ParentEntity.AbsolutePosition; if (CopyRotates) { Quaternion worldRot = target2.GetWorldRotation(); // SceneObjectGroup obj = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot); DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot); //obj.Rotation = worldRot; //obj.UpdateGroupRotationR(worldRot); } else { DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, Quaternion.Identity); } } return; } return; } }
void RezObjectHandler(Packet packet, LLAgent agent) { RezObjectPacket rez = (RezObjectPacket)packet; // Find the target position Vector3 position = Vector3.Zero; Vector3 linksetScale = Vector3.Zero; bool bypassRaycast = (rez.RezData.BypassRaycast == 1); //bool rayEndIsIntersection = rez.RezData.RayEndIsIntersection; #region Position Calculation if (bypassRaycast || m_physics == null) { position = rez.RezData.RayEnd; } else { Vector3 direction = (rez.RezData.RayEnd - rez.RezData.RayStart); direction /= direction.Length(); Ray ray = new Ray(rez.RezData.RayStart, direction); ISceneEntity collisionObj; float collisionDist; if (m_physics.FullSceneCollisionTest(true, ray, null, out collisionObj, out collisionDist)) { position = ray.GetPoint(collisionDist); } else { m_log.Warn("Full scene collision test for ray " + ray + " failed"); position = agent.ScenePosition + Vector3.UnitZ; } } position.Z += linksetScale.Z * 0.5f; #endregion Position Calculation InventoryBase invObject; if (m_inventoryClient.TryGetInventory(agent.ID, rez.InventoryData.ItemID, out invObject) & invObject is InventoryItem) { InventoryItem item = (InventoryItem)invObject; Asset asset; if (m_assetClient.TryGetAsset(item.AssetID, item.ContentType, out asset)) { #region Object Deserialization/Rezzing // Deserialize the asset data into a linkset using (MemoryStream stream = new MemoryStream(asset.Data)) { OSDMap linksetMap = OSDParser.DeserializeJson(stream) as OSDMap; if (linksetMap != null) { IList<LLPrimitive> linkset = LLPrimitive.DeserializeLinkset(linksetMap, m_scene, m_primMesher, true); // Rez the parent(s) first for (int i = 0; i < linkset.Count; i++) { LLPrimitive prim = linkset[i]; // Make sure the ownerID is set correctly prim.OwnerID = agent.ID; if (prim.Parent == null) { RezSinglePrim(prim, rez.RezData, position); m_log.Debug("Deserialized root prim " + prim.ID + " (" + prim.LocalID + ") from inventory"); } } // Rez the children for (int i = 0; i < linkset.Count; i++) { if (linkset[i].Parent != null) RezSinglePrim(linkset[i], rez.RezData, position); } // FIXME: Use these to determine if we need to delete the source inventory or task item //rez.RezData.FromTaskID //rez.RezData.RemoveItem } else { m_log.WarnFormat("Failed to deserialize asset {0} ({1} bytes, Content-Type: {2}) into a linkset", asset.ID, asset.Data.Length, asset.ContentType); } } #endregion Object Deserialization/Rezzing } else { m_log.Warn(agent.Name + "'s RezObject failed to retrieve asset " + item.AssetID); } } else { m_log.Warn(agent.Name + " called RezObject for unknown item " + rez.InventoryData.ItemID); } }
void ObjectAddHandler(Packet packet, LLAgent agent) { if (!agent.IsVerified) { m_scene.PresenceAlert(this, agent, "You are logged in with an unverified account. Object creation is disabled."); return; } ObjectAddPacket add = (ObjectAddPacket)packet; Vector3 position = Vector3.Zero; Vector3 scale = add.ObjectData.Scale; PCode pcode = (PCode)add.ObjectData.PCode; PrimFlags flags = (PrimFlags)add.ObjectData.AddFlags; bool bypassRaycast = (add.ObjectData.BypassRaycast == 1); //bool rayEndIsIntersection = (add.ObjectData.RayEndIsIntersection == 1); #region Position Calculation if (bypassRaycast) { position = add.ObjectData.RayEnd; } else if (m_physics != null) { Vector3 direction = (add.ObjectData.RayEnd - add.ObjectData.RayStart); direction /= direction.Length(); Ray ray = new Ray(add.ObjectData.RayStart, direction); ISceneEntity collisionObj; float collisionDist; if (m_physics.FullSceneCollisionTest(true, ray, null, out collisionObj, out collisionDist)) { position = ray.GetPoint(collisionDist); } else { m_log.Warn("Full scene collision test for ray " + ray + " failed"); position = agent.ScenePosition + Vector3.UnitZ; } } position.Z += scale.Z * 0.5f; #endregion Position Calculation if (!CanAddPrims(agent, position, 1)) return; #region Foliage Handling // Set all foliage to phantom if (pcode == PCode.Grass || pcode == PCode.Tree || pcode == PCode.NewTree) { flags |= PrimFlags.Phantom; if (pcode != PCode.Grass) { // Resize based on the foliage type Tree tree = (Tree)add.ObjectData.State; switch (tree) { case Tree.Cypress1: case Tree.Cypress2: scale = new Vector3(4f, 4f, 10f); break; default: scale = new Vector3(4f, 4f, 4f); break; } } } #endregion Foliage Handling #region Prim Creation // Create an object Primitive prim = new Primitive(); prim.Flags = PrimFlags.CastShadows | PrimFlags.InventoryEmpty; prim.Flags |= (PrimFlags)add.ObjectData.AddFlags; // TODO: Security check prim.GroupID = add.AgentData.GroupID; prim.ID = UUID.Random(); prim.MediaURL = String.Empty; prim.OwnerID = agent.ID; prim.Position = position; prim.PrimData.Material = (Material)add.ObjectData.Material; prim.PrimData.PathCurve = (PathCurve)add.ObjectData.PathCurve; prim.PrimData.ProfileCurve = (ProfileCurve)add.ObjectData.ProfileCurve; prim.PrimData.PathBegin = Primitive.UnpackBeginCut(add.ObjectData.PathBegin); prim.PrimData.PathEnd = Primitive.UnpackEndCut(add.ObjectData.PathEnd); prim.PrimData.PathScaleX = Primitive.UnpackPathScale(add.ObjectData.PathScaleX); prim.PrimData.PathScaleY = Primitive.UnpackPathScale(add.ObjectData.PathScaleY); prim.PrimData.PathShearX = Primitive.UnpackPathShear((sbyte)add.ObjectData.PathShearX); prim.PrimData.PathShearY = Primitive.UnpackPathShear((sbyte)add.ObjectData.PathShearY); prim.PrimData.PathTwist = Primitive.UnpackPathTwist(add.ObjectData.PathTwist); prim.PrimData.PathTwistBegin = Primitive.UnpackPathTwist(add.ObjectData.PathTwistBegin); prim.PrimData.PathRadiusOffset = Primitive.UnpackPathTwist(add.ObjectData.PathRadiusOffset); prim.PrimData.PathTaperX = Primitive.UnpackPathTaper(add.ObjectData.PathTaperX); prim.PrimData.PathTaperY = Primitive.UnpackPathTaper(add.ObjectData.PathTaperY); prim.PrimData.PathRevolutions = Primitive.UnpackPathRevolutions(add.ObjectData.PathRevolutions); prim.PrimData.PathSkew = Primitive.UnpackPathTwist(add.ObjectData.PathSkew); prim.PrimData.ProfileBegin = Primitive.UnpackBeginCut(add.ObjectData.ProfileBegin); prim.PrimData.ProfileEnd = Primitive.UnpackEndCut(add.ObjectData.ProfileEnd); prim.PrimData.ProfileHollow = Primitive.UnpackProfileHollow(add.ObjectData.ProfileHollow); prim.PrimData.PCode = pcode; prim.Properties = new Primitive.ObjectProperties(); prim.Properties.CreationDate = DateTime.UtcNow; prim.Properties.CreatorID = agent.ID; prim.Properties.Description = String.Empty; prim.Properties.GroupID = add.AgentData.GroupID; prim.Properties.LastOwnerID = agent.ID; prim.Properties.Name = "Object"; prim.Properties.ObjectID = prim.ID; prim.Properties.OwnerID = prim.OwnerID; prim.Properties.Permissions = m_permissions.GetDefaultPermissions(); prim.Properties.SalePrice = 10; prim.Rotation = add.ObjectData.Rotation; prim.Scale = scale; prim.TextColor = Color4.Black; if (pcode == PCode.Prim) { prim.Textures = new Primitive.TextureEntry(PLYWOOD_TEXTURE); } #endregion Prim Creation // Add this prim to the scene ISceneEntity primObj = new LLPrimitive(prim, m_scene, m_primMesher); m_scene.EntityAddOrUpdate(this, primObj, UpdateFlags.FullUpdate, 0); }
/// <summary> /// Gets a new rez location based on the raycast and the size of the object that is being rezzed. /// </summary> /// <param name="RayStart"></param> /// <param name="RayEnd"></param> /// <param name="RayTargetID"></param> /// <param name="rot"></param> /// <param name="bypassRayCast"></param> /// <param name="RayEndIsIntersection"></param> /// <param name="frontFacesOnly"></param> /// <param name="scale"></param> /// <param name="FaceCenter"></param> /// <returns></returns> public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter) { Vector3 pos = Vector3.Zero; if (RayEndIsIntersection == 1) { pos = RayEnd; return pos; } if (RayTargetID != UUID.Zero) { ISceneChildEntity target = m_parentScene.GetSceneObjectPart(RayTargetID); Vector3 direction = Vector3.Normalize(RayEnd - RayStart); Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z); Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z); if (target != null) { pos = target.AbsolutePosition; //MainConsole.Instance.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString()); // TODO: Raytrace better here Ray NewRay = new Ray(AXOrigin, AXdirection); // Ray Trace against target here EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); // Un-comment out the following line to Get Raytrace results printed to the console. //MainConsole.Instance.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); float ScaleOffset = 0.5f; // If we hit something if (ei.HitTF) { Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z); if (scaleComponent.X != 0) ScaleOffset = scale.X; if (scaleComponent.Y != 0) ScaleOffset = scale.Y; if (scaleComponent.Z != 0) ScaleOffset = scale.Z; ScaleOffset = Math.Abs(ScaleOffset); Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z); // Set the position to the intersection point Vector3 offset = (normal*(ScaleOffset/2f)); pos = (intersectionpoint + offset); } return pos; } else { // We don't have a target here, so we're going to raytrace all the objects in the scene. EntityIntersection ei = GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false); // Un-comment the following line to print the raytrace results to the console. //MainConsole.Instance.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); pos = ei.HitTF ? new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z) : RayEnd; return pos; } } // fall back to our stupid functionality pos = RayEnd; //increase height so its above the ground. //should be getting the normal of the ground at the rez point and using that? pos.Z += scale.Z/2f; return pos; }
/// <summary> /// A method which find the first object the ray hit. This is done by comparing distances. /// The smallest distance is the distance between the intersection point and the ray start point. /// </summary> /// <param name="ray">The ray which will be used to test the intersection against each part in the scene</param> /// <param name="source">An object which the ray start from. We need this to make sure that the shortest /// distance isn't zero (from itself to itself)</param> /// <returns>Intersection point with True if this ray intersect something, or false if nothing at all</returns> public EntityIntersectionWithPart findNextHit(Ray ray, SceneObjectPart source) { float smallestDistance = 1000000f; EntityIntersection closestIntersection = new EntityIntersection(); SceneObjectPart closestPart = new SceneObjectPart(); foreach (SceneObjectPart part in worldObjects) { if (!part.Equals(source)) //Cannot intersect itself (i.e. ignore/do nothing when it is itself) { //Test if the ray intersect this part. EntityIntersection intersection; if (part.GetPrimType() == OpenSim.Region.Framework.Scenes.PrimType.SPHERE) { intersection = part.TestIntersection(ray, part.ParentGroup.GroupRotation); } else { intersection = part.TestIntersectionOBB(ray, part.ParentGroup.GroupRotation, true, false); } //If it intersects, then check again with another method checkPointIntersectPrim(). if (intersection.HitTF && checkPointIntersectPrim(intersection.ipoint, part, 0.1f)) { //If yes, then remember this distance and this intersection as the current 'return' candidate if (intersection.distance < smallestDistance) { smallestDistance = intersection.distance; closestIntersection = intersection; closestPart = part; }//if }//if }//if }//foreach return new EntityIntersectionWithPart(closestIntersection, closestPart); }
/// <summary> /// A recursive method which trace a ray until its power is less than ray-minimum power thershold /// </summary> /// <param name="path">New PathFromTxToRy object.</param> /// <param name="ray">A starting ray (first ray)</param> /// <param name="lastIntersectPart">A world object which this ray last intersect, or start</param> /// <returns>PathFromTxToRy with True if it reaches receiver and False if it did not reach the receiver.</returns> public PathFromTxToRy traceRay(PathFromTxToRy path, Ray ray, SceneObjectPart lastIntersectPart) { EntityIntersectionWithPart nextHit = findNextHit(ray, transmitter.RootPart); if (nextHit.intersection.HitTF) { //Check for limit number of reflection allowed. if(path.getNoOfReflection() >= MAX_REFLECTIONS) { path.reachesReceiver = false; return path; } //drawRay(ray.Origin, nextHit.intersection.ipoint); else if (nextHit.intersectPart.Equals(receiver.RootPart)) //If it reaches the receiver { path.reachesReceiver = true; path.addNextPoint(nextHit.intersection.ipoint, receiver.RootPart.Material); return path; }//if //recursive case, keep tracing this ray. else { path.addNextPoint(nextHit.intersection.ipoint, nextHit.intersectPart.Material); Vector3 reflectedVector = getReflectedVector(ray.Direction, nextHit.intersection.normal); Ray newRay = new Ray(nextHit.intersection.ipoint, reflectedVector); return traceRay(path, newRay, nextHit.intersectPart); }//else if } else //It didn't hit anything { path.reachesReceiver = false; return path; }//else }
/// <summary> /// Get a scene object group that contains the prim with the given uuid /// </summary> /// <param name="hray"></param> /// <param name="frontFacesOnly"></param> /// <param name="faceCenters"></param> /// <returns>null if no scene object group containing that prim is found</returns> protected internal EntityIntersection GetClosestIntersectingPrim(Ray hray, bool frontFacesOnly, bool faceCenters) { // Primitive Ray Tracing float closestDistance = 280f; EntityIntersection result = new EntityIntersection(); ISceneEntity[] EntityList = Entities.GetEntities(hray.Origin, closestDistance); foreach (ISceneEntity ent in EntityList) { if (ent is SceneObjectGroup) { SceneObjectGroup reportingG = (SceneObjectGroup) ent; EntityIntersection inter = reportingG.TestIntersection(hray, frontFacesOnly, faceCenters); if (inter.HitTF && inter.distance < closestDistance) { closestDistance = inter.distance; result = inter; } } } return result; }
public bool EntityCollisionTest(Ray ray, IPhysical obj, out float distance) { float unused; return RayAABB.CollisionTestSmits(obj.SceneAABB, ray, out distance, out unused); }
/// <summary> /// Gets a list of scene object group that intersect with the given ray /// </summary> public List<EntityIntersection> GetIntersectingPrims(Ray hray, float length, int count, bool frontFacesOnly, bool faceCenters, bool getAvatars, bool getLand, bool getPrims) { // Primitive Ray Tracing List<EntityIntersection> result = new List<EntityIntersection>(count); if (getPrims) { ISceneEntity[] EntityList = Entities.GetEntities(hray.Origin, length); result.AddRange( EntityList.OfType<SceneObjectGroup>() .Select(reportingG => reportingG.TestIntersection(hray, frontFacesOnly, faceCenters)) .Where(inter => inter.HitTF)); } if (getAvatars) { List<IScenePresence> presenceList = Entities.GetPresences(); foreach (IScenePresence ent in presenceList) { //Do rough approximation and keep the # of loops down Vector3 newPos = hray.Origin; for (int i = 0; i < 100; i++) { newPos += ((Vector3.One*(length*(i/100)))*hray.Direction); if (ent.AbsolutePosition.ApproxEquals(newPos, ent.PhysicsActor.Size.X*2)) { EntityIntersection intersection = new EntityIntersection(); intersection.distance = length*(i/100); intersection.face = 0; intersection.HitTF = true; intersection.obj = ent; intersection.ipoint = newPos; intersection.normal = newPos; result.Add(intersection); break; } } } } if (getLand) { //TODO } result.Sort((a, b) => a.distance.CompareTo(b.distance)); if (result.Count > count) result.RemoveRange(count, result.Count - count); return result; }
public bool FullSceneCollisionTest(bool includeTerrain, Ray ray, ISceneEntity castingObj, out ISceneEntity collisionObj, out float dist) { ISceneEntity minCollider = null; float minDist = Single.MaxValue; // Test against the AABB of every entity in the scene (can be slow!) m_scene.ForEachEntity( delegate(ISceneEntity entity) { if (entity == castingObj) return; float thisDist; if (entity is IPhysical && EntityCollisionTest(ray, (IPhysical)entity, out thisDist) && thisDist < minDist) { minDist = thisDist; minCollider = entity; } } ); collisionObj = minCollider; dist = minDist; if (includeTerrain) { // Test against the terrain float terrainDist; if (RayHeightmap.CollisionTest(ray, m_terrain.GetHeightmap(), 256, 256, 256.0f, out terrainDist) && terrainDist < dist) { dist = terrainDist; collisionObj = null; return true; } } return collisionObj != null; }
/// <summary> /// Gets a new rez location based on the raycast and the size of the object that is being rezzed. /// </summary> /// <param name="RayStart"></param> /// <param name="RayEnd"></param> /// <param name="RayTargetID"></param> /// <param name="rot"></param> /// <param name="bypassRayCast"></param> /// <param name="RayEndIsIntersection"></param> /// <param name="frontFacesOnly"></param> /// <param name="scale"></param> /// <param name="FaceCenter"></param> /// <returns></returns> public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter) { Vector3 pos = Vector3.Zero; if (RayEndIsIntersection == (byte)1) { pos = RayEnd; return pos; } if (RayTargetID != UUID.Zero) { SceneObjectPart target = GetSceneObjectPart(RayTargetID); Vector3 direction = Vector3.Normalize(RayEnd - RayStart); Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z); Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z); if (target != null) { pos = target.AbsolutePosition; //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString()); // TODO: Raytrace better here //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection)); Ray NewRay = new Ray(AXOrigin, AXdirection); // Ray Trace against target here EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); // Un-comment out the following line to Get Raytrace results printed to the console. // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); float ScaleOffset = 0.5f; // If we hit something if (ei.HitTF) { Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z); if (scaleComponent.X != 0) ScaleOffset = scale.X; if (scaleComponent.Y != 0) ScaleOffset = scale.Y; if (scaleComponent.Z != 0) ScaleOffset = scale.Z; ScaleOffset = Math.Abs(ScaleOffset); Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z); // Set the position to the intersection point Vector3 offset = (normal * (ScaleOffset / 2f)); pos = (intersectionpoint + offset); //Seems to make no sense to do this as this call is used for rezzing from inventory as well, and with inventory items their size is not always 0.5f //And in cases when we weren't rezzing from inventory we were re-adding the 0.25 straight after calling this method // Un-offset the prim (it gets offset later by the consumer method) //pos.Z -= 0.25F; } return pos; } else { // We don't have a target here, so we're going to raytrace all the objects in the scene. EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false); // Un-comment the following line to print the raytrace results to the console. //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); if (ei.HitTF) { pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); } else { // fall back to our stupid functionality pos = RayEnd; } return pos; } } else { // fall back to our stupid functionality pos = RayEnd; //increase height so its above the ground. //should be getting the normal of the ground at the rez point and using that? pos.Z += scale.Z / 2f; return pos; } }
private void UpdateEntity(ISceneEntity entity) { if (!(entity is IPhysical)) return; if (entity is IScenePresence && ((IScenePresence)entity).IsChildPresence) return; float elapsedTime = m_elapsedTime; if (elapsedTime <= 0f) return; IPhysical physical = (IPhysical)entity; if (!physical.DynamicsEnabled) return; IPhysicalPresence presence = (physical is IPhysicalPresence) ? (IPhysicalPresence)physical : null; Vector3 velocity = physical.Velocity * elapsedTime; Vector3 position = physical.RelativePosition; Vector3 move = (presence != null) ? presence.InputVelocity : Vector3.Zero; bool jumping = (presence != null) ? presence.JumpStart != 0 : false; float gravity = 0f; float waterHeight = 0.0f; if (m_terrain != null) waterHeight = m_terrain.WaterHeight; float waterChestHeight = waterHeight - (physical.Scale.Z * .33f); float speed = elapsedTime; float fallElapsed = (float)(Environment.TickCount - physical.FallStart) / 1000f; UUID anim = UUID.Zero; List<ISceneEntity> colliders = new List<ISceneEntity>(); if (presence != null && presence.StunMS > 0) { move = Vector3.Zero; presence.StunMS -= (int)((float)1000 * elapsedTime); } ISceneEntity collider; float collisionDist; //if (presence != null && presence.InputDirection != Vector3.Zero) //{ // // Raycast in the direction the avatar wishes to move // Ray avRay = new Ray(physical.ScenePosition, Vector3.Normalize(presence.InputDirection)); // if (FullSceneCollisionTest(false, avRay, presence, out collider, out collisionDist)) // { // speed = Math.Min(speed, collisionDist - COLLISION_MARGIN); // m_log.Debug("Raycasted to " + collider.Name + " (" + collider.LocalID + ")"); // } //} //HACK: detect both X and Y ray collisions, since we are not calculating a collision normal Vector3 normVel = Vector3.Normalize(velocity); if ((normVel.X != 0f || move.X != 0f) && FullSceneCollisionTest(false, new Ray(position, normVel.X > 0 || move.X > 0 ? Vector3.UnitX : -Vector3.UnitX), physical, out collider, out collisionDist) && collisionDist <= COLLISION_MARGIN) { move.X = 0f; velocity.X = 0f; if (!colliders.Contains(collider)) colliders.Add(collider); } if ((normVel.Y != 0f || move.Y != 0f) && FullSceneCollisionTest(false, new Ray(position, normVel.Y > 0 || move.Y > 0 ? Vector3.UnitY : -Vector3.UnitY), physical, out collider, out collisionDist) && collisionDist <= COLLISION_MARGIN) { move.Y = 0f; velocity.Y = 0f; if (!colliders.Contains(collider)) colliders.Add(collider); } #region Terrain Movement float oldFloor = 0.0f, newFloor = 0.0f; if (m_terrain != null) oldFloor = m_terrain.GetTerrainHeightAt(position.X, position.Y); position += (move * speed); if (m_terrain != null) newFloor = m_terrain.GetTerrainHeightAt(position.X, position.Y); if (presence != null) { if (presence.MovementState != MovementState.Flying && newFloor != oldFloor) speed /= (1f + (SQRT_TWO * Math.Abs(newFloor - oldFloor))); } //HACK: distance from avatar center to the bottom of its feet float distanceFromFloor = physical.Scale.Z * .5f; // Raycast for gravity Ray ray = new Ray(position, -Vector3.UnitZ); if (FullSceneCollisionTest(false, ray, physical, out collider, out collisionDist)) { if (position.Z - collisionDist > newFloor) { newFloor = position.Z - collisionDist; //FIXME //if (!colliders.Contains(collider)) //colliders.Add(collider); } } float lowerLimit = newFloor + distanceFromFloor; #endregion Terrain Movement if (presence != null && presence.MovementState == MovementState.Flying) { #region Flying physical.FallStart = 0; presence.JumpStart = 0; //velocity falloff while flying velocity.X *= 0.66f; velocity.Y *= 0.66f; velocity.Z *= 0.33f; if (position.Z == lowerLimit) velocity.Z += INITIAL_HOVER_IMPULSE; if (move.X != 0f || move.Y != 0f) anim = Animations.FLY; else if (move.Z > 0f) anim = Animations.HOVER_UP; else if (move.Z < 0f) anim = Animations.HOVER_DOWN; else anim = Animations.HOVER; #endregion Flying } else if (position.Z > lowerLimit + FALL_FORGIVENESS || position.Z <= waterChestHeight) { #region Falling/Floating/Landing if (position.Z > waterHeight) { //above water //override controls while drifting move = Vector3.Zero; //keep most of our horizontal inertia velocity.X *= 0.975f; velocity.Y *= 0.975f; if (physical.FallStart == 0) //|| (fallElapsed > FALL_DELAY && velocity.Z >= 0f)) { //just started falling physical.FallStart = Environment.TickCount; } else { gravity = GRAVITY * fallElapsed * elapsedTime; //normal gravity if (!jumping) { //falling if (fallElapsed > FALL_DELAY) { //falling long enough to trigger the animation anim = Animations.FALLDOWN; } } } } else if (position.Z >= waterChestHeight) { //at the water line velocity *= 0.1f; velocity.Z = 0f; physical.FallStart = 0; if (move.Z < 1f) position.Z = waterChestHeight; if (move.Z > 0f) anim = Animations.HOVER_UP; else if (move.X != 0f || move.Y != 0f) anim = Animations.SWIM_FORWARD; else anim = Animations.HOVER; } else { //underwater velocity *= 0.1f; velocity.Z += 0.75f * elapsedTime; // buoyant if (move.Z < 0f) anim = Animations.SWIM_DOWN; else anim = Animations.SWIM_FORWARD; } #endregion Falling/Floating/Landing } else { #region Ground Movement if (presence != null) { if (presence.JumpStart == 0 && physical.FallStart > 0) { if (fallElapsed >= FALL_DELAY * 4) { anim = Animations.STANDUP; presence.StunMS = 2000; } else if (fallElapsed >= FALL_DELAY * 3) { anim = Animations.MEDIUM_LAND; presence.StunMS = 1000; } else if (fallElapsed >= FALL_DELAY * 2) { anim = Animations.LAND; presence.StunMS = 500; } if (presence.Animations.SetDefaultAnimation(anim, 1)) m_scene.SendPresenceAnimations(this, presence); } } physical.FallStart = 0; //friction velocity *= 0.2f; velocity.Z = 0f; position.Z = lowerLimit; if (presence != null) { if (move.Z > 0f) { //jumping if (!jumping) { //begin prejump move.Z = 0f; //override Z control anim = Animations.PRE_JUMP; presence.JumpStart = Environment.TickCount; } else if (Environment.TickCount - presence.JumpStart > PREJUMP_DELAY * 1000) { //start actual jump if (presence.JumpStart == -1) { //already jumping! end current jump presence.JumpStart = 0; return; } anim = Animations.JUMP; Vector3 normalVel = Vector3.Normalize(velocity); velocity.X += normalVel.X * JUMP_IMPULSE_HORIZONTAL * elapsedTime; velocity.Y += normalVel.Y * JUMP_IMPULSE_HORIZONTAL * elapsedTime; velocity.Z = JUMP_IMPULSE_VERTICAL * elapsedTime; presence.JumpStart = -1; //flag that we are currently jumping } else move.Z = 0; //override Z control } else { //not jumping presence.JumpStart = 0; if (move.X != 0 || move.Y != 0) { if (move.Z < 0) anim = Animations.CROUCHWALK; else if (presence.MovementState == MovementState.Running) anim = Animations.RUN; else anim = Animations.WALK; } else { if (move.Z < 0) anim = Animations.CROUCH; else anim = Animations.STAND; } } } #endregion Ground Movement } if (presence != null) { if (anim != UUID.Zero && presence.StunMS <= 0 && presence.Animations.SetDefaultAnimation(anim, 1)) m_scene.SendPresenceAnimations(this, presence); } float maxVel = AVATAR_TERMINAL_VELOCITY * elapsedTime; #region Update Physical State // Calculate how far we moved this frame Vector3 moved = position - physical.RelativePosition; if (moved.Z < -maxVel) moved.Z = -maxVel; else if (moved.Z > maxVel) moved.Z = maxVel; position += velocity; moved.Z = moved.Z - gravity; velocity += moved; if (velocity.Z < -maxVel) velocity.Z = -maxVel; else if (velocity.Z > maxVel) velocity.Z = maxVel; if (position.Z < lowerLimit) position.Z = lowerLimit; if (position.Z < lowerLimit + COLLISION_MARGIN) velocity.Z = 0f; physical.Velocity = velocity / elapsedTime; physical.RelativePosition = position; #endregion Update Physical State EventHandler<EntityCollisionArgs> callback = OnEntityCollision; if (callback != null) { for (int i = 0, len = colliders.Count; i < len; i++) { callback(this, new EntityCollisionArgs { First = physical, Second = colliders[i] }); callback(this, new EntityCollisionArgs { First = colliders[i], Second = physical }); } } m_scene.EntityAddOrUpdate(this, physical, UpdateFlags.Position | UpdateFlags.Velocity, 0); }
public EntityIntersection TestIntersection(Ray iray, Quaternion parentrot) { // In this case we're using a sphere with a radius of the largest dimension of the prim // TODO: Change to take shape into account EntityIntersection result = new EntityIntersection(); Vector3 vAbsolutePosition = AbsolutePosition; Vector3 vScale = Scale; Vector3 rOrigin = iray.Origin; Vector3 rDirection = iray.Direction; //rDirection = rDirection.Normalize(); // Buidling the first part of the Quadratic equation Vector3 r2ndDirection = rDirection*rDirection; float itestPart1 = r2ndDirection.X + r2ndDirection.Y + r2ndDirection.Z; // Buidling the second part of the Quadratic equation Vector3 tmVal2 = rOrigin - vAbsolutePosition; Vector3 r2Direction = rDirection*2.0f; Vector3 tmVal3 = r2Direction*tmVal2; float itestPart2 = tmVal3.X + tmVal3.Y + tmVal3.Z; // Buidling the third part of the Quadratic equation Vector3 tmVal4 = rOrigin*rOrigin; Vector3 tmVal5 = vAbsolutePosition*vAbsolutePosition; Vector3 tmVal6 = vAbsolutePosition*rOrigin; // Set Radius to the largest dimension of the prim float radius = 0f; if (vScale.X > radius) radius = vScale.X; if (vScale.Y > radius) radius = vScale.Y; if (vScale.Z > radius) radius = vScale.Z; // the second part of this is the default prim size // once we factor in the aabb of the prim we're adding we can // change this to; // radius = (radius / 2) - 0.01f; // radius = (radius / 2) + (0.5f / 2) - 0.1f; //radius = radius; float itestPart3 = tmVal4.X + tmVal4.Y + tmVal4.Z + tmVal5.X + tmVal5.Y + tmVal5.Z - (2.0f*(tmVal6.X + tmVal6.Y + tmVal6.Z + (radius*radius))); // Yuk Quadradrics.. Solve first float rootsqr = (itestPart2*itestPart2) - (4.0f*itestPart1*itestPart3); if (rootsqr < 0.0f) { // No intersection return result; } float root = ((-itestPart2) - (float) Math.Sqrt((double) rootsqr))/(itestPart1*2.0f); if (root < 0.0f) { // perform second quadratic root solution root = ((-itestPart2) + (float) Math.Sqrt((double) rootsqr))/(itestPart1*2.0f); // is there any intersection? if (root < 0.0f) { // nope, no intersection return result; } } // We got an intersection. putting together an EntityIntersection object with the // intersection information Vector3 ipoint = new Vector3(iray.Origin.X + (iray.Direction.X*root), iray.Origin.Y + (iray.Direction.Y*root), iray.Origin.Z + (iray.Direction.Z*root)); result.HitTF = true; result.ipoint = ipoint; // Normal is calculated by the difference and then normalizing the result Vector3 normalpart = ipoint - vAbsolutePosition; result.normal = normalpart / normalpart.Length(); // It's funny how the Vector3 object has a Distance function, but the Axiom.Math object doesn't. // I can write a function to do it.. but I like the fact that this one is Static. Vector3 distanceConvert1 = new Vector3(iray.Origin.X, iray.Origin.Y, iray.Origin.Z); Vector3 distanceConvert2 = new Vector3(ipoint.X, ipoint.Y, ipoint.Z); float distance = (float) Util.GetDistanceTo(distanceConvert1, distanceConvert2); result.distance = distance; return result; }
private ContactResult[] ObjectIntersection(Vector3 rayStart, Vector3 rayEnd, bool includePhysical, bool includeNonPhysical, bool includePhantom, int max) { List<ContactResult> contacts = World.PhysicsScene.RaycastWorld(rayStart, Vector3.Normalize(rayEnd - rayStart), Vector3.Distance(rayEnd, rayStart), max); for (int i = 0; i < contacts.Count; i++) { ISceneEntity grp = World.GetGroupByPrim(contacts[i].ConsumerID); if(grp == null || (!includePhysical && grp.RootChild.PhysActor.IsPhysical) || (!includeNonPhysical && !grp.RootChild.PhysActor.IsPhysical)) contacts.RemoveAt(i--); } if (includePhantom) { Ray ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart)); Vector3 ab = rayEnd - rayStart; ISceneEntity[] objlist = World.Entities.GetEntities(); foreach (ISceneEntity group in objlist) { if (m_host.ParentEntity == group) continue; if (group.IsAttachment) continue; if (group.RootChild.PhysActor != null) continue; // Find the radius ouside of which we don't even need to hit test float minX; float maxX; float minY; float maxY; float minZ; float maxZ; float radius = 0.0f; group.GetAxisAlignedBoundingBoxRaw(out minX, out maxX, out minY, out maxY, out minZ, out maxZ); if (Math.Abs(minX) > radius) radius = Math.Abs(minX); if (Math.Abs(minY) > radius) radius = Math.Abs(minY); if (Math.Abs(minZ) > radius) radius = Math.Abs(minZ); if (Math.Abs(maxX) > radius) radius = Math.Abs(maxX); if (Math.Abs(maxY) > radius) radius = Math.Abs(maxY); if (Math.Abs(maxZ) > radius) radius = Math.Abs(maxZ); radius = radius * 1.413f; Vector3 ac = group.AbsolutePosition - rayStart; // Vector3 bc = group.AbsolutePosition - rayEnd; double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); // Too far off ray, don't bother if (d > radius) continue; // Behind ray, drop double d2 = Vector3.Dot(Vector3.Negate(ab), ac); if (d2 > 0) continue; ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart)); EntityIntersection intersection = group.TestIntersection(ray, true, false); // Miss. if (!intersection.HitTF) continue; Vector3 b1 = new Vector3(minX, minY, minZ); Vector3 b2 = new Vector3(maxX, maxY, maxZ); //m_log.DebugFormat("[LLCASTRAY]: min<{0},{1},{2}>, max<{3},{4},{5}> = hitp<{6},{7},{8}>", b1.X,b1.Y,b1.Z,b2.X,b2.Y,b2.Z,intersection.ipoint.X,intersection.ipoint.Y,intersection.ipoint.Z); if (!(intersection.ipoint.X >= b1.X && intersection.ipoint.X <= b2.X && intersection.ipoint.Y >= b1.Y && intersection.ipoint.Y <= b2.Y && intersection.ipoint.Z >= b1.Z && intersection.ipoint.Z <= b2.Z)) continue; ContactResult result = new ContactResult(); result.ConsumerID = group.LocalId; result.Depth = intersection.distance; result.Normal = intersection.normal; result.Pos = intersection.ipoint; contacts.Add(result); } } return contacts.ToArray(); }
public EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters) { // We got a request from the inner_scene to raytrace along the Ray hRay // We're going to check all of the prim in this group for intersection with the ray // If we get a result, we're going to find the closest result to the origin of the ray // and send back the intersection information back to the innerscene. EntityIntersection result = new EntityIntersection(); foreach (SceneObjectPart part in m_partsList) { // Temporary commented to stop compiler warning //Vector3 partPosition = // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); Quaternion parentrotation = GroupRotation; // Telling the prim to raytrace. //EntityIntersection inter = part.TestIntersection(hRay, parentrotation); EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); // This may need to be updated to the maximum draw distance possible.. // We might (and probably will) be checking for prim creation from other sims // when the camera crosses the border. float idist = Constants.RegionSize; if (inter.HitTF) { // We need to find the closest prim to return to the testcaller along the ray if (inter.distance < idist) { result.HitTF = true; result.ipoint = inter.ipoint; result.obj = part; result.normal = inter.normal; result.distance = inter.distance; } } } return result; }
/// <summary> /// From the transmitter, we create a ray in all direction (with angle between ray = ANGLE_BETWEEN_RAY). For each /// of those ray, we 'trace/follow' them and find where they are heading. If they reaches the reciever, then /// we store them in a list. /// </summary> public void startRayTracerBrutefoce() { m_log.DebugFormat("[BARE BONES NON SHARED] Started Raytracing!"); float lat, lon; float toPercent = 100.0f/360.0f; //For every lon and lat increase by ANGLE_BETWEEN_RAY for (lon = 0; lon < 360; lon += ANGLE_BETWEEN_RAY) { for (lat = 0; lat < 360; lat += ANGLE_BETWEEN_RAY) { double lonr = lon * DEG_TO_RAD; double latr = lat * DEG_TO_RAD; //Note: Lat = angle of elevation. Lon = angle around the z-axis //To get a point on a sphere using 2 angle //Assuming Radius = 1 so we can get rid of multiplying radius. //http://stackoverflow.com/questions/969798/plotting-a-point-on-the-edge-of-a-sphere float x = (float)(Math.Sin(latr) * Math.Cos(lonr)); float y = (float)(Math.Sin(latr) * Math.Sin(lonr)); float z = (float)(Math.Cos(latr)); Vector3 pointOnSphere = new Vector3(x, y, z); pointOnSphere.Normalize(); Vector3 direction = pointOnSphere; Ray ray = new Ray(transmitter.RootPart.AbsolutePosition, direction); //Trace this ray string pathID = getPathID(); PathFromTxToRy thisRayPath = new PathFromTxToRy(this, transmitter.RootPart.AbsolutePosition, pathID); thisRayPath = traceRay(thisRayPath, ray, transmitter.RootPart); //If it reaches the receiver, then add it to the hit list. if (thisRayPath.reachesReceiver && !checkPathIsDrawn(thisRayPath)) { pathHits[thisRayPath.getNoOfReflection()].Add(pathID, thisRayPath); } } //If lon < 359 then calculate the progress if (lon < 359) { updateProgressBar(lon * toPercent); } else //else it is completed so return 100% { updateProgressBar(100.0f); } }//for }