CSharpGL(21)用鼠标拾取、拖拽VBO图元内的点、线或本身

以最常见的三角形网格(用GL_TRIANGLES方式进行渲染)为例。

在拾取模式为GeometryType.Point时,你可以拾取单个的顶点。

CSharpGL(21)用鼠标拾取、拖拽VBO图元内的点、线或本身

在拾取模式为GeometryType.Line时,你可以拾取任意一个三角形里的任意一条线。即同时拾取此线段的两个顶点。

CSharpGL(21)用鼠标拾取、拖拽VBO图元内的点、线或本身

在拾取模式为GeometryType.Triangle时,你可以拾取任意一个三角形。即同时拾取此三角形的三个顶点。

CSharpGL(21)用鼠标拾取、拖拽VBO图元内的点、线或本身

实际上,CSharpGL实现了在所有渲染模式下拾取Point、Line、Triangle、Quad和Polygon的功能。(当然,你可以想象,如果想在一个GL_TRIANGLES渲染方式下拾取一个Quad,那是什么都拾取不到的)下面是描述这一功能的图示。由于我的白板小,就没有列出GL_TRIANGLES_ADJACENCY、GL_TRIANGLE_STRIP_ADJACENCY、GL_LINES_ADJACENCY、GL_LINE_STRIP_ADJCANCEY这几个情况。

CSharpGL(21)用鼠标拾取、拖拽VBO图元内的点、线或本身

下载

CSharpGL已在GitHub开源,欢迎对OpenGL有兴趣的同学加入(https://github.com/bitzhuwei/CSharpGL

规定

为了简便描述,我用GL_LINE*代表GL_LINES、GL_LINE_STRIP、GL_LINES_ADJACENCY、GL_LINE_STRIP_ADJACENCY,用GL_TRIANGLE*代表GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN、GL_TRIANGLES_ADJACENCY、GL_TRIANGLE_STRIP_ADJACENCY,用GL_QUAD*代表GL_QUADS、GL_QUAD_STRIP。

如何使用

使用方式十分简单,只需给RenderEventArgs传入如下的参数:

 1 GeometryType PickingGeometryType = Geometry.Point;
 2 var arg = new RenderEventArgs(
 3     // 为了拾取而进行的渲染
 4     RenderModes.ColorCodedPicking,
 5     this.glCanvas1.ClientRectangle,
 6     this.camera, 
 7     // 我想拾取的类型(Geometry)
 8     this.PickingGeometryType);
 9 // 要拾取的位置(鼠标位置)
10 Point mousePostion = GetMousePosition();
11 // 支持Picking的Renderer列表 
12 PickableRenderer[] pickableElements = GetRenderersInScene();
13 // 执行拾取操作
14 PickedGeometry pickedGeometry = ColorCodedPicking.Pick(arg, mousePostion, pickableElements);

具体用法详见(CSharpGL(20)用unProject和Project实现鼠标拖拽图元

如何实现

在GL_POINTS时拾取Point,在GL_LINE*时拾取Line,在GL_TRIANGL*时拾取Triangle,在GL_QUAD*时拾取Quad,在GL_POLYGON时拾取Polygon,这都是已经实现了的(CSharpGL(18)分别处理glDrawArrays()和glDrawElements()两种方式下的拾取(ColorCodedPicking))。这些不再详述。

拾取Point

ZeroIndexRenderer

在除了GL_POINTS时,想拾取一个Point,只能用 glDrawArrays(GL_POINTS, ..); 来代替原有的 glDrawArrays(OriginalMode, ..); 。但这会渲染所有的顶点。而在OriginalMode下,未必渲染所有的顶点。所以在拾取到一个Point后要判断一下是否真的应该拾取到它。

  1         /// <summary>
  2         /// 现在,已经判定了鼠标在某个点上。
  3         /// 我需要判定此点是否出现在图元上。
  4         /// now that I know the mouse is picking on some point,
  5         /// I need to make sure that point should appear.
  6         /// </summary>
  7         /// <param name="lastVertexId"></param>
  8         /// <param name="mode"></param>
  9         /// <returns></returns>
 10         private bool OnPrimitiveTest(uint lastVertexId, DrawMode mode)
 11         {
 12             bool result = false;
 13             int first = this.zeroIndexBufferPtr.FirstVertex;
 14             if (first < 0) { return false; }
 15             int vertexCount = this.zeroIndexBufferPtr.VertexCount;
 16             if (vertexCount <= 0) { return false; }
 17             int last = first + vertexCount - 1;
 18             switch (mode)
 19             {
 20                 case DrawMode.Points:
 21                     result = true;
 22                     break;
 23                 case DrawMode.LineStrip:
 24                     result = vertexCount > 1;
 25                     break;
 26                 case DrawMode.LineLoop:
 27                     result = vertexCount > 1;
 28                     break;
 29                 case DrawMode.Lines:
 30                     if (vertexCount > 1)
 31                     {
 32                         if (vertexCount % 2 == 0)
 33                         {
 34                             result = (first <= lastVertexId && lastVertexId <= last);
 35                         }
 36                         else
 37                         {
 38                             result = (first <= lastVertexId && lastVertexId <= last - 1);
 39                         }
 40                     }
 41                     break;
 42                 case DrawMode.LineStripAdjacency:
 43                     if (vertexCount > 3)
 44                     {
 45                         result = (first < lastVertexId && lastVertexId < last);
 46                     }
 47                     break;
 48                 case DrawMode.LinesAdjacency:
 49                     if (vertexCount > 3)
 50                     {
 51                         var lastPart = last - (last + 1 - first) % 4;
 52                         if (first <= lastVertexId && lastVertexId <= lastPart)
 53                         {
 54                             var m = (lastVertexId - first) % 4;
 55                             result = (m == 1 || m == 2);
 56                         }
 57                     }
 58                     break;
 59                 case DrawMode.TriangleStrip:
 60                     if (vertexCount > 2)
 61                     {
 62                         result = vertexCount > 2;
 63                     }
 64                     break;
 65                 case DrawMode.TriangleFan:
 66                     if (vertexCount > 2)
 67                     {
 68                         result = vertexCount > 2;
 69                     }
 70                     break;
 71                 case DrawMode.Triangles:
 72                     if (vertexCount > 2)
 73                     {
 74                         if (first <= lastVertexId)
 75                         {
 76                             result = ((vertexCount % 3 == 0) && (lastVertexId <= last))
 77                                 || ((vertexCount % 3 == 1) && (lastVertexId < last))
 78                                 || ((vertexCount % 3 == 2) && (lastVertexId + 1 < last));
 79                         }
 80                     }
 81                     break;
 82                 case DrawMode.TriangleStripAdjacency:
 83                     if (vertexCount > 5)
 84                     {
 85                         var lastPart = last - (last + 1 - first) % 2;
 86                         if (first <= lastVertexId && lastVertexId <= lastPart)
 87                         {
 88                             result = (lastVertexId - first) % 2 == 0;
 89                         }
 90                     }
 91                     break;
 92                 case DrawMode.TrianglesAdjacency:
 93                     if (vertexCount > 5)
 94                     {
 95                         var lastPart = last - (last + 1 - first) % 6;
 96                         if (first <= lastVertexId && lastVertexId <= lastPart)
 97                         {
 98                             result = (lastVertexId - first) % 2 == 0;
 99                         }
100                     }
101                     break;
102                 case DrawMode.Patches:
103                     // not know what to do for now
104                     break;
105                 case DrawMode.QuadStrip:
106                     if (vertexCount > 3)
107                     {
108                         if (first <= lastVertexId && lastVertexId <= last)
109                         {
110                             result = (vertexCount % 2 == 0)
111                                 || (lastVertexId < last);
112                         }
113                     }
114                     break;
115                 case DrawMode.Quads:
116                     if (vertexCount > 3)
117                     {
118                         if (first <= lastVertexId && lastVertexId <= last)
119                         {
120                             var m = vertexCount % 4;
121                             if (m == 0) { result = true; }
122                             else if (m == 1) { result = lastVertexId + 0 < last; }
123                             else if (m == 2) { result = lastVertexId + 1 < last; }
124                             else if (m == 3) { result = lastVertexId + 2 < last; }
125                             else { throw new Exception("This should never happen!"); }
126                         }
127                     }
128                     break;
129                 case DrawMode.Polygon:
130                     if (vertexCount > 2)
131                     {
132                         result = (first <= lastVertexId && lastVertexId <= last);
133                     }
134                     break;
135                 default:
136                     throw new NotImplementedException();
137             }
138 
139             return result;
140         }
bool OnPrimitiveTest(uint lastVertexId, DrawMode mode)

相关文章: