IPickedGeometry IColorCodedPicking.Pick(uint stageVertexID) { IColorCodedPicking element = this as IColorCodedPicking; PickedGeometryIndexed pickedGeometry = element.TryPick <PickedGeometryIndexed>( PrimitiveModes.TriangleStrip, stageVertexID); if (pickedGeometry == null) { return(null); } // Fill primitive's positions and colors. This maybe changes much more than lines above in second dev. uint lastVertexID; if (element.GetLastVertexIDOfPickedGeometry(stageVertexID, out lastVertexID)) { pickedGeometry.CubeIndex = lastVertexID / 8; var vertexIndex = lastVertexID % 8; pickedGeometry.positions = new vec3[1] { unitCubePos[vertexIndex] }; } return(pickedGeometry); }
public override string ToString() { var positions = this.positions; if (positions == null) { positions = new vec3[0]; } string strPositions = positions.PrintArray(); uint stageVertexID = this.StageVertexID; IColorCodedPicking picking = this.From; string lastVertexID = "?"; if (picking != null) { uint tmp; if (picking.GetLastVertexIDOfPickedGeometry(stageVertexID, out tmp)) { lastVertexID = string.Format("{0}", tmp); } } string result = string.Format("{0}: P: {1} vertex ID:{2}/{3} ∈{4}", GeometryType, strPositions, lastVertexID, stageVertexID, From); return(result); //return base.ToString(); }
private IPickedGeometry Pick(SceneElement element, uint stageVertexID) { IPickedGeometry pickedGeometry = null; IColorCodedPicking pickingElement = element as IColorCodedPicking; if (pickingElement != null) { pickedGeometry = pickingElement.Pick(stageVertexID); } if (pickedGeometry == null) { if (element != null) { foreach (var item in element.Children) { pickedGeometry = Pick(item, stageVertexID); if (pickedGeometry != null) { break; } } } } return(pickedGeometry); }
/// <summary> /// Returns last vertex's id of picked geometry if the geometry represented by <paramref name="stageVertexID"/> belongs to this <paramref name="element"/> instance. /// <para>Returns false if <paramref name="stageVertexID"/> the primitive is in some other element.</para> /// </summary> /// <param name="element"></param> /// <param name="stageVertexID"></param> /// <param name="lastVertexID"></param> /// <returns></returns> public static bool GetLastVertexIDOfPickedGeometry(this IColorCodedPicking element, uint stageVertexID, out uint lastVertexID) { lastVertexID = uint.MaxValue; bool result = false; if (element != null) { if (stageVertexID < element.PickingBaseID) // ID is in some previous element. { return(false); } uint vertexCount = element.GetVertexCount(); uint id = stageVertexID - element.PickingBaseID; if (id < vertexCount) { lastVertexID = id; result = true; } else // ID is in some subsequent element. { result = false; } } return(result); }
//private void glCanvas1_MouseClick(object sender, MouseEventArgs e) //{ // if (e.Button == System.Windows.Forms.MouseButtons.Right) // { // IPickedGeometry pickedGeometry = this.Pick(e.X, e.Y); // if (pickedGeometry != null) // { // this.txtPickedInfo.Text = string.Format("{0:yyyy-MM-dd HH:mm:ss.ff} {1}", // DateTime.Now, pickedGeometry); // } // else // { // this.txtPickedInfo.Text = string.Format("{0:yyyy-MM-dd HH:mm:ss.ff} {1}", // DateTime.Now, "nothing picked"); // } // } //} private IPickedGeometry Pick(int x, int y) { //this.glCanvas1.MakeCurrent(); // render the scene for color-coded picking. GL.ClearColor(1.0f, 1.0f, 1.0f, 1.0f); GL.Clear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT); SharedStageInfo info = new SharedStageInfo(); info.Reset(); var arg = new RenderEventArgs(RenderModes.HitTest, this.camera); IColorCodedPicking pickable = this.element; info.RenderForPicking(pickable, arg); GL.Flush(); // get coded color. //byte[] codedColor = new byte[4]; UnmanagedArray <byte> codedColor = new UnmanagedArray <byte>(4); GL.ReadPixels(x, this.glCanvas1.Height - y - 1, 1, 1, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, codedColor.Header); if (codedColor[0] == byte.MaxValue && codedColor[1] == byte.MaxValue && codedColor[2] == byte.MaxValue && codedColor[3] == byte.MaxValue) { // This is when (x, y) is on background and no primitive is picked. return(null); } /* // This is how is vertexID coded into color in vertex shader. * int objectID = gl_VertexID; * codedColor = vec4( * float(objectID & 0xFF), * float((objectID >> 8) & 0xFF), * float((objectID >> 16) & 0xFF), * float((objectID >> 24) & 0xFF)); */ // get vertexID from coded color. // the vertexID is the last vertex that constructs the primitive. // see http://www.cnblogs.com/bitzhuwei/p/modern-opengl-picking-primitive-in-VBO-2.html uint shiftedR = (uint)codedColor[0]; uint shiftedG = (uint)codedColor[1] << 8; uint shiftedB = (uint)codedColor[2] << 16; uint shiftedA = (uint)codedColor[3] << 24; uint stageVertexID = shiftedR + shiftedG + shiftedB + shiftedA; // get picked primitive. IPickedGeometry pickedGeometry = null; pickedGeometry = ((IColorCodedPicking)this.element).Pick(stageVertexID); return(pickedGeometry); }
/// <summary> /// Get the primitive of <paramref name="element"/> according to vertex's id. /// <para>Returns <code>null</code> if <paramref name="element"/> is null or <paramref name="stageVertexID"/> does not belong to any of this <paramref name="element"/>'s vertices.</para> /// <para>Note: the <paramref name="stageVertexID"/> refers to the last vertex that constructs the primitive. And it's unique in scene's all elements.</para> /// </summary> /// <typeparam name="T">Subclass of <see cref="IPickedGeometry"/></typeparam> /// <param name="element">the scene's element that contains the primitive.</param> /// <param name="mode">specifies what type of primitive it is.</param> /// <param name="stageVertexID">Refers to the last vertex that constructs the primitive. And it's unique in scene's all elements.</param> /// <param name="positions">element's vertices' position array.</param> /// <returns></returns> public static T TryPick <T>( this IColorCodedPicking element, PrimitiveModes mode, uint stageVertexID, float[] positions) where T : IPickedGeometry, new() { if (positions == null) { throw new ArgumentNullException("positions"); } T pickedGeometry = element.TryPick <T>(mode, stageVertexID); // Fill primitive's positions and colors. This maybe changes much more than lines above in second dev. if (pickedGeometry != null) { uint lastVertexID; if (element.GetLastVertexIDOfPickedGeometry(stageVertexID, out lastVertexID)) { int vertexCount = pickedGeometry.GeometryType.GetVertexCount(); if (vertexCount == -1) { vertexCount = positions.Length / 3; } float[] geometryPositions = new float[vertexCount * 3]; uint i = lastVertexID * 3 + 2; for (int j = (geometryPositions.Length - 1); j >= 0; i--, j--) { if (i == uint.MaxValue)// This is when mode is GL_LINE_LOOP. { i = (uint)positions.Length - 1; } geometryPositions[j] = positions[i]; } var poss = new vec3[vertexCount]; for (int t = 0; t < vertexCount; t++) { poss[t] = new vec3(geometryPositions[t * 3 + 0], geometryPositions[t * 3 + 1], geometryPositions[t * 3 + 2]); } pickedGeometry.positions = poss; } } return(pickedGeometry); }
IPickedGeometry IColorCodedPicking.Pick(uint stageVertexID) { IColorCodedPicking element = this as IColorCodedPicking; PickedGeometryColored pickedGeometry = element.TryPick <PickedGeometryColored>( this.Model.Mode, stageVertexID, this.Model.Positions); if (pickedGeometry == null) { return(null); } // Fill primitive's positions and colors. This maybe changes much more than lines above in second dev. uint lastVertexID; if (element.GetLastVertexIDOfPickedGeometry(stageVertexID, out lastVertexID)) { ScientificModel model = this.Model; int vertexCount = pickedGeometry.GeometryType.GetVertexCount(); if (vertexCount == -1) { vertexCount = model.VertexCount; } float[] geometryColors = new float[vertexCount * 3]; float[] modelColors = model.Colors; uint i = lastVertexID * 3 + 2; for (int j = (geometryColors.Length - 1); j >= 0; i--, j--) { if (i == uint.MaxValue)// This is when mode is GL_LINE_LOOP. { i = (uint)modelColors.Length - 1; } geometryColors[j] = modelColors[i]; } pickedGeometry.colors = geometryColors; } return(pickedGeometry); }
/// <summary> /// Get the primitive of <paramref name="element"/> according to vertex's id. /// <para>Returns <code>null</code> if <paramref name="element"/> is null or <paramref name="stageVertexID"/> is not in the range of this <paramref name="element"/>.</para> /// <para>Note: the <paramref name="stageVertexID"/> Refers to the last vertex that constructs the primitive. And it's unique in scene's all elements.</para> /// <para>Note: The result's positions property is not set up as there will be different kinds of storage mode for positions(float[], IntPtr, etc). You have to initialize the positions property and fill correct position information afterwards.</para> /// </summary> /// <typeparam name="T">Sub type of <see cref="IPickedGeometry"/></typeparam> /// <param name="element">the scene's element that contains the primitive.</param> /// <param name="mode">specifies what type of primitive it is.</param> /// <param name="stageVertexID">Refers to the last vertex that constructs the primitive. And it's unique in scene's all elements.</param> /// <returns></returns> public static T TryPick <T>( this IColorCodedPicking element, PrimitiveModes mode, uint stageVertexID) where T : IPickedGeometry, new() { T pickedGeometry = default(T); if (element != null) { uint lastVertexID; if (element.GetLastVertexIDOfPickedGeometry(stageVertexID, out lastVertexID)) { pickedGeometry = new T(); pickedGeometry.GeometryType = mode.ToGeometryType(); pickedGeometry.StageVertexID = stageVertexID; pickedGeometry.From = element; } } return(pickedGeometry); }
/// <summary> /// Render the element that inherts <see cref="IColorCodedPicking"/> for color coded picking. /// </summary> /// <param name="pickable"></param> /// <param name="gl"></param> /// <param name="renderMode"></param> public virtual void RenderForPicking(IColorCodedPicking pickable, RenderEventArgs e) { if (pickable != null) { pickable.PickingBaseID = this.RenderedVertexCount; // render the element. pickable.Render(e); uint rendered = this.RenderedVertexCount + pickable.GetVertexCount(); if (this.RenderedVertexCount <= rendered) { this.RenderedVertexCount = rendered; } else { throw new OverflowException( string.Format("Too many geometries({0} + {1} > {2}) for color coded picking.", this.RenderedVertexCount, pickable.GetVertexCount(), uint.MaxValue)); } } }
/// <summary> /// Render the element that inherts <see cref="IColorCodedPicking"/> for color coded picking. /// </summary> /// <param name="pickable"></param> /// <param name="gl"></param> /// <param name="renderMode"></param> public virtual void RenderForPicking(IColorCodedPicking pickable, RenderEventArgs e) { if (pickable != null) { pickable.PickingBaseID = this.RenderedVertexCount; // render the element. IRenderable renderable = pickable; renderable.Render(e); uint rendered = this.RenderedVertexCount + pickable.GetVertexCount(); if (this.RenderedVertexCount <= rendered) { this.RenderedVertexCount = rendered; } else { throw new OverflowException( string.Format("Too many geometries({0} + {1} > {2}) for color coded picking.", this.RenderedVertexCount, pickable.GetVertexCount(), uint.MaxValue)); } } }
private void glCanvas1_MouseMove(object sender, MouseEventArgs e) { if (rotator.MouseDownFlag) { rotator.MouseMove(e.X, e.Y); this.cameraUpdated = true; } { IColorCodedPicking pickable = this.renderer; pickable.MVP = this.camera.GetProjectionMat4() * this.camera.GetViewMat4(); IPickedGeometry pickedGeometry = ColorCodedPicking.Pick( this.camera, e.X, e.Y, this.glCanvas1.Width, this.glCanvas1.Height, pickable); if (pickedGeometry != null) { this.bulletinBoard.SetContent(pickedGeometry.ToString()); } else { this.bulletinBoard.SetContent("picked nothing."); } } }
/// <summary> /// Render the element that inherts <see cref="IColorCodedPicking"/> for color coded picking. /// </summary> /// <param name="picking"></param> /// <param name="gl"></param> /// <param name="renderMode"></param> public virtual void RenderForPicking(IColorCodedPicking picking, OpenGL gl, SceneGraph.Core.RenderMode renderMode) { if (picking != null) { picking.PickingBaseID = this.RenderedVertexCount; // render the element. SharpGL.SceneGraph.Core.IRenderable renderable = picking; renderable.Render(gl, renderMode); uint rendered = this.RenderedVertexCount + picking.GetVertexCount(); if (this.RenderedVertexCount <= rendered) { this.RenderedVertexCount = rendered; } else { throw new OverflowException( string.Format("Too many geometries({0} + {1} > {2}) for color coded picking.", this.RenderedVertexCount, picking.GetVertexCount(), uint.MaxValue)); } } }
//public override void Draw(SceneGraph.Cameras.Camera camera = null) //{ // this.Draw(camera, RenderMode.Design); //} /// <summary> /// Renders the element. /// </summary> /// <param name="gl">The gl.</param> /// <param name="renderMode">The render mode.</param> public void MyRenderElement(SceneElement sceneElement, OpenGL gl, RenderMode renderMode, SharedStageInfo info) { // If the element is disabled, we're done. if (sceneElement.IsEnabled == false) { return; } // Push each effect. foreach (var effect in sceneElement.Effects) { if (effect.IsEnabled) { effect.Push(gl, sceneElement); } } // If the element can be bound, bind it. IBindable bindable = sceneElement as IBindable;// example: Light if (bindable != null) { bindable.Push(gl); } // If the element has an object space, transform into it. IHasObjectSpace hasObjectSpace = sceneElement as IHasObjectSpace;// example: Polygon, quadric, Teapot if (hasObjectSpace != null) { hasObjectSpace.PushObjectSpace(gl); } // Render self. { // If the element has a material, push it. IHasMaterial hasMaterial = sceneElement as IHasMaterial;// example: Polygon, quadric, Teapot if (hasMaterial != null && hasMaterial.Material != null) { hasMaterial.Material.Push(gl); } if (renderMode == RenderMode.HitTest) { IColorCodedPicking picking = sceneElement as IColorCodedPicking; info.RenderForPicking(picking, gl, renderMode); } else { // If the element can be rendered, render it. IRenderable renderable = sceneElement as IRenderable; if (renderable != null) { renderable.Render(gl, renderMode); } } // If the element has a material, pop it. if (hasMaterial != null && hasMaterial.Material != null) { hasMaterial.Material.Pop(gl); } } // If the element is volume bound and we are rendering volumes, render the volume. IVolumeBound volumeBound = null; if (RenderBoundingVolumes) { volumeBound = sceneElement as IVolumeBound; if (volumeBound != null) { volumeBound.BoundingVolume.Render(gl, renderMode); } } // Recurse through the children. foreach (var childElement in sceneElement.Children) { MyRenderElement(childElement, gl, renderMode, info); } // If the element has an object space, transform out of it. if (hasObjectSpace != null) { hasObjectSpace.PopObjectSpace(gl); } // If the element can be bound, bind it. if (bindable != null) { bindable.Pop(gl); } // Pop each effect. for (int i = sceneElement.Effects.Count - 1; i >= 0; i--) { if (sceneElement.Effects[i].IsEnabled) { sceneElement.Effects[i].Pop(gl, sceneElement); } } }
/// <summary> /// Get geometry's count according to specified <paramref name="mode"/>. /// <para>Returns false if the <paramref name="element"/> is null.</para> /// </summary> /// <param name="element"></param> /// <param name="mode"></param> /// <param name="count"></param> /// <returns></returns> public static bool GetGeometryCount(this IColorCodedPicking element, PrimitiveModes mode, out uint count) { bool result = false; count = uint.MaxValue; if (element != null) { uint vertexCount = element.GetVertexCount(); switch (mode) { case PrimitiveModes.Points: count = vertexCount; break; case PrimitiveModes.Lines: count = vertexCount / 2; break; case PrimitiveModes.LineLoop: count = vertexCount; break; case PrimitiveModes.LineStrip: count = vertexCount - 1; break; case PrimitiveModes.Triangles: count = vertexCount / 3; break; case PrimitiveModes.TriangleStrip: count = vertexCount - 2; break; case PrimitiveModes.TriangleFan: count = vertexCount - 2; break; case PrimitiveModes.Quads: count = vertexCount / 4; break; case PrimitiveModes.QuadStrip: count = vertexCount / 2 - 1; break; case PrimitiveModes.Polygon: count = 1; break; default: throw new NotImplementedException(); } result = true; } return(result); }
/// <summary> /// Get geometry's index(start from 0) according to <paramref name="lastVertexID"/> and <paramref name="mode"/>. /// <para>Returns false if failed.</para> /// </summary> /// <param name="element"></param> /// <param name="mode"></param> /// <param name="lastVertexID">Refers to the last vertex that constructs the primitive. /// <para>Ranges from 0 to (<paramref name="element"/>'s vertices' count - 1).</para></param> /// <param name="index"></param> /// <returns></returns> public static bool GetGeometryIndex(this IColorCodedPicking element, PrimitiveModes mode, uint lastVertexID, out uint index) { index = uint.MaxValue; if (element == null) { return(false); } uint vertexCount = element.GetVertexCount(); if (lastVertexID < vertexCount) { switch (mode) { case PrimitiveModes.Points: // vertexID should range from 0 to vertexCount - 1. index = lastVertexID; break; case PrimitiveModes.Lines: // vertexID should range from 0 to vertexCount - 1. index = lastVertexID / 2; break; case PrimitiveModes.LineLoop: // vertexID should range from 0 to vertexCount. if (lastVertexID == 0) // This is the last primitive. { index = vertexCount - 1; } else { index = lastVertexID - 1; } break; case PrimitiveModes.LineStrip: index = lastVertexID - 1; // If lastVertexID is 0, this returns -1. break; case PrimitiveModes.Triangles: index = lastVertexID / 3; break; case PrimitiveModes.TriangleStrip: index = lastVertexID - 2; // if lastVertexID is 0 or 1, this returns -2 or -1. break; case PrimitiveModes.TriangleFan: index = lastVertexID - 2; // if lastVertexID is 0 or 1, this returns -2 or -1. break; case PrimitiveModes.Quads: index = lastVertexID / 4; break; case PrimitiveModes.QuadStrip: index = lastVertexID / 2 - 1; // If lastVertexID is 0 or 1, this returns -1. break; case PrimitiveModes.Polygon: index = 0; break; default: throw new NotImplementedException(); } } return(true); }