RU: Graphical Primitives 2

Отображение графических примитивов (грани)

Как было сказано выше (см. Отображение графических примитивов (точки, линии)), к примитивам участков поверхности относятся: отдельные треугольники, их цепочки и вееры, отдельные четырехугольники и их цепочки а также многоугольники (полигоны). Далее эти эти фигуры, ради краткости, будем называть многоугольниками.

Обычно многоугольники рисуются в виде закрашенной области пикселей, лежащих внутри их границ, но также они могут быть нарисованы в виде самой границы (ломаной) или просто в виде точек, соответствующих их вершинам. Возможна как полная заливка, так и применение различных шаблонов и наложение текстуры.

Обращаем внимание на то, что у грани есть две стороны — лицевая и обратная, и они могут рисоваться по-разному.

Свойства отображения грани

Свойства отображения участка поверхности описываются классом Graphic3d_AspectFillArea3d. Вначале перечислим их, а потом обсудим.

  • Стиль заполнения области, одно из значений перечисляемого типа Aspect_InteriorStyle:
    • Aspect_IS_EMPTY — область не рисуется (значение по умолчанию). Обращаем внимание на то, что в данном случае не отображается внутренность области, но этот признак не относится к ребрам границы (см. далее).
    • Aspect_IS_HOLLOW — область не рисуется, но рисуется ее граница. Граница рисуется тонкой линией цветом заполнения области. Хотя геометрически граница есть совокупность ребер, но подключение отображения ребер не зависит от данного признака. Иначе говоря, границу имеет смысл рисовать только без ребер.
    • Aspect_IS_SOLID — область заполняется.
    • Aspect_IS_HATCH — область заполняется и штрихуется. Тип штриховки устанавливается вызовом процедуры
         SetHatchStyle (const Aspect_HatchStyle AStyle)
      

      где Aspect_HatchStyle — перечисляемый тип, имеющий значения Aspect_HS_HORIZONTAL, Aspect_HS_HORIZONTAL_WIDE, Aspect_HS_VERTICAL и так далее.
    • Aspect_IS_HIDDENLINE — режим удаления невидимых линий.
    Отметим, что стиль заполнения относится к участку поверхности, а не отдельно к передней и задней его сторонам (как
    можно было бы представить). Т.е. нельзя, например, переднюю сторону залить цветом, а у задней отображать только
    ребра (что возможно в OpenGL).

    Стиль заполнения области можно указать в конструкторе, либо методом класса

       void SetInteriorStyle (const Aspect_InteriorStyle AStyle)
    

  • Атрибуты отображения ребер. По умолчанию ребра грани не рисуются. Включение/выключение их рисования выполняется вызовом
    процедур
       void    SetEdgeOn ()
       void    SetEdgeOff ()
    

    а цвет, ширина и стиль линии устанавливаются процедурами
       void    SetEdgeColor (const Quantity_Color &AColor)
       void    SetEdgeWidth (const Standard_Real AWidth)
       void    SetEdgeLineType (const Aspect_TypeOfLine AType)
    

  • По умолчанию (для стиля Aspect_IS_SOLID) передняя и задняя стороны грани отображаются одинаково. Включение/отключение отображения задней стороны выполняется процедурами
       void    AllowBackFace ()
       void    SuppressBackFace ()
    

    Для передней и задней сторон можно установить свой цвет заполнения области
       void    SetInteriorColor (const Quantity_Color &AColor)
       void    SetBackInteriorColor (const Quantity_Color &color)
    

    Область заливается этим цветом в том случае, если не задан материал. Материал, о котором подробнее см. ниже, для
    передней и задней сторон устанавливается процедурами
       void    SetFrontMaterial (const Graphic3d_MaterialAspect &AMaterial)
       void    SetBackMaterial (const Graphic3d_MaterialAspect &AMaterial)
    

  • Текстура грани (см. пример ниже) задается процедурами
       void    SetTextureMap (const Handle< Graphic3d_TextureMap > &ATexture)
       void    SetTextureMapOn ()
       void    SetTextureMapOff ()
    


Кострукторы класса Graphic3d_AspectFillArea3d имеют вид
    Graphic3d_AspectFillArea3d ()
    Graphic3d_AspectFillArea3d (const Aspect_InteriorStyle Interior,
       const Quantity_Color &InteriorColor, const Quantity_Color &EdgeColor,
       const Aspect_TypeOfLine EdgeLineType, const Standard_Real EdgeWidth,
       const Graphic3d_MaterialAspect &FrontMaterial,
       const Graphic3d_MaterialAspect &BackMaterial)

Первый создает набор свойств по-умолчанию, второй позволяет задать часть свойств.

Материал грани

Воспринимаемый цвет поверхности зависит от долей падающего красного, зеленого и синего света, которые он отражает. Например, максимально красный шар отражает весь красный свет, который на него падает и поглощает весь зеленый и синий. Если смотреть на такой шар в белом свете (состоящим из одинакового количества красного, зеленого и синего), весь красный свет отразится, и мы будем видеть красный шар. Если смотреть на шар при красном свете, он также будет выглядеть красным. Если, однако, посмотреть на него под зеленым светом, он будет выглядеть черным (весь зеленый свет поглотится, а красного нет, то есть никакой свет отражен не будет). Материалом поверхности называют ее способность отражать падающий свет.

Так же как и свет, материалы имеют разные фоновый (ambient), диффузный (diffuse) и зеркальный (specular) цвета, которые задают реакцию материала на фоновый, диффузный и зеркальный компоненты света. Кроме этого, материал может иметь излучающую (emissive) составляющую. Фоновый цвет материала комбинируется с фоновым компонентом всех источников света, диффузный цвет с диффузным компонентом, а зеркальный с зеркальным. Фоновый и диффузный цвета задают видимый цвет материала, они обычно близки, если не эквивалентны. Зеркальный цвет обычно белый или серый. Он задает цвет блика на объекте (то есть он может совпадать с зеркальным компонентом источника света).

Отражение фонового света (фоновое отражение) одинаково влияет на все участки поверхности, независимо от их ориентации по отношению к наблюдателю и положения источников света. Интенсивность диффузного отражения зависит от угла между нормалью к поверхности и направлением на источник света. Оно играет важную роль в восприятии формы поверхности и наиболее ярко в случае, если источник света расположен перпендикулярно к поверхности. Так же, как и для фонового отражения, оно не зависит от точки наблюдения. Зеркальное отражение создает блик, и, в отличие от фонового и диффузного отражений, интенсивнось зеркального отражения, зависит от положения точки наблюдения. Размер и яркость блика можно контролировать отдельным параметром — яркостью (shininess). Задавая излучающую
компоненту можно изобразить объект так, как будто он излучает свет. Нужно иметь в виду, что хотя такой объект выглядят светящимися, на самом деле они не служит источников света, то есть не оказывают никакого воздействия на другие объекты сцены. Для того, чтобы имитировать лампу или фонарь, нужно создать дополнительный источник света и поместить его в ту же позицию, что и светящийся объект.

Свойства материала описываются классом Graphic3d_MaterialAspect. В системе имеется довольно большой набор предопределенных материалов, имена которых перечислены в Graphic3d_NameOfMaterial и имеют вид Graphic3d_NOM_BRASS, Graphic3d_NOM_STEEL и так далее. Конструкторы класса имет вид

// Создание неопределенного материала
    Graphic3d_MaterialAspect()
// Создание материала с параметрами, указанными именем
    Graphic3d_MaterialAspect(const Graphic3d_NameOfMaterial AName)

Включение/отключение свойства отражения для одной из компонент выполняеся процедурами

// Включение свойства отражения поверхности.
// Graphic3d_TypeOfReflection -- перечисляемый тип, имеющий значения:
//    Graphic3d_TOR_AMBIENT -- отражение фонового света
//    Graphic3d_TOR_DIFFUSE -- отражение диффузного света
//    Graphic3d_TOR_SPECULAR -- зеркальное отражение
//    Graphic3d_TOR_EMISSION -- испускание света поверхностью
    void SetReflectionModeOn(const Graphic3d_TypeOfReflection AType)
// Отключение отражения поверхностью света определенного типа
    void SetReflectionModeOff(const Graphic3d_TypeOfReflection AType)

Для задания компонент отражения предназначены процедуры
// Фоновое отражение (цвет, интенсивность)
    void SetColor(const Quantity_Color& AColor) ;
    void SetAmbientColor(const Quantity_Color& AColor) ;
    void SetAmbient(const Standard_Real AValue) ;
// Диффузная компонента (цвет, интенсивность)
    void SetDiffuseColor(const Quantity_Color& AColor) ;
    void SetDiffuse(const Standard_Real AValue) ;
// Зеркальная компонента (цвет, интенсивность, яркость)
    void SetSpecularColor(const Quantity_Color& AColor)
    void SetSpecular(const Standard_Real AValue)
    void SetShininess(const Standard_Real AValue) ;
// Излучаемый свет (цвет, интенсивность)
   void SetEmissiveColor(const Quantity_Color& AColor) ;
   void SetEmissive(const Standard_Real AValue) ;

Кроме этого, можно установить прозрачность (transparency) материала. Эта величина изменяется от нуля (материал непрозрачный (opaque), значение по умолчанию), до единицы (полностью прозрачный (transparent)). Свойство прозрачности применимо только в том случае, если включена хотя бы одна из компонент отражения.

    void SetTransparency(const Standard_Real AValue) ;

Группа треугольников

Для задания группы треугольников, как уже было сказано выше, имеются три возможности: отдельный треугольник, цепочка (strip) и веер (fan). Разберем их последовательно.

OCC_graphPrim11.JPG
OCC_graphPrim12.JPG
OCC_graphPrim13.JPG


Класс Graphic3d_ArrayOfTriangles — позволяет задать группу из одного или нескольких отдельных треугольников. Конструктор класса имеет вид:

   Graphic3d_ArrayOfTriangles (const Standard_Integer maxVertexs,
      const Standard_Integer maxEdges=0,
      const Standard_Boolean hasVNormals=Standard_False,
      const Standard_Boolean hasVColors=Standard_False,
      const Standard_Boolean hasTexels=Standard_False,
      const Standard_Boolean hasEdgeInfos=Standard_False)

Простейший способ описания группы состоит в указании троек точек, которые рассматриваются как вершины треугольников.

Например, построим тетраэдр (правильную треугольную пирамиду), взяв в качестве вершин точки с координатами (вершины куба)

(1)
\begin{align} (+1, -1, -1), \qquad (-1, +1, -1), \qquad (-1, -1, +1), \qquad (+1, +1, +1) \end{align}

— четыре треугольника. Вот как выглядит участок программы:

//
// Вершины куба
   gp_Pnt point[8];
   Standard_Real side = 1.0;   // Длина (половина) стороны куба
   point[0].SetCoord(-side,-side,-side);
   point[1].SetCoord(side,-side,-side);
   point[2].SetCoord(side,side,-side);
   point[3].SetCoord(-side,side,-side);
   point[4].SetCoord(-side,-side,side);
   point[5].SetCoord(side,-side,side);
   point[6].SetCoord(side,side,side);
   point[7].SetCoord(-side,side,side);
//
   Handle(Graphic3d_AspectFillArea3d) aspectArea;
   aspectArea = new  Graphic3d_AspectFillArea3d();
   aspectArea->SetInteriorStyle(Aspect_IS_SOLID);
   aspectArea->SetInteriorColor (Quantity_NOC_WHITE);
   aspectArea->SetEdgeOn ();
   aspectArea->SetEdgeColor (Quantity_NOC_YELLOW);
   aspectArea->SetEdgeWidth (2.0);
//
   Handle(Graphic3d_Group) group;
   group = new Graphic3d_Group(structure) ;
   group->SetPrimitivesAspect(aspectArea);
//
// 4 треугольника, всего 12 точек
   Handle(Graphic3d_ArrayOfTriangles) arrayOfTriangles;
   arrayOfTriangles = new Graphic3d_ArrayOfTriangles(12);
   arrayOfTriangles->AddVertex(point[1]);
   arrayOfTriangles->AddVertex(point[3]);
   arrayOfTriangles->AddVertex(point[6]);
   arrayOfTriangles->AddVertex(point[6]);
   arrayOfTriangles->AddVertex(point[3]);
   arrayOfTriangles->AddVertex(point[4]);
   arrayOfTriangles->AddVertex(point[4]);
   arrayOfTriangles->AddVertex(point[3]);
   arrayOfTriangles->AddVertex(point[1]);
   arrayOfTriangles->AddVertex(point[4]);
   arrayOfTriangles->AddVertex(point[1]);
   arrayOfTriangles->AddVertex(point[6]);
//
   group->AddPrimitiveArray (arrayOfTriangles);

Результат представлен на левом рисунке ниже.

OCC_graphPrim03.JPG
OCC_graphPrim04.JPG
OCC_graphPrim05.JPG

Другой способ состоит в указании точек и троек ребер каждого треугольника. Например (изменение в предыдущем)

//
// 4 треугольника, 4 вершины, 12 ребер
      arrayOfTriangles = new Graphic3d_ArrayOfTriangles(4,12);
      arrayOfTriangles->AddVertex(point[1]);      // 1
      arrayOfTriangles->AddVertex(point[3]);      // 2
      arrayOfTriangles->AddVertex(point[4]);      // 3
      arrayOfTriangles->AddVertex(point[6]);      // 4
   // 1
      arrayOfTriangles->AddEdge(1);
      arrayOfTriangles->AddEdge(2);
      arrayOfTriangles->AddEdge(4);
   // 2
      arrayOfTriangles->AddEdge(4);
      arrayOfTriangles->AddEdge(2);
      arrayOfTriangles->AddEdge(3);
   // 3
      arrayOfTriangles->AddEdge(3);
      arrayOfTriangles->AddEdge(2);
      arrayOfTriangles->AddEdge(1);
   // 4
      arrayOfTriangles->AddEdge(3);
      arrayOfTriangles->AddEdge(1);
      arrayOfTriangles->AddEdge(4);

Мы можем залить разные грание разными цветами. Для этого перед включением треугольника в группу нужно изменить текущие свойства, как показано ниже:

//
// Грани различными цветами
   aspectArea = new  Graphic3d_AspectFillArea3d();
   aspectArea->SetInteriorStyle(Aspect_IS_SOLID);
   aspectArea->SetInteriorColor (Quantity_NOC_WHITE);
   aspectArea->SetEdgeOn ();
   aspectArea->SetEdgeColor (Quantity_NOC_YELLOW);
   aspectArea->SetEdgeWidth (2.0);
   group->SetPrimitivesAspect(aspectArea);
// White
   arrayOfTriangles = new Graphic3d_ArrayOfTriangles(3);
   arrayOfTriangles->AddVertex(point[1]);
   arrayOfTriangles->AddVertex(point[3]);
   arrayOfTriangles->AddVertex(point[6]);
   group->AddPrimitiveArray (arrayOfTriangles);
// Red
   aspectArea->SetInteriorColor (Quantity_NOC_RED);
   group->SetPrimitivesAspect(aspectArea);
   arrayOfTriangles = new Graphic3d_ArrayOfTriangles(3);
   arrayOfTriangles->AddVertex(point[6]);
   arrayOfTriangles->AddVertex(point[3]);
   arrayOfTriangles->AddVertex(point[4]);
   group->AddPrimitiveArray (arrayOfTriangles);
// Green
   aspectArea->SetInteriorColor (Quantity_NOC_GREEN);
   group->SetPrimitivesAspect(aspectArea);
   arrayOfTriangles = new Graphic3d_ArrayOfTriangles(3);
   arrayOfTriangles->AddVertex(point[4]);
   arrayOfTriangles->AddVertex(point[3]);
   arrayOfTriangles->AddVertex(point[1]);
   group->AddPrimitiveArray (arrayOfTriangles);
// Blue
   aspectArea->SetInteriorColor (Quantity_NOC_BLUE1);
   group->SetPrimitivesAspect(aspectArea);
   arrayOfTriangles = new Graphic3d_ArrayOfTriangles(3);
   arrayOfTriangles->AddVertex(point[4]);
   arrayOfTriangles->AddVertex(point[1]);
   arrayOfTriangles->AddVertex(point[6]);
   group->AddPrimitiveArray (arrayOfTriangles);

Результат — на рисунке выше, в центре.

Вернемся к обсуждению параметров конструтора. Третьим параметром служит Standard_Boolean hasVNormals=Standard_False, т.е. у вершин можно задавать нормали, и по умолчанию они отключены. Влияние нормалей мы отложим до обсуждения источников света.

Четвертый параметр Standard_Boolean hasVColors=Standard_False указывает на то, что у вершин можно задавать цвет. Обсудим эту возможность на примере тетраэдра. Вершину $(+1, -1, -1)$ сделаем красной, вершину $(-1, +1, -1)$ — зеленой, $(-1, -1, +1)$ — белой, а $(+1, +1, +1)$ — синей. Соответствующий участок программы выглядит так:

//
// Цвета у вершин
   arrayOfTriangles = new Graphic3d_ArrayOfTriangles(3, 0, Standard_False,Standard_True);
   arrayOfTriangles->AddVertex(point[1],Quantity_NOC_RED);
   arrayOfTriangles->AddVertex(point[3],Quantity_NOC_GREEN);
   arrayOfTriangles->AddVertex(point[6],Quantity_NOC_BLUE1);
   group->AddPrimitiveArray (arrayOfTriangles);
//
   arrayOfTriangles = new Graphic3d_ArrayOfTriangles(3, 0, Standard_False,Standard_True);
   arrayOfTriangles->AddVertex(point[6],Quantity_NOC_BLUE1);
   arrayOfTriangles->AddVertex(point[3],Quantity_NOC_GREEN);
   arrayOfTriangles->AddVertex(point[4],Quantity_NOC_WHITE);
   group->AddPrimitiveArray (arrayOfTriangles);
//
   arrayOfTriangles = new Graphic3d_ArrayOfTriangles(3, 0, Standard_False,Standard_True);
   arrayOfTriangles->AddVertex(point[4],Quantity_NOC_WHITE);
   arrayOfTriangles->AddVertex(point[3],Quantity_NOC_GREEN);
   arrayOfTriangles->AddVertex(point[1],Quantity_NOC_RED);
   group->AddPrimitiveArray (arrayOfTriangles);
//
   arrayOfTriangles = new Graphic3d_ArrayOfTriangles(3, 0, Standard_False,Standard_True);
   arrayOfTriangles->AddVertex(point[4],Quantity_NOC_WHITE);
   arrayOfTriangles->AddVertex(point[1],Quantity_NOC_RED);
   arrayOfTriangles->AddVertex(point[6],Quantity_NOC_BLUE1);
   group->AddPrimitiveArray (arrayOfTriangles);

а результат показан на рисунке выше справа.

Пятый параметр конструктора Standard_Boolean hasTexels=Standard_False сявязан с заданием координат текстуры. Пример наложения текстуры приведен ниже.

Шестой параметр Standard_Boolean hasEdgeInfos=Standard_False связан с возможностью не отображать некоторые ребра.

Перейдем к классу Graphic3d_ArrayOfTriangleStrips — одна или несколько цепочек треугольников. Процедуры класса позволяют задать последовательность треугольников (см. рисунок выше), используя вершины V[0], V[1] и V[2], затем V[2], V[1] и V[3] (обратите внимание на порядок), затем V[2], V[3], V[4], и так далее. Такой порядок гарантирует, что все треугольники будут иметь одинаковую ориентацию и, таким образом, соединенные треугольники могут сформировать часть поверхности.

Класс Graphic3d_ArrayOfTriangleFans описывает один или несколько вееров треугольников. В отличие от цепочки, порядок вершин следующий: V[0], V[1], V[2], затем V[0], V[2], V[3], затем V[0], V[3], V[4], и так далее (см. рисунок выше).

Четырехугольники и многоугольники (полигоны)

Класс Graphic3d_ArrayOfQuadrangles позволяет задать один или несколько отдельных четырехугольников, используя вершины V[0], V[1], V[2], V[3], затем V[4], V[5], V[6], V[7], и так далее.

Приведем пример наложения текстуры на четырехугольник. Для отображения текстуры необходимо выставить признак разрешения такого отображения. Это можно сделать для всех представлений, вызвав метод void V3d_Viewer::SetDefaultSurfaceDetail( const V3d_TypeOfSurfaceDetail Type ), либо только для одного методом void V3d_View::SetSurfaceDetail( const V3d_TypeOfSurfaceDetail SurfaceDetail ). Итак

// Текстура на верхней грани куба
   myViewer->SetDefaultSurfaceDetail(V3d_TEX_ALL); // Позволяем отображать текстуру
//
// Свойства грани
   aspectArea = new  Graphic3d_AspectFillArea3d();
   aspectArea->SetInteriorStyle(Aspect_IS_SOLID);
   aspectArea->SetInteriorColor (Quantity_NOC_RED);  // Заливка красным
//
// Текстура (из стандартного набора)
   Handle(Graphic3d_Texture2D) texture = new Graphic3d_Texture2Dmanual(Graphic3d_NOT_2D_MATRA);
   aspectArea->SetTextureMapOn ();
   aspectArea->SetTextureMap (texture);
//
   group->SetPrimitivesAspect(aspectArea);
//
// Квадрат верхней грани кубика
   Handle(Graphic3d_ArrayOfQuadrangles) arrayOfQuadra;
   arrayOfQuadra = new Graphic3d_ArrayOfQuadrangles(/* maxVertexs = */ 4 ,/* maxEdges = */ 0 ,
      /* hasVNormals = */ Standard_False , /* hasVColors = */ Standard_False ,
      /* hasTexels = */ Standard_True, /* hasEdgeInfos = */ Standard_False);
   arrayOfQuadra->AddVertex(point[5] );   // 1
   arrayOfQuadra->AddVertex(point[6] );   // 2
   arrayOfQuadra->AddVertex(point[7] );   // 3
   arrayOfQuadra->AddVertex(point[4] );   // 4
// Координаты текстуры для узлов
   arrayOfQuadra->SetVertexTexel( 1, 0., 0.);
   arrayOfQuadra->SetVertexTexel( 2, 1., 0.);
   arrayOfQuadra->SetVertexTexel( 3, 1., 1.);
   arrayOfQuadra->SetVertexTexel( 4, 0., 1.);
// Вставляем квадрат в группу
   group->AddPrimitiveArray(arrayOfQuadra);

Результат показан на рисунке справа.

Класс Graphic3d_ArrayOfQuadrangleStrips предоставляет процедуры для создания одной или нескольких цепочек четырехугольников, которые строятся, используя следующий порядок вершин: V[0], V[1], V[3], V[2], затем V[2], V[3], V[5], V[4], затем V[4], V[5], V[7], V[6] и так далее.

Процедуры класса Graphic3d_ArrayOfPolygons создают один или несколько многоугольников, используя точки V[0], V[1], V[2], …, V[n-1] в качестве вершин. Пример применения многоугольников см. в Пример. Правильные многогранники.

OCC_graphPrim23.JPG