/// <summary> /// Sets this frustum to the given frustum</summary> /// <param name="other">Frustum</param> public void Set(Frustum other) { for (int i = 0; i < 6; i++) { m_planes[i] = other.m_planes[i]; } }
/// <summary> /// Constructor</summary> /// <param name="renderStateGuardian">Render state guardian</param> public PickAction(RenderStateGuardian renderStateGuardian) : base(renderStateGuardian) { m_selectionBuffer = new int[65536]; m_openGlHits = 0; m_pickTolerance = 3.0f; m_viewFrust0 = new Frustum(); }
private void TestToStringResults(Frustum o, string s, string listSeparator, string decimalSeparator) { string[] results = s.Split(new[] { listSeparator }, StringSplitOptions.RemoveEmptyEntries); Assert.AreEqual(results.Length, 6); foreach (string oneFloatString in results) Assert.True(oneFloatString.Contains(decimalSeparator)); Assert.AreEqual(float.Parse(results[0]), o.Right); Assert.AreEqual(float.Parse(results[1]), o.Left); Assert.AreEqual(float.Parse(results[2]), o.Top); Assert.AreEqual(float.Parse(results[3]), o.Bottom); Assert.AreEqual(float.Parse(results[4]), o.Near); Assert.AreEqual(float.Parse(results[5]), o.Far); }
private void TestToStringWithCulture(CultureInfo culture) { CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = culture; try { string listSeparator = culture.TextInfo.ListSeparator; string decimalSeparator = culture.NumberFormat.NumberDecimalSeparator; var o = new Frustum(1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f); string s = o.ToString(null, null); TestToStringResults(o, s, listSeparator, decimalSeparator); s = o.ToString("G", culture); TestToStringResults(o, s, listSeparator, decimalSeparator); s = o.ToString("R", culture); TestToStringResults(o, s, listSeparator, decimalSeparator); } finally { Thread.CurrentThread.CurrentCulture = originalCulture; } }
/// <summary> /// Dispatches untyped items. Replaces DispatchNotTyped(). To get the same behavior as /// the old DispatchNotTyped(), set the TypeFilter property to null prior to calling.</summary> /// <param name="traverseList">The traverse list</param> /// <param name="camera">The camera</param> protected void DispatchTraverseList(ICollection<TraverseNode> traverseList, Camera camera) { // Prepare for geometric picking -- create the ray in world space and reset geometric hit-list. // First create the ray in viewing coordinates and transform to world coordinates. float nx = (m_x / (float)m_width) - 0.5f;//normalized x float ny = 0.5f - (m_y / (float)m_height);//normalized y Ray3F rayWorld = camera.CreateRay(nx, ny); Matrix4F worldToView = camera.ViewMatrix; Matrix4F viewToWorld = new Matrix4F(); viewToWorld.Invert(worldToView); rayWorld.Transform(viewToWorld); ClearHitList(); // for geometric picking. will be cleared for each HitRecord. List<uint> userData = new List<uint>(1); // Dispatch traverse list int index = 0; foreach (TraverseNode node in traverseList) { // First test for filtering. IRenderObject renderObject = node.RenderObject; if (FilterByType(renderObject)) { IIntersectable intersectable = renderObject.GetIntersectable(); IGeometricPick geometricPick = intersectable as IGeometricPick; if (geometricPick != null) { // Picking by geometry. Matrix4F objToWorld = new Matrix4F(node.Transform); Matrix4F worldToObj = new Matrix4F(); worldToObj.Invert(objToWorld); Matrix4F viewToObj = Matrix4F.Multiply(viewToWorld, worldToObj); if (m_frustumPick) { //The pick frustum is in view space. Transform to world space then object space. Frustum frustumObj = new Frustum(m_viewFrust0); frustumObj.Transform(viewToObj); //Multi-pick. Get everything in the pick frustum (m_viewFrust0). Vec3F eyeObj; worldToObj.Transform(camera.Eye, out eyeObj); userData.Clear(); if (geometricPick.IntersectFrustum(frustumObj, eyeObj, node.RenderState, userData)) { // Prepare a multi-pick HitRecord, as if OpenGL had calculated this. HitRecord hit = new HitRecord( node.GraphPath, renderObject, objToWorld, userData.ToArray()); m_geoHitList.Add(hit); } } else { //Single pick. We care about distance from camera eye. //Make a copy of the ray in world-space and tranform it to object space. Ray3F rayObj = rayWorld; //remember, Ray3F is a value type, not a reference type. rayObj.Transform(worldToObj); // Do the intersection test in object space. userData.Clear(); Vec3F intersectionPt, surfaceNormal; Vec3F nearestVert; bool intersected; intersected = geometricPick.IntersectRay( rayObj, camera, node.RenderState, objToWorld, this, out intersectionPt, out nearestVert, out surfaceNormal, userData); if (intersected) { // Transform to world space and then to screen space. objToWorld.Transform(intersectionPt, out intersectionPt); objToWorld.Transform(nearestVert, out nearestVert); // Prepare a single-pick HitRecord, as if OpenGL had calculated this. HitRecord hit = new HitRecord( node.GraphPath, renderObject, objToWorld, userData.ToArray()); // This is the one difference from OpenGL pick. We have the world pt already. hit.WorldIntersection = intersectionPt; hit.NearestVert = nearestVert; // Another difference is that it's possible to get the surface normal. if (surfaceNormal != Vec3F.ZeroVector) { objToWorld.TransformNormal(surfaceNormal, out surfaceNormal); surfaceNormal.Normalize(); hit.Normal = surfaceNormal; } m_geoHitList.Add(hit); } } } else { // Picking by "rendering", using OpenGL pick. PushMatrix(node.Transform, false); Gl.glPushName(index); IRenderPick pickInterface = renderObject as IRenderPick; if (pickInterface != null) { pickInterface.PickDispatch(node.GraphPath, node.RenderState, this, camera); } else { renderObject.Dispatch(node.GraphPath, node.RenderState, this, camera); } Gl.glPopName(); PopMatrix(); } } index++; } }
/// <summary> /// Builds a traverse list from the Scene and dispatches it for rendering</summary> /// <param name="scene">The scene to dispatch</param> /// <param name="camera">The camera</param> public override void Dispatch(Scene scene, Camera camera) { //We no longer want render stats for picking because when testing for the manipulator, // this is very fast and leads to an artificially high frame rate. Better to let the // displayed frame rate mean what people expect -- the number of times the visible // frame buffer is rendered each second. //Util3D.RenderStats.ResetFrame(); PreDispatch(scene, camera); // Cache current view frustum Frustum frust = new Frustum(); frust.Set(camera.Frustum); // Set pick frustum camera.Frustum.Set(m_viewFrust0); // Clear traverse list m_traverseList.Clear(); m_traverseList.SetViewMatrix(camera.ViewMatrix); // Make sure that solid-coloring is default, so that objects that don't implement // IRenderPick can still be picked when wireframe mode is on. RenderState origState = scene.StateStack.Peek(); RenderState pickState; if (origState != null) { scene.StateStack.Pop(); pickState = new RenderState(origState); } else { pickState = new RenderState(); } pickState.RenderMode |= RenderMode.Smooth | RenderMode.SolidColor; pickState.RenderMode &= ~RenderMode.Wireframe; pickState.OverrideChildState |= RenderMode.Wireframe; scene.StateStack.Push(pickState); //s_stopWatch.Reset(); //s_stopWatch.Start(); BuildTraverseList(camera, m_traverseList, scene); //Util3D.RenderStats.TraverseNodeCount = m_traverseList.Count; //Util3D.RenderStats.TimeForTraverse = s_stopWatch.ElapsedMilliseconds; // Restore original render state. scene.StateStack.Pop(); if (origState != null) { scene.StateStack.Push(origState); } //Restore view frustum for pick rendering camera.Frustum.Set(frust); //s_stopWatch.Reset(); //s_stopWatch.Start(); DispatchTraverseList(m_traverseList, camera); //Util3D.RenderStats.TimeForDispatchTraverseList = s_stopWatch.ElapsedMilliseconds; PostDispatch(scene, camera); }
/// <summary> /// Constructor</summary> /// <param name="other">Other frustum</param> public Frustum(Frustum other) : this() { Set(other); }