VRML в примерах

Марина Миланина, Diamond Team

Что такое VRML

Язык VRML (Virtual Realty Modelling Languagy) предназначен для описания трехмерных изображений и оперирует объектами, описывающими геометрические фигуры и их расположение в пространстве.

Vrml-файл представляет собой обычный текстовый файл, интерпретируемый браузером. Поскольку большинство браузеров не имеет встроенных средств поддержки vrml, для просмотра Vrml-документов необходимо подключить вспомогательную программу - Vrml-браузер, например, Live3D или Cosmo Player.

Как и в случае с HTML, один и тот же vrml-документ может выглядеть по-разному в разных VRML-браузерах. Кроме того, многие разработчики VRML-браузеров добавляют нестандартные расширения VRML в свой браузер.

Существует немало VRML-редакторов, делающих удобней и быстрее процесс создания Vrml-документов, однако несложные модели, рассматриваемые в данной статье, можно создать при помощи самого простого текстового редактора.

Единицы измерения

В VRML приняты следующие единицы измерения:

Заголовок VRML-файла

Как уже говорилось, Vrml-документ представляет собой обычный тестовый файл.

Для того, чтобы VRML-браузер распознал файл с VRML-кодом, в начале файла ставится специальный заголовок - file header:


    #VRML V1.0 ascii



Такой заголовок обязательно должен находиться в первой строке файла, кроме того, перед знаком диеза не должно быть пробелов.

Примитивы VRML

В VRML определены четыре базовые фигуры: куб (верней не куб, а прямоугольный параллепипед), сфера, цилиндр и конус.

Эти фигуры называются примитивами (primitives). Набор примитивов невелик, однако комбинируя их, можно строить достаточно сложные трехмерные изображения. Например, вот такие:

Рассмотрим поподробней каждый из примитивов.

Куб

Возможные параметры: width - ширина, height - высота, depth - глубина.




     Cube {

        width   2    # ширина

        height  3    # высота

        depth   1    # глубина 

          }



Сфера

Параметр у сферы только один, это radius.


    Sphere {

        radius  1    # радиус

           }



Конус

Возможные параметры: bottomRadius - радиус основания, height - высота, parts - определяет, какие части конуса будут видны. Параметр parts может принимать значения ALL, SIDES или BOTTOM.


     Cone {

        parts           ALL      #видны и основание, и боковая поверхность конуса

        bottomRadius    1        #радиус основания

        height          2        #высота

          }



Цилиндр

Для цилиндра можно задать параметры radius и height. Кроме того, с помощью параметра parts для цилиндра можно определить будут ли отображаться основания цилиндра и его боковая поверхность. Параметр parts может принимать значения ALL, SIDES, BOTTOM или TOP.


      Cylinder {

          parts   ALL      #видны все части цилиндра

          radius  1        #радиус основания

          height  2        #высота цилиндра

              }   



Цвет и текстура

Цвет фигуры, определяется с помощью объекта Material.


    Material {

         ambientColor    0.2 0.2 0.2

         diffuseColor    0.8 0.8 0.8

         specularColor   0 0 0

         emissiveColor   0 0 0

         transparency    0

             }

Параметры ambientColor, diffuseColor, specularColor и emissiveColor управляют цветами и указываются в палитре RGB (красный, зеленый и голубой), причем первая цифра определяет интенсивность красного цвета, вторая - зеленого, а третья - синего.

К примеру, синий кубик, может быть описан следующим образом:


    #VRML V1.0 ascii

        Material {

               diffuseColor 0 0 1

                 }

        Cube {}    

Параметр transparency может принимать значения от 0 до1 и определяет степень прозрачности, причем максимальная прозрачность достигается при transparency равном единице. В приведенном примере описано два цилиндра разных размеров, меньший из которых просвечивает сквозь другой.


    #VRML V1.0 ascii

       Material {

	      diffuseColor 0 0 1

          transparency    0.7

                }

       Cylinder {

          height  1

          radius  1

                }

       Material {

          emissiveColor    1 0 0

          transparency    0

                }

       Cylinder {

          height  0.8

          radius  0.1

                }

Для имитирования различных поверхностей в VRML существует объект Texture2.

В качестве текстуры легче всего использовать обычный графический файл, например, в GIF-формате. В таком случае для "натягивания" текстуры на трехмерное изображение нужно только указать путь к файлу в параметре filename объекта Texture2.


.     #VRML V1.0 ascii

     Texture2 {

                 filename    "krp.gif"

                 image       0 0 0

                 wrapS REPEAT 

                 wrapT REPEAT

                    }

     Cube { 

                 width 1

                 height 1

                 depth 1 

              }

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

Положение объектов в пространстве

Изменение координат

По умолчанию любой описанный нами объект будет располагаться точно по центру окна браузера. По этой причине, если мы опишем к примеру два одинаковых цилиндра, они сольются друг с другом. Для того, чтобы изменить положение второго цилиндра, применим узел Translation.

Узел Translation определяет координаты объекта:


    Translation {

         translation 1 2 3 #т.е. соответственно x=1 y=2 z=3

                }

Вообще говоря, координаты указываемые в Translation не являются абсолютными. Фактически это координаты относительно предыдущего узла Translation. Чтобы прояснить это вопрос, рассмотрим пример:


    #VRML V1.0 ascii

      Cube {

        width 1

        height 1

        depth 1

           }

     # Этот куб по умолчанию располагается в центре

      Translation {

          translation 2 0 0 

                  } 

     #Второй куб сдвинут вправо на 2

      Cube {

         width 1

         height 1

         depth 1

            }

      Translation {

         translation 2 0 0 

                  } 

     #Третий куб сдвинут вправо на два относительно 2-го !!!!

      Cube {

         width 1

         height 1

         depth 1

           }

Как видите, третий кубик вовсе не совпадает с первым, хотя в в узле Translation указаны те же координаты.

В VRML 1.0 принято следующее правило: узлы, модифицирующие свойства фигур (Translation, Material и т.п.), действуют на все далее описанные фигуры.

Чтобы ограничить область действия модифицирующих узлов, фигуры необходимо сгруппировать с помощью узла Separator.


     Separator 

                     {       

                 другие узлы

        }

Узел Separator работает как контейнер, он может содержать любые другие узлы, и основным его предназначением является именно ограничение области действия узлов типа Translation и Material.

Сравните следующий пример с предыдущим:


     #VRML V1.0 ascii

      Separator {

           Cube {

              width 1

              height 1

              depth 1

                 }

         }# конец области действия узла Separator

      Separator { 

           Translation {

                translation 2 0 0 

                       } 

           #Второй куб сдвинут вправо на 2

            Cube {

                 width 1

                 height 1

                 depth 1

                 }

         }# конец области действия узла Separator

       Separator {

             Translation {

                 translation 2 0 0 

                         } 

            #Третий куб сдвинут вправо на два относительно 1-го.

              Cube {

                 width 1

                 height 1

                 depth 1

                    }

        }# конец области действия узла Separator

Хотя в примере описано три кубика, мы видим только два, так как второй и третий совпадают.

Вообще говоря рекомендуется всегда и везде использовать узел Separator. Он не только избавит от ошибок, связанных с относительностью координат, но и сделает VRML-код более простым и понятным.

Вращение

Для вращения фигур вокруг осей координат применяется узел Rotation.


   Rotation {

         rotation 0 1 0  1.57

            }

Первые три цифры определяет будет ли осуществлен поворот вокруг соответственно осей x, y и z, а четвертая задает угол вращения в радианах. В приведенном выше листинге поворот осуществляется вокруг оси y на 90 градусов.

Углы в градусах Радианы
30 0.52
45 0.78
60 1.04
90 1.57
180 3.14
270 4.71

Составим букву T из двух цилиндров. По умолчанию цилиндр ориентирован вертикально (см. рисунок). Поэтому для успешного выполнения задачи повернем его вокруг оси z на 90 градусов.


     #VRML V1.0 ascii

      Separator { #Красный цилиндр 

               Material { emissiveColor   1 0.6 0.6 }

               Cylinder {

                      height    1

                      radius    0.3

                        }

                }

      Separator { # Синий цилиндр, повернутый на 90 градусов вокруг оси z

              Translation {

                    translation 0 0.5 0

                          }

              Rotation {

                     rotation    0 0 1  1.57

                       }

              Material { emissiveColor   0.5 0.5 1 }

              Cylinder {

                     height    1

                     radius    0.3

                       }

                }

Масштабирование

Узел Scale масштабирует фигуры по одному или нескольким измерениям. Три цифры, стоящие после параметра scaleFactor определяют коэффициенты масштабирования относительно осей x,y и z.


      Scale {

         scaleFactor 1 1 1

            }

В следующем примере, узел Scale сжимает сферу по оси x, и из сферы получается эллипсоид.


    #VRML V1.0 ascii

       Material { emissiveColor   1 1 0 }

       Scale {

          scaleFactor 0.7 1 1 #сжимаем сферу по оси x

             }

       Sphere { radius 1}

             }

Определение собственных объектов

VRML предоставляет прекрасную возможность сократить и сделать более понятным исходный код VRML-файла путем описания собственных объектов. Это значит, что если в изображении несколько раз повторяется одна и та же фигура, то ее можно описать всего лишь один раз и в дальнейшем только ссылаться на нее.

Объект описывается одним из способов:


    DEF name 

       Cube {}



 

или


    DEF name

       Material {}



или


    DEF name 

    Separator {

        Сгруппированные узлы, описывающие фигуру и свойства материала

    }



Для того, чтобы вставить в VRML-файл ранее определенную фигуру, используется команда USE


    Separator {

        USE name

    }

Создадим VRML-файл, описывающий стул, при этом ножку стула опишем как объект LEG:


    #VRML V1.0 ascii

    Material { emissiveColor 1 0.5 0.5 }

    Separator {

         Translation { translation 1 1 1 }

         DEF LEG  #Определяем объект - ножку стула

         Separator { # leg

            Cylinder {

               height  0.8

               radius  0.1

                     }

                   } # определили ножку

               }

    Separator { 

         Translation { translation 0 1 1 }

         USE LEG # используем определенный объект

              }

    Separator { # еще одна ножка

         Translation { translation 1 1 0 }

         USE LEG

              }

    Separator { # последняя ножка

         Translation { translation 0 1 0 }

         USE LEG

              }

    Separator { # сиденье

         Translation { translation 0.49 1.5 0.5 }

         Cube {

            height 0.2

            width 1.2

	         depth 1.2	

              }

              }

    Separator { # спинка

        Translation { translation 0.49 2 0 }

        Cube {

           height 0.8

           width 1.2

           depth 0.2	

             }

              }

    Separator { # закругление спинки

        Translation { translation 0.49 2.1 0 }

        Rotation {

           rotation    1 0 0 1.57

                 }

        Cylinder {

           radius 0.6

           height 0.2	

                 }

          }

Как видите, нам не понадобилось описывать каждую ножку в отдельности - в результате объем VRML-кода стал меньше, а сам код более читабельным.

Еще один способ уменьшить размер VRML-файла - вставлять фигуры из другого файла.

Это позволяет делать узел WWWInline:


    #VRML V1.0 ascii

    Separator {

          WWWInline {

              name        ""

              bboxSize    0 0 0

              bboxCenter  0 0 0

                    }

              }

Параметр name - это путь к файлу, параметры bboxSize и bboxCenter не обязательны и показывают пользователю размеры и положение вставляемого объекта, пока объект подгружается.

Вместо заключения, хочется обратить Ваше внимание на две особенности VRML, незнание которых сильно затруднит создание VRML-документов вручную.

  1. Все описания узлов и параметров в VRML регистрозависимы. Если Вы используете буквы неправильного регистра - то VRML-браузер просто проигнорирует такое описание.
  2. В VRML имеет огромное значение порядок описания узлов. Так к примеру, описание
    
           ...
    
           Rotation {...}
    
           Scale {...}
    
           ...
    
    
    и описание
    
         ...
    
         Scale {...}
    
         Rotation {...}
    
         ...
    
    
дают совершенно разный результат.

Большое спасибо Ромке за картинки:)