Различия между текстурными картами. Создание материалов и текстур для трехмерных моделей


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


Color = texture(ourTexture, TexCoord) * vec4(ourColor, 1.0f);

У вас должно получиться нечто такое?


Текстурный блок

Возможно вы задаетесь вопросом: “Почему sampler2D переменная является uniform, если мы ей так и не присвоили никакое значение с помощью glUniform ?”. С помощью glUniform1i мы можем присвоить значение метоположения текстурному сэмплеру для возможности использования нескольких текстур в одном фрагментном шейдере. Местоположение текстуры чаще называется текстурным блоком. Текстурный блок по умолчанию - 0, который означает текущий активный текстурный блок для того, чтобы нам не требовалось указывать местоположение в прошлой секции.


Основная цель текстурных блоков это обеспечение возможности использования более чем 1 текстуры в нашем шейдере. Передавая текстурные блоки сэмплеру мы можем привязывать несколько текстур за один раз до тех пор, пока мы активируем соотносящиеся текстурные блоки. Также как и glBindTexture мы можем активировать текстуры с помощью glActivateTexture передавая туда текстурный блок, который мы хотим использовать:


glActiveTexture(GL_TEXTURE0); // Активируем текстурный блок перед привязкой текстуры glBindTexture(GL_TEXTURE_2D, texture);

После активации текстурного блока, последующий вызов glBindTexture привяжет эту текстуру к активному текстурному блоку. Блок GL_TEXTURE0 всегда активирован по-умолчанию, так что нам не требовалось активировать текстурные блоки в прошлом примере.


OpenGL поддерживает как минимум 16 текстурных блоков, которые вы можете получить через GL_TEXTURE0 - GL_TEXTURE15 . Они объявлены по-порядку, поэтому вы также можете получить их следующим образом: GL_TEXTURE8 = GL_TEXTURE0 + 8 . Это удобно, если вам приходится итерировать через текстурные блоки.

В любом случае нам все еще требуется изменить фрагментный шейдер для принятия другого сэмплера:


#version 330 core ... uniform sampler2D ourTexture1; uniform sampler2D ourTexture2; void main() { color = mix(texture(ourTexture1, TexCoord), texture(ourTexture2, TexCoord), 0.2); }

Финальный результат - это комбинация двух текстур. В GLSL встроена функция mix которая принимает два значения на вход и интерполирует их на основе третьего значения. Если третье значение 0.0 то эта функция вернет первый аргумент, если 1.0 то второй. Значение в 0.2 вернет 80% первого входного цвета и 20% второго входного цвета.


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


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


glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture1); glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture2); glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture2"), 1); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0);

Заметьте, что использовали glUniform1i для того, чтобы установить позицию текстурного блока в uniform sampler. Устанавливая их через glUniform1i мы будем уверены, что uniform sampler соотносится с правильным текстурным блоком. В результате вы должны будете получить следующий результат:



Вероятно вы заметили, что текстура перевернута вверх ногами! Это произошло, поскольку OpenGL представляет координату 0.0 по оси Y снизу изображения, но изображения зачастую имеют координату 0.0 сверху по оси Y. Некоторые библиотеки для загрузки изображений, типа имеют настройки для инвертирования Y оси во время загрузки. SOIL такой настройки лишен. У SOIL есть функция SOIL_load_OGL_texture , которая загружает текстуру и генерирует текстуру с флагом SOIL_FLAG_INVERT_Y , который решает нашу проблему. Тем не менее эта функция использует вызовы, недоступные в современной версии OpenGL, поэтому нам придется остановиться на использовании SOIL_load_image и самостоятельной загрузкой текстуры.


Для исправления этой небольшой недоработки у нас есть 2 пути:

  1. Мы можем изменить текстурные координаты в вершинных данных и перевернуть Y ось (вычесть Y координату из 1)
  2. Мы можем изменить вершинный шейдер для переворачивания Y координаты, заменив формулу задачи TexCoord на TexCoord = vec2(texCoord.x, 1.0f - texCoord.y);. .
Приведенные решения - это маленькие хаки, которые позволяют перевернуть изображение. Эти способы работают в большинстве случаев, но результат всегда будет зависеть от формата и типа выбираемой текстуры, так что лучшее решение проблемы - решать ее на этапе загрузки изображения, приводя ее в формат, понятный OpenGL.

Как только вы измените вершинные данные или перевернете Y ось в вершинном шейдере вы получите следующий результат:


Упражнения

Для лучшего усвоения материала прежде чем приступать к следующему уроку взгляните на следующие упражнения.

  1. Добейтесь того, чтобы только вершинный шейдер был перевернут, с помощью изменения фрагментного шейдера. Решение
  2. Поэкспериментируйте с другим методам натягивания текстур, изменяя текстурные координаты в пределах от 0.0f

Теги: Добавить метки

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

Но под короткой фразой «создать трехмерные модели», кроется гораздо более сложный процесс производства. Очень важной составляющей в этапе создания трехмерных моделей является создание материалов и текстур для трехмерных моделей.

Рекламный постер короткометражного фильма «Архитип» Арона Симса, главную роль в котором «играет» персонаж, полностью созданный средствами трехмерной компьютерной графики.
Copyright © 2012 Aaron Sims

Общая информация

Прежде чем трехмерная модель появится на экране кинотеатра, телевизора или монитора, ее должны создать. Как правило, под термином «создать модель», подразумевают поочередное прохождение следующих этапов производства:

  1. Создание образа будущей модели.
  2. Создание геометрической формы трехмерной модели.
  3. Создание набора текстур для модели и настройка материалов.
  4. Настройка скелета и оснастки трехмерной модели.
  5. Анимация модели.

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

Создание образа модели выполняет художник по концептам (concept artist) отталкиваясь от словесного описания режиссера или сценариста. Полученные наброски передаются моделеру (modeling artist) для того, чтобы он создал трехмерную геометрическую форму модели. На этом первые два шага в процессе производства трехмерной модели заканчиваются, но этого еще недостаточно для того, чтобы модель можно было использовать в финальном проекте.

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


Пример трехмерной модели механического солдата будущего. Левая часть - чистая трехмерная модель, правая часть - законченная модель с назначенными материалами.
Copyright 2011 © Mike Jensen
Источник: http://eat3d.com/zbrush_hardsurface

Создание и настройка материалов

Что же такое «материалы», которые так нужны трехмерным моделям? Под этим термином подразумевается описание набора свойств поверхности. То есть материал хранит внутри себя описание того, какими свойствами (параметрами) обладает поверхность. Это такие свойства, как: цвет поверхности, глянцевитость или матовость, наличие или отсутствие рельефа, отражение, прозрачность, свечение и т.п.

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

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


Пример внешнего вида различных материалов, которые используются для назначения трехмерным моделям.
Источник: http://www.vray-materials.de

А вот создают и настраивают материалы обычно в тех же программах, в которых и создается геометрическая форма трехмерной модели. Это такие пакеты, как: Maya, Softimage, 3dsMax, LightWave 3D, Cinema 4D, Blender, Houdini, Modo и многие другие. Как правило все эти программы предоставляют удобный интерфейс для работы с материалами. А сам процесс работы сводится к тому, что художнику нужно подобрать правильное значение того или иного параметра в конкретном материале для того, чтобы он точнее соответствовал нужной поверхности.

Значения параметров материала художник может менять несколькими способами. Первый способ - это цвет . Например, красный плащ, выглядит красным из-за того, что параметр цвета в материале, который назначен геометрии плаща, задан именно красным цветом. Второй способ изменить или задать параметр материала - это цифровое значение . Например, свойство прозрачности в материале может задаваться числом в диапазоне от 0 до 100, где 0 - означает что модель полностью прозрачна, а 100 - означает, что модель не прозрачна. В то же самое время, значение 68 - сделает модель частично прозрачной. И третий способ - это использование текстур . Например, просто присвоив текстуру с изображением ландшафта трехмерной геометрии ландшафта, мы сразу заставим нашу трехмерную модель выглядеть как ландшафт. Именно третий способ настройки материала используется чаше всего при создании сложных типов материалов.


Пример настройки материалав ПО Autodesk Maya.
Источник: http://www.polycount.com/forum/showthread.php?t=94077

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

Текстуры во всех пакетах занимающихся работой с трехмерной графикой делятся на два типа:

  • растровые текстуры;
  • процедурные текстуры.

Растровые текстуры - это обычные растровые изображения, которые можно получить любы способом: фото, видео технику, сканирования изображений, самостоятельное создание в редакторах растровой графики, таких как Adobe Photoshop, Gimp и др.

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

Чаще художники по текстурам используют именно растровые изображения для создания материалов трехмерных моделей. И тут очень важно помнить об одной особенности растра. Она заключается в том, что качество растрового файла ограничено его размером. Чем больше ширина и высота картинки (изображения), тем выше вероятность того, что материал будет отображаться в качестве при любой степени приближения камеры к поверхности модели. Поэтому современные модели обычно используют текстуры размером минимум 2k (2048 пикселя), а в идеале, хотя бы 4k (4096 пикселя) и даже больше.

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

Развертка текстурных координат

Для создания трехмерных моделей существует огромное количество инструментов и каждый пакет для моделирования обладает своим инструментарием для выполнения этой задачи. Есть моделирования на базе сплайнов, моделирование с помощью NURBS-кривых, полигональное моделирование, моделирование Sub-D поверхностями, но обычно в самом конце, модель преображают в полигональную сетку. И одна из причин такого конвертирования кроется в том, что для полигонального каркаса не так сложно можно создать развертку текстурных координат.

Под термином развертка (unwrap) - подразумевается процесс создания для каждого полигона трехмерной модели его отображения (проекции) на плоскости координат. Модели, которые создают, являются геометрическими формами расположенными в трехмерном пространстве, а текстуры - это плоские изображения. Развертка позволяет решить вопрос с тем, как на трехмерную геометрию нанести плоское (двумерное) изображение.

Для создания разверток можно использовать как программы, занимающиеся моделированием объектов, так и специализированные программы, которые выполняют исключительно создание разверток. Примерами программ второго типа являются программы: headus UVLayout, Ultimate Unwrap 3D, UVMapper, Unfold 3D.

Есть несколько требований к развертке текстурных координат:

  1. Размер полигонов на сетке текстурных координат должен соответствовать или приближаться к размеру полигона на трехмерной геометрии. Иначе текстура на поверхности модели может быть искажена (сжата или растянута).
  2. Нужно попытаться как можно эффективнее занят пространство текстурного квадрата (места, где расположена развертка текстурных координат), иначе это приведет к ухудшению качества отображения текстуры.
  3. В большинстве случает запрещены наслоения (наложения) одних текстурных координат с другими. Исключением являются только симметричные, а порой и одинаковые части модели.
  4. Нужно стараться делать как можно меньше швов (мест разделения текстурных координат) на видимых частях модели.

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


Пример развертки текстурных координат (справа) для трехмерной модели пистолета (слева).
Источник: http://www.polycount.com/forum/showthread.php?t=80947

Создание текстур для трехмерной модели

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

Способ первый - это создание текстур в редакторах растровой графики (Adobe Photoshop, Gimp, Painter и т.п.) с нуля или же используя готовые растровые изображения (фотографии, рисунки и т.п.).

Способ второй - создание текстур в специализированных программа для рисования текстур сразу на поверхности трехмерной модели.

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

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


Пример трехмерной модели «дрона» (слева) и набора текстур (справа) созданного в Adobe Photoshop.

Как уже понятно из названия статьи, речь пойдет об использовании текстур в . В прошлом уроке мы создали куб и добавили возможность вращать его вокруг осей координат. Сегодня давайте попробуем наложить текстуры на грани куба и получить некое подобие игральной кости =)

Итак, возьмем за основу проект из предыдущей статьи, и для начала нужно добавить в него изображения, на базе которых впоследствии мы создадим текстуры. Я не стал особо заморачиваться, просто нарисовал по-быстрому в paint’е 6 картинок, по одной для каждой грани куба 😉 Получилось вот так:

Тем, кто как и я, использует Qt Creator теперь необходимо добавить эти файлы в проект. Для этого нужно создать пустой файл ресурсов и прописать в нем пути для всех используемых изображений. Не будем в эту тему углубляться, все-таки статья не об этом 😉

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

void MainScene:: generateTextures () { glGenTextures(6 , textures) ; QImage texture1; texture1.load (":/cubeOne.jpg" ) ; texture1 = QGLWidget:: convertToGLFormat (texture1) ; glBindTexture(GL_TEXTURE_2D, textures[ 0 ] ) ; glTexImage2D(GL_TEXTURE_2D, 0 , 3 , (GLsizei) texture1.width () , (GLsizei) texture1.height () , 0 , GL_RGBA, GL_UNSIGNED_BYTE, texture1.bits () ) ; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) ; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) ;

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

Давайте разбираться, что тут происходит…

Первым делом вызываем функцию glGenTextures() – она генерирует специальные имена для каждой из текстур и помещает их в массив, который мы передаем в качестве одного из аргументов. А первый аргумент – количество текстур, которые нам понадобятся (в данном случае у нас 6 граней, значит передаем в функцию аргумент “6”). Эта функция вызывается только один раз, в самом начале функции generateTextures() .

И, кстати, не забудьте объявить массив в нашем классе MainScene :

GLuint textures[ 6 ] ;

С этим все понятно, переходим дальше. Теперь мы создаем объект класса QImage и загружаем в него наше изображение. Функция glBindTexture делает активной текстуру с номером, соответствующим аргументу функции. В данном случае это текстура для первой грани (textures ). Вызовом этой функции мы как бы показываем , что дальнейшие действия нужно производить именно с той текстурой, которую мы выбрали. Поэтому вызов glTexImage2D() произведет генерацию текстуры, соответствующей номеру textures (напоминаю, в этом массиве у нас хранятся уникальные номера-идентификаторы для каждой из текстур проекта).

Функция glTexImage2D() принимает на вход кучу аргументов, так что давайте рассмотрим каждый из них в отдельности:

  • первый параметр говорит о том, что мы будем работать с 2D текстурой
  • второй параметр – уровень детализации, у нас 0
  • третий – 3 – число цветовых компонент – RGB
  • четвертый, пятый – ширина, высота текстуры, у нас они определяются автоматически
  • пятый – относится к границе текстуры, его просто оставляем нулевым
  • шестой, седьмой – дают информацию о цветах и типе данных исходного изображения
  • и, наконец, седьмой параметр передает сами данные изображения, из которых нужно формировать текстуру

На этом создание текстуры заканчивается, но нужно еще настроить некоторые параметры отображения текстур:

Как вы уже догадались, работать с текстурами мы будем также через массивы. Каждой вершине грани (квадрата) нужно поставить в соответствие 2D координату текстуры, причем нужно обязательно учесть, что текстуры в имеют нормированные координаты, то есть от 0 до 1. В нашем примере текстура квадратная, значит она будет иметь такие координаты:

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

glBindTexture(GL_TEXTURE_2D, textures[ 0 ] ) ; cubeVertexArray[ 0 ] [ 0 ] = 0.0 ; cubeVertexArray[ 0 ] [ 1 ] = 0.0 ; cubeVertexArray[ 0 ] [ 2 ] = 1.0 ; cubeVertexArray[ 1 ] [ 0 ] = 0.0 ; cubeVertexArray[ 1 ] [ 1 ] = 1.0 ; cubeVertexArray[ 1 ] [ 2 ] = 1.0 ; cubeVertexArray[ 2 ] [ 0 ] = 1.0 ; cubeVertexArray[ 2 ] [ 1 ] = 1.0 ; cubeVertexArray[ 2 ] [ 2 ] = 1.0 ; cubeVertexArray[ 3 ] [ 0 ] = 1.0 ; cubeVertexArray[ 3 ] [ 1 ] = 0.0 ; cubeVertexArray[ 3 ] [ 2 ] = 1.0 ; cubeVertexArray[ 4 ] [ 0 ] = 0.0 ; cubeVertexArray[ 4 ] [ 1 ] = 0.0 ; cubeVertexArray[ 4 ] [ 2 ] = 0.0 ; cubeVertexArray[ 5 ] [ 0 ] = 0.0 ; cubeVertexArray[ 5 ] [ 1 ] = 1.0 ; cubeVertexArray[ 5 ] [ 2 ] = 0.0 ; cubeVertexArray[ 6 ] [ 0 ] = 1.0 ; cubeVertexArray[ 6 ] [ 1 ] = 1.0 ; cubeVertexArray[ 6 ] [ 2 ] = 0.0 ; cubeVertexArray[ 7 ] [ 0 ] = 1.0 ; cubeVertexArray[ 7 ] [ 1 ] = 0.0 ; cubeVertexArray[ 7 ] [ 2 ] = 0.0 ; cubeTextureArray[ 0 ] [ 0 ] = 0.0 ; cubeTextureArray[ 0 ] [ 1 ] = 0.0 ; cubeTextureArray[ 1 ] [ 0 ] = 1.0 ; cubeTextureArray[ 1 ] [ 1 ] = 0.0 ; cubeTextureArray[ 2 ] [ 0 ] = 1.0 ; cubeTextureArray[ 2 ] [ 1 ] = 1.0 ; cubeTextureArray[ 3 ] [ 0 ] = 0.0 ; cubeTextureArray[ 3 ] [ 1 ] = 1.0 ; cubeIndexArray[ 0 ] [ 0 ] = 0 ; cubeIndexArray[ 0 ] [ 1 ] = 3 ; cubeIndexArray[ 0 ] [ 2 ] = 2 ; cubeIndexArray[ 0 ] [ 3 ] = 1 ; glVertexPointer(3 , GL_FLOAT, 0 , cubeVertexArray) ; glTexCoordPointer(2 , GL_FLOAT, 0 , cubeTextureArray) ; glDrawElements(GL_QUADS, 4 , GL_UNSIGNED_BYTE, cubeIndexArray) ;

Как видите, все очень похоже на работу с массивами вершин и цветов, только вместо цветов мы задаем координаты текстуры для каждой из вершин квадрата. Повторив эти действия для остальных граней, в итоге мы получим полноценный “текстурный” кубик 😉

Наша задача на сегодня реализована, поэтому на этом я заканчиваю статью, обязательно еще вернемся к теме OpenGL на нашем сайте, так что не проходите мимо 😉

Вот полный проект с примером программы –

Рисунок 1 – Нумерация страниц виртуальной текстуры внутри mip-уровней

Как видно из рисунка 1, очевидно, что удобнее всего виртуальную текстуру будет хранить на жестком диске в виде последовательности страниц 0,1,2,3,4… и так далее. Таким образом, доступ к данным страницы просто вычислить по формуле:

PageFileOffset = PageNumber * PageSize * PageSize * Bpp (2)

где:
PageFileOffset – смещение относительно заголовка файла;
PageNumber – номер страницы;
PageSize – размер страницы;
Bpp – количество байт на пиксель.

Очевидно также, что это не единственный способ хранения виртуальной текстуры. Эффективнее всего хранить страницы в сжатом виде, но это выходит за рамки данной статьи.

4. Конвейер

Весь процесс работы с виртуальной текстурой можно разбить на несколько основных этапов:
1. Определение видимых страниц виртуальной текстуры
2. Анализ пункта 1, формирование списков страниц на загрузку, отсортированных по приоритетам (очередь приоритетов).
3. В соответствии с очередью приоритетов, загрузка виртуальных страниц в оперативную память, формирование списка загруженных страниц (данный этап можно вынести в отдельный поток).
4. Обновление текстурного кэша.
5. Обновление таблицы переадресации.
6. Рендеринг сцены.

4.1 Определение видимых страниц виртуальной текстуры

На данном этапе нам нужно определить номера видимых страниц, ну и, соответственно, номер mip-уровня, к которому данная страница принадлежит.

Я пробовал два способа определения видимых страниц виртуальной текстуры. Первый из них основывался на принципе рендеринга в сцены в текстурном пространстве . То есть мы рисуем сцену в текстуру, используя не мировые координаты вершин, а текстурные. При этом размер одной страницы в текстурном пространстве соответствовал одному пикселу. Данный метод имеет кучу проблем, так как при рендеринге в текстурном пространстве стандартные способы отсечения уже не работают, а в шейдер нужно передавать информацию о плоскостях пирамиды видимости (frustum) и рассчитывать clipping distances. Кроме того, необходим ручной backface-culling. Еще одним существенным недостатком данного метода является необходимость определения, не загораживает ли один объект другой, чтобы не допустить рендеринг невидимых в данный момент объектов. Ну и последний недостаток, который заставил меня выбрать другой метод, это необходимость в, так называемом, консервативном растеризаторе (conservative rasterizer) . Дело в том, что если видно только около 50% процентов страницы, то стандартный GPU растеризатор попросту не будет растеризировать ее в один пиксель, таким образом, мы теряем ценную информацию о нужной странице. Учитывая сложность реализации консервативного растеризатора данный метод в нашем случае оказался неэффективным.

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

На входе вершинного шейдера мы оперируем виртуальными координатами текстуры (virtUV). Этап получения номера страницы состоит из определения текущего mip-уровня (miplevel) и положения страницы относительно текущего mip-уровня (pageOffset):

pageOffset = virtUV * exp2(miplevel) (3)

На выходе в pageOffset будет номер страницы по x и по y относительно текущего mip-уровня. Далее не составит сложности простыми арифметическими операциями преобразовать pageOffset в pageNumber (рисунок 1). Здесь есть небольшая тонкость: дело в том, что в шейдере мы можем закодировать число от 0 до 255 на один канал. При размере виртуальной текстуры, используемой в игре Rage (128к x 128k пикселей), на верхнем mip-уровне pageOffset может превысить число 255. Решить это ограничение можно используя дополнительный канал, в котором кодируются дополнительные восемь бит (по четыре на pageOffset.x и pageOffset.y). Таким образом, максимальное количество страниц, которые мы можем закодировать увеличивается до 4095 по x и столько же по y. В оставшийся четвертый канал мы записываем номер mip-уровня страницы. Еще одним способом снять ограничение является использование float текстур с 32-битными каналами, но в нашем случае это накладно, т.к. в последствии нам нужно будет передавать текстуру в оперативную память для ее анализа.

Теперь, когда мы имеем feedback буфер, мы можем приступить к его анализу.

4.2 Анализ feedback буфера

На данном этапе нам нужно проанализировать полученный feedback буфер и сформировать очередь страниц на загрузку. Для этого нужно прочитать данные в оперативную память из видео памяти. К счастью OpenGL и DirectX позволяют это сделать, правда ценой медленной скорости передачи данных из GPU.

В цикле мы для каждого пикселя feedback буфера декодируем pageOffset и miplevel, преобразуя их в PageNumber (нумерация страниц изображена на рисунке 1). Здесь нам понадобится дополнительная структура данных, так называемая таблица страниц (pageTable). Физически это обычный массив, размер которого равен общему числу страниц (TotalPages). Каждый элемент представляет собой структуру из положения страницы в текстурном кэше (pageX, pageY) и ее mip-уровеня. Также предлагается создать аналогичного размера массив pageInfoTable. Поскольку предложенная организация расположения страниц внутри mip-уровней отлично подходит для реализации Quad-tree, в pageInfoTable мы можем сохранить дополнительную информацию о странице, а именно о ее потомке, а также переменную для хранения флагов (Cached, Needed). Было решено отделить pageTable и pageInfoTable только ради удобства, подробнее об этом будет сказано чуть позже (на пятом этапе, при создании таблицы переадресации).

Таблица 3

Таблица 4.

Подсчёт грансостава

Цена одного деления окуляр-микрометра…….мм

Размеры фракций, мм

Количество делений окуляр-микрометра

Условные единицы

Сумма условных единиц

Примечание

меньше 0,01

Сумма всех зёрен (не менее 300)

Рис. 1. Шапка для построения кривых и описания результатов

Изучение текстурных особенностей алевро-песчаных пород

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

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

Вторичные текстуры возникают в уже сформированной породе.

Первичные текстуры Текстуры поверхности слоя

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

Трещины усыхания – образуются в глинистом или известковом осадке, накопившемся в водной среде при последующем высыхании его на воздухе. Трещины заполнены инородным материалом.

Отпечатки капель дождя и града – округлые углубления с бортиками по периферии.

Следы выделения газов – напоминают отпечатки капель, но диаметр их достигает нескольких см.

Следы животных – отпечатки лап, хвостов и т.п.

Внутрислоевые текстуры

I. Однородные массивные текстуры характеризуются беспорядочным расположением в породе ее составных частей (фото 1).

II. Неоднородная текстура

Горизонтальная слоистость :

1)ритмичная

а)равномерное чередование слойков глин и песчано-алевритовых пород более или менее одинаковой толщины (фото 2)

б)неравномерное чередование. Песчано-алеврито-глинистые слойки имеют разную толщину (фото 3).

2)линейная – четко заметны линии раздела слоев

3)горизонтальная прерывистая слоистая – прерывистое расположение компонентов слоев (фото 4).

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

Волнистая слоистость

1.Пологоволнистая (фото 5,6)

2.Линзовидноволнистая (фото 8)

3.Мульдообразная

4.Перекрестная (фото 10)

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

Косая слоистость (фото 11,12,13) менее распространена, чем горизонтальная. Характеризуется расположением слойков под углом к границам серий слойков. Направление падения косых слойков совпадает с направлением движения среды отложения. Ориентировка слойков может меняться на небольшом отрезке.