/// <summary> /// uint[]配列のセレクション・バッファを解析して、 /// SelectionDataのリストに変換する。 /// </summary> /// <param name="selectionBuffer">セレクションモードで得られたセレクション・バッファ</param> /// <returns>ヒットしたデータのリスト</returns> public static List <SelectionData> ParseSelectionBuffer(uint[] selectionBuffer) { List <SelectionData> dataList = new List <SelectionData>(); int i = 0; try { for (i = 0; i < selectionBuffer.Length;) { if (selectionBuffer[i] == 0) { break; } SelectionData data = new SelectionData(); data.nameStackDepth = (int)selectionBuffer[i++]; data.zMin = (double)selectionBuffer[i++] / (double)uint.MaxValue; data.zMax = (double)selectionBuffer[i++] / (double)uint.MaxValue; data.names = new int[data.nameStackDepth]; for (int j = 0; j < data.nameStackDepth; ++j) { data.names[j] = (int)selectionBuffer[i++]; } dataList.Add(data); } } catch (IndexOutOfRangeException ex) //selectionBufferの長さが足りないと、IndexOutOfRangeExceptionが発生してここに来る。 { if (i >= selectionBuffer.Length) // つまり、selectionBufferの長さが足りない { //この場合は、うまく取得できたデータだけを返して、長さが足りない分は無視。 } else { //それ以外は想定外のエラーなので、とりあえずエラーを投げておく。 throw new Exception("ParseSelectionBuffer failed.", ex); } } catch (Exception ex) { //IndexOutOfRangeException以外は想定外のエラーなので、とりあえずエラーを投げておく。 throw new Exception("ParseSelectionBuffer failed.", ex); } return(dataList); }
/// <summary> /// <para>ヒットしたオブジェクトのリストから、最も遠くにあるオブジェクトを取得する。</para> /// <para>リストのカウントが0の場合はnullを返す。</para> /// </summary> /// <param name="pickedList">ヒットしたオブジェクトのリスト</param> /// <returns><para>最も遠くにあるオブジェクト。</para> /// <para>pickedListのカウントが0の場合はnullを返す。</para></returns> public static SelectionData GetFarthest(List <SelectionData> pickedList) { if (pickedList == null) { return(null); } double zMax = double.MinValue; SelectionData farthest = null; for (int i = 0; i < pickedList.Count; i++) { if (pickedList[i].zMax > zMax) { farthest = pickedList[i]; } } return(farthest); }
/// <summary> /// <para>ヒットしたオブジェクトのリストから、最も手前にあるオブジェクトを取得する。</para> /// <para>リストのカウントが0の場合はnullを返す。</para> /// </summary> /// <param name="pickedList">ヒットしたオブジェクトのリスト</param> /// <returns><para>最も手前にあるオブジェクト。</para> /// <para>pickedListのカウントが0の場合はnullを返す。</para></returns> public static SelectionData GetNearest(List <SelectionData> pickedList) { if (pickedList == null) { return(null); } double zMin = double.MaxValue; SelectionData nearest = null; for (int i = 0; i < pickedList.Count; i++) { if (pickedList[i].zMin < zMin) { nearest = pickedList[i]; } } return(nearest); }
//####################################### #region public static List<SelectionData> Pick<T>( ... ) where T : class /// <summary> /// OpenGLのセレクションモードを利用して、マウスピッキングを行う。 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="items">対象となるオブジェクトのリスト</param> /// <param name="renderingParams">レンダリングパラメータ</param> /// <param name="mousePos">ピッキングするウィンドウ座標(左下原点)(double[]{x, y})</param> /// <param name="region">ヒットする範囲の幅と高さ(double[]{width, height})</param> /// <param name="camera">シーンのカメラ(要プロジェクション設定)</param> /// <param name="viewport">シーンのビューポート</param> /// <param name="pickChild">trueを指定した場合、子オブジェクト単位でヒットする。 /// falseの場合は、階層構造のトップのオブジェクトがヒットする。</param> /// <param name="pickedMatrixSet">セレクションモードで使用された変換行列。 /// ただし、Modelviewプロパティには引数cameraによるビューイング変換を表す行列が格納される。</param> /// <returns><para>ヒットしたオブジェクトのリスト。</para> /// <para>ヒットしたオブジェクトは、SelectionData.itemフィールドに格納されている。</para></returns> public static List <SelectionData> Pick <T>( IDictionary <int, T> items, double[] mousePos, double[] region, Jusin.Camera.CCamera camera, int[] viewport, bool pickChild, out TransformMatrixes pickedMatrixSet) where T : class { int err = Gl.glGetError(); if (err != Gl.GL_NO_ERROR) { throw new Exception(); } uint[] selectionBuff = new uint[SelectionBufferLength]; Gl.glSelectBuffer(selectionBuff.Length, selectionBuff); Gl.glRenderMode(Gl.GL_SELECT); Gl.glInitNames(); Gl.glPushName(0); //マウスピッキング時の変換行列 //しばしば必要になるので、取得しておく。 pickedMatrixSet = new TransformMatrixes(); pickedMatrixSet.Viewport = viewport; Gl.glMatrixMode(Gl.GL_PROJECTION); Gl.glPushMatrix(); Gl.glLoadIdentity(); //プロジェクション行列を取得。 camera.ApplyProjection(); double[] current_projection = new double[16]; Gl.glGetDoublev(Gl.GL_PROJECTION_MATRIX, current_projection); pickedMatrixSet.Projection = current_projection; //PickMatrixをセットする必要があるので、改めてプロジェクション行列をセット。 Gl.glLoadIdentity(); Glu.gluPickMatrix(mousePos[0], mousePos[1], region[0], region[1], viewport); Gl.glMultMatrixd(pickedMatrixSet.Projection); //モデルビュー行列を設定。 Gl.glMatrixMode(Gl.GL_MODELVIEW); Gl.glPushMatrix(); Gl.glLoadIdentity(); camera.gluLookAtLH(); //モデルビュー行列を取得。 Gl.glGetDoublev(Gl.GL_MODELVIEW_MATRIX, pickedMatrixSet.Modelview); foreach (int key in items.Keys) { if ((items[key] != null) && (items[key] is ISelectable)) { ISelectable drawItem = (ISelectable)items[key]; if (drawItem.Selectable) { Gl.glLoadName(drawItem.name); drawItem.DrawSceneForSelectionMode(drawItem.name); } } } /* * for (int i = 0; i < items.Count; i++) * { * * if ((items[i] != null) && (items[i] is ISelectable)) * { * ISelectable drawItem = (ISelectable)items[i]; * if (drawItem.Selectable) * { * Gl.glLoadName(drawItem.name); * drawItem.DrawSceneForSelectionMode(drawItem.name); * } * } * }*/ Gl.glPopName(); Gl.glMatrixMode(Gl.GL_PROJECTION); Gl.glPopMatrix(); Gl.glMatrixMode(Gl.GL_MODELVIEW); Gl.glPopMatrix(); int hits = Gl.glRenderMode(Gl.GL_RENDER); err = Gl.glGetError(); if (err != Gl.GL_NO_ERROR) { throw new Exception(err.ToString()); } List <SelectionData> hitData = SelectionData.ParseSelectionBuffer(selectionBuff); if (hitData.Count != 0) { if (pickChild) { for (int i = 0; i < hitData.Count; i++) { hitData[i].item = ((ISelectable)items[hitData[i].names[0]]).GettHitObject(hitData[i]); } } else { for (int i = 0; i < hitData.Count; i++) { hitData[i].item = (ISelectable)items[hitData[i].names[0]]; } } } return(hitData); }