Метляков Андрей (deviaphan) wrote in coin3d_ru,
Метляков Андрей
deviaphan
coin3d_ru

Category:

SoRayPickAction

#include <Inventor/actions/SoRayPickAction.h> SoRayPickAction - выполняет поиск пересечений луча с граф-сценой. При поиске пересечений с лучом, полученным  из координат мыши, следует обратить внимание на используемые системы координат. В OpenGL начало экраных координат находится в левом нижнем углу и ось Y направлена вверх. Если координаты мыши возвращаются в иной системе координат, то их необходимо скорректировать соответствующим образом. Использование класса поиска пересечений я продемонстрирую на примере функции, выполняющей поиск. После небольших доработок её можно использовать в реальных проектах.
testpoint.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120     // Тип объекта, пересечение с которым хотим найти. Например preferredType = SoIndexedFaceSet::getClassTypeId() SoType preferredType; // отбрасываем при поиске грани, повёрнутые лицевой стороной от эрана bool testNormal = true; // Вы можете сгруппировать несколько отдельных граней (узлом SoSeparator), чтобы они выглядели как одно цельное тело. // Чтобы обнаружить пересечение с этим телом придётся пойти на небольшой трюк... bool testSolid = false; // используемая в граф-сцене камера SoCamera * camera = 0; // Проекция точки в экранных координатах в линию с учётом текущего положения камеры. bool GetLine( SoNode * root, SbVec2s pos, SbLine & line ) { // http://coin3d-ru.livejournal.com/28328.html SoPath * path = SearchPath(root, SoCamera::getClassTypeId() ); if( !path ) return false; // последний узел в пути это и есть искомый узел camera = path->getTail(); // удаляем путь. Узлы, хранящиеся в пути, удалены не будут, т.к. они находятся в граф сцене и иих счётчики не обнулятся path->unref(); if( !camera ) return false; // получаем проекцию точки в линию camera->getViewVolume().projectPointToLine(SbVec2f(pos[0], pos[1]), line); return true; } /* SoRayPickAction root - Узел в граф-сцене, от которого будет выполнен поиск pos - Координаты мыши или любая другая точка в экранных координатах vp - Размеры окна. Получается из текущего вьювера методом getViewportRegion() line - линия, направленная от "глаз" в глубину экрана. Используется для проверки ориентации проверяемых граней, если это нужно */ SoPath * TestPoint( SoNode * root, SbVec2s pos, SbViewportRegion const & vp, const SbVec3f * line ) { // Если фильтр хочется отключить, его можно отключить if( filter == None ) return NULL; // инициализируем габаритами окна просмотра SoRayPickAction rayPick( vp ); // Задаём радиус вокруг указанной точки, чтобы было проще попадать по рёбрам и точкам. По умолчанию 5.0 rayPick.setRadius( 3.0f ); // Находим все пересечения, а не только самое ближайшее к камере // Если использовать фильтрацию при поиске, то необходимо находить все пересечения и вручную отбрасывать лишние объекты rayPick.setPickAll( true ); // Можно перезадать размеры окна, указанные в конструкторе rayPick.setViewportRegion( vp ); // Указываем точку в экранных координатах, в которой будет производиться поиск rayPick.setPoint( pos ); // Выполняем поиск rayPick.apply( root ); // Получаем список всех найденных пересечений const SoPickedPointList & ppl = rayPick.getPickedPointList(); const int length = ppl.getLength(); if( length ) { SoPickedPoint * pp = 0; for(int i = 0; i < length; ++i ) { pp = (SoPickedPoint*)ppl.get(i); SoPath * path = pp->getPath(); assert( path ); assert( path->getTail() ); // Проверяем, совпадает ли тип узла с искомым типом, либо является дочерним к искомому типу if( path->getTail()->isOfType( preferredType ) ) { if( testNormal && line ) { // Данный код имеет смысл только для граней. У рёбер и точек нормалей быть не может. // Если вы выполняете поиск точек, то нужно запрещать тестирование нормалей, в противном случае вас ждёт UB // Получаем нормаль в точке пересечения const SbVec3f& wn = pp->getNormal(); // если направление нормали в точке пересечения совпадает с направлением взгляда, то мы смотрим с изнанки и может эту грань отбросить if( wn.dot(*line) >= 0 ) continue; // При необходимости можно получить точку пересечения const SbVec3f & pt = pp->getPoint(); // И текстурные координаты в данной точке const SbVec4f & tx = pp->getTextureCoords(); // Дополнительную информацию можно получить от одного из классов, унаследованных от SoDetail SoFaceDetail * detail = dynamic_cast<SoDetail*>( pp->getDetail() ); assert(detail); } if( testSolid ) { // Трюк! // Если производится поиск группирующего узла, то нужно выкинуть последний узел из пути (или два-три узла, в зависимости от архитектуры приложения) path->pop(); } // Увеличим счётчик, чтобы путь не удалился при разрушении объекта SoSearchAction path->ref(); return path; } } } // Нет выбранных узлов return NULL; }
Tags: класс:SoRayPickAction
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments