1.16. Графика
Графика
Графика в информационных технологиях — это целая система представления, обработки, передачи и интерпретации визуальной информации с использованием вычислительных ресурсов. Она объединяет в себе элементы математики, физики (оптики и света), архитектуры вычислительных систем, теории восприятия и программной инженерии. В практическом смысле графика — это способ передачи данных в форме, доступной для визуального восприятия человеком, с учётом ограничений и возможностей аппаратного обеспечения и программной среды.
Современная компьютерная графика — результат длительной эволюции, начавшейся с простых символьных терминалов и осциллографов 1950–1960-х годов и завершившейся сегодняшними системами, генерирующими фотореалистичные изображения в реальном времени. При этом графика лежит в основе систем визуализации данных (dashboard, GIS), интерфейсов (GUI, VR/AR), проектирования (CAD/CAM), медицинской диагностики (томография), автоматизированного управления (HMI), а также машинного зрения и генеративного ИИ.
Двумерная и трёхмерная графика
Принципиальное деление графики по измерности — на двумерную (2D) и трёхмерную (3D) — отражаетгеометрические свойства изображаемых объектов и различия в архитектуре обработки, в логике работы API, в требованиях к вычислительной мощности и в парадигмах разработки.
Двумерная графика
Двумерная графика оперирует плоскими объектами, позиционируемыми в координатной системе с двумя осями — горизонтальной (X) и вертикальной (Y). В рамках этой модели отсутствует понятие глубины как физической размерности; всё, что происходит «вглубь экрана», имитируется с помощью художественных приёмов: перекрытия, масштабирования, воздушной перспективы, градиентов и теней. Такая имитация, однако, остаётся статичной и не позволяет изменить точку наблюдения без перерисовки всей сцены.
Типичные представители 2D-графики — сканированные изображения, снимки с цифровых камер, интерфейсные элементы (кнопки, иконки, текст), схемы, диаграммы, анимация в стиле традиционного мультипликационного кино. Несмотря на «плоскость», двумерная графика может включать сложную внутреннюю структуру: многослойные композиции, альфа-каналы прозрачности, анимационные кривые, интерактивные зоны. Важно: 2D-графика не обязательно «простая» — современные 2D-движки (например, Godot 2D, PIXI.js, Cairo) поддерживают сложные эффекты постобработки, физику, частицы, шейдерную обработку и даже псевдо-3D-проекции (parallax scrolling, isometric view, faux-3D вроде mode 7 на SNES).
С точки зрения выполнения, 2D-рендеринг часто ближе к прямоугольной компоновке: операции сводятся к наложению спрайтов (изображений с прозрачностью), рисованию примитивов (линии, прямоугольники, кривые Безье), применению трансформаций (аффинных: сдвиг, поворот вокруг Z, масштаб) и композитингу. Это позволяет достигать высокой производительности даже на слабых устройствах — от микроконтроллеров с дисплеями до мобильных телефонов. Многие современные UI-фреймворки (Qt Quick, Flutter, Jetpack Compose, SwiftUI) используют именно 2D-графическую модель как основу, даже если визуально интерфейс создаёт иллюзию объёма.
Трёхмерная графика
Трёхмерная графика вводит третью координатную ось — Z (глубину), что позволяет описывать объекты как объёмные тела, обладающие формой на плоскости и пространственным положением, ориентацией и взаимным расположением в сцене. В 3D-модели отсутствует жёсткая привязка к «виду»: одно и то же описание сцены может быть визуализировано с любой точки наблюдения, с любым углом обзора, под разным освещением — без необходимости хранить или перерисовывать отдельные изображения.
Процесс создания 3D-графики — это конвейер, состоящий из нескольких логических этапов, каждый из которых может быть реализован как на CPU, так и на GPU:
-
Моделирование — этап создания геометрического описания объектов. Обычно это полигональная сетка (mesh): совокупность вершин (vertex), рёбер и граней (чаще всего треугольников), задающих поверхность объекта. Также возможны аналитические представления (NURBS, subdivision surfaces), воксельные модели, signed distance fields (SDF), но в реальном времени доминирует именно полигональный подход из-за его эффективности и аппаратной поддержки.
-
Трансформация и анимация — каждая вершина подвергается последовательности матричных преобразований:
- модельная (перенос из локального пространства объекта в мировое),
- видовая (перенос из мирового пространства в систему координат камеры),
- проекционная (отображение 3D-сцены в 2D-плоскость — перспективное или ортогональное искажение).
Эти операции часто объединяются в одну составную матрицу и применяются в vertex shader.
-
Освещение и шейдинг — расчёт вклада источников света в цвет каждой точки поверхности. Модели освещения могут быть феноменологическими (Phong, Blinn-Phong), физически корректными (PBR — Physically Based Rendering), основанными на трассировке лучей (ray tracing) или на глобальном освещении (radiosity, photon mapping). В реальном времени ключевую роль играют шейдеры — небольшие программы, исполняемые параллельно на GPU:
- vertex shader — обрабатывает вершины,
- fragment (pixel) shader — определяет итоговый цвет каждого фрагмента,
- geometry/tessellation/compute shaders — расширяют возможности для генерации геометрии, детализации, GPGPU.
-
Растеризация и постобработка — завершающая стадия конвейера, на которой происходит:
- разбиение примитивов на фрагменты (пиксельные кандидаты),
- тесты глубины (Z-buffering), прозрачности, шаблона (stencil),
- интерполяция атрибутов (цвет, нормаль, UV-координаты),
- применение текстур (sampling, filtering, mipmapping),
- запись в буфер кадра (framebuffer),
- пост-эффекты (bloom, SSAO, motion blur, tone mapping).
-
Рендеринг — общий термин, охватывающий всё вышеперечисленное. В контексте «оффлайн» (кино, архитектурная визуализация) рендеринг может занимать часы на кадр и использовать методы, такие как path tracing, photon mapping, Metropolis light transport. В «реальном времени» (игры, VR) — он ограничивается ~16 мс на кадр (60 FPS) и вынужден полагаться на аппроксимации и упрощения.
Важно подчеркнуть: 3D-графика не обязательно «реалистична». Стилизованные подходы (cel-shading, NPR — non-photorealistic rendering) намеренно отклоняются от физической достоверности для достижения художественного эффекта: аниме-рендеринг в The Legend of Zelda: Wind Waker, мультяшная графика в Borderlands, карандашный стиль в Okami — всё это 3D, но с сознательным подавлением глубины, теней, текстур в пользу чётких контуров и плоских цветовых зон.
Архитектурные уровни графической обработки
Графическая система современного компьютера — это иерархия уровней абстракции, в которой каждый слой решает конкретную задачу и скрывает сложность нижележащих компонентов.
-
Прикладной уровень — код приложения (игра, редактор, браузер). Здесь определяется логика сцены: какие объекты отображаются, как они анимируются, как реагируют на ввод. Разработчик работает с высокоуровневыми API: Three.js, BabylonJS, Unity, Unreal Engine, Qt3D — или напрямую с низкоуровневыми графическими API.
-
Графический API (Application Programming Interface) — интерфейс между приложением и драйвером GPU. Он стандартизирует вызовы: создание контекста, выделение ресурсов (буферов, текстур), отправка команд отрисовки (draw calls), синхронизация. Основные API:
- OpenGL — кроссплатформенный, устаревший, но всё ещё используемый (особенно в embedded и legacy-системах);
- Vulkan — современный, низкоуровневый, явный, требует ручного управления памятью и синхронизацией, но даёт максимальный контроль и производительность;
- DirectX 12 — эквивалент Vulkan для Windows и Xbox, тесно интегрирован с экосистемой Microsoft;
- Metal — проприетарный API для устройств Apple (iOS, macOS), оптимизированный под их SoC;
- WebGL / WebGPU — API для браузерного рендеринга; WebGL основан на OpenGL ES, WebGPU — на Vulkan/Metal/DX12 и представляет будущее веб-графики.
-
Драйвер устройства — ПО, предоставляемое производителем GPU (NVIDIA, AMD, Intel). Он переводит вызовы API в команды, понятные конкретному чипу, управляет ресурсами памяти, планирует выполнение, обеспечивает изоляцию и безопасность. Драйвер — «мост» между стандартизированным интерфейсом и уникальной архитектурой железа.
-
Графический процессор (GPU) — специализированное вычислительное устройство, построенное по принципу massively parallel processing. Современные GPU содержат тысячи ядер (CUDA cores, Stream Processors), кэши, высокоскоростную память (GDDR6X, HBM), подсистемы декодирования/кодирования видео, RT-ядра (для ускорения ray tracing), тензорные ядра (для ИИ-ускорения). GPU не «рисует» напрямую — он выполняет программы (шейдеры), читает данные (вершины, текстуры), записывает результат (в цветовой и глубинный буферы).
-
Дисплейная подсистема — компоненты, отвечающие за вывод изображения: видеовыход (HDMI, DisplayPort), контроллер дисплея, сам дисплей (LCD, OLED, CRT — в историческом контексте). Здесь происходят:
- вертикальная синхронизация (vsync) — согласование частоты обновления кадров и дисплея,
- двойная/тройная буферизация — предотвращение tearing’а,
- HDR-обработка, цветокоррекция, масштабирование.
Время и интерактивность
Особое значение в графике имеет временной аспект. В статической графике (изображения, PDF, печать) результат фиксирован. В динамической графике (анимация, интерфейсы, игры) изображение пересчитывается многократно в секунду. Это вводит понятие кадра (frame) — единицы визуального обновления, и частоты кадров (FPS — frames per second), определяющей плавность восприятия.
Низкая частота (< 30 FPS) воспринимается как «рывки»; 60 FPS — стандарт для большинства приложений; 90–120+ FPS — требование для VR (во избежание кинетоза). Однако важно не только количество кадров, но и их стабильность: резкие просадки (stuttering) ощущаются сильнее, чем равномерное снижение FPS.
Для достижения интерактивности критична сквозная задержка (end-to-end latency) — время от ввода (нажатие клавиши, движение мыши) до отображения результата. В шутерах, авиасимуляторах, музыкальных играх эта задержка должна быть минимальной (желательно < 20 мс), что требует быстрого рендеринга и оптимизированных систем ввода, предсказания движения (prediction), асинхронного отображения (ASW, ATW).
Современные тенденции и перспективы
Несмотря на зрелость технологии, графика продолжает развиваться. Основные направления:
-
Гибридный рендеринг — комбинация растеризации (быстро) и трассировки лучей (реалистично). RTX-ядра в GPU позволяют выполнять ray tracing в реальном времени частично: для теней, отражений, глобального освещения — при этом основная геометрия всё ещё растеризуется.
-
Программируемая графика — рост роли compute shaders, где GPU используется для отрисовки, для физики, ИИ, обработки данных. Это стирает границы между графикой и GPGPU.
-
Виртуализация и облачная графика — рендеринг происходит на удалённом сервере (Google Stadia, NVIDIA GeForce NOW), клиент получает видеопоток. Требует низкой задержки сети и адаптивного кодека.
-
Нейрогенеративная графика — использование нейросетей для суперразрешения (DLSS, FSR), интерполяции кадров (Frame Generation), автоматической генерации текстур, моделей, анимаций. Это не заменяет традиционную графику, но дополняет её новыми инструментами.
-
Доступность и инклюзивность — развитие графики не только для «мощных десктопов», но и для устройств с ограниченными ресурсами: веб (WebGPU), мобильные (Vulkan Mobile), embedded (OpenGL ES, Vulkan SC для safety-critical систем).
Графический конвейер
Графический конвейер — это абстрактная модель, описывающая поток данных и управления в системе визуализации. Он существует как на уровне спецификаций API (например, pipeline stages в Vulkan), так и на уровне аппаратной архитектуры GPU (fixed-function units и программируемые блоки). Конвейер не является физической «трубой», по которой движутся пиксели — это скорее логическая последовательность этапов, каждый из которых может выполняться параллельно, конвейерно, с перекрытием, при условии соблюдения зависимостей.
Современные конвейеры можно разделить на две большие категории:
- Графический конвейер реального времени — оптимизированный под скорость, с доминированием растеризации (rasterization pipeline). Используется в играх, интерфейсах, интерактивных приложениях.
- Оффлайн-конвейер — оптимизированный под физическую точность, с доминированием трассировки лучей и её обобщений (ray tracing pipeline, path tracing). Используется в кино, архитектурной визуализации, симуляциях.
Ниже рассматривается растеризационный конвейер, поскольку он лежит в основе подавляющего большинства интерактивных систем (включая браузеры через WebGL и мобильные приложения через Metal/Vulkan). При этом мы будем отмечать, как этапы меняются или заменяются в гибридных и ray tracing-подходах.
1. Определение сцены и подготовка данных
Всё начинается в приложении. Разработчик (или движок) формирует описание сцены — не изображение, а структурированный набор объектов и параметров:
- Геометрия — вершины, индексы, нормали, UV-координаты. Хранится в буферах вершин (vertex buffers) и индексных буферах (index buffers). Вершины могут включать дополнительные атрибуты: цвет, тангенс-базис (для normal mapping), skinning weights (для анимации).
- Материалы — описания того, как объект взаимодействует со светом: базовый цвет, шероховатость, металличность, эмиссия, прозрачность. В PBR-подходе эти параметры соответствуют физическим свойствам поверхности.
- Текстуры — растровые данные, накладываемые на геометрию: diffuse/albedo (основной цвет), normal (рельеф), roughness/metallic (PBR-параметры), height/displacement (высота), ambient occlusion (затенённость складок).
- Свет — источники: точечные, направленные, прожекторы, area lights. В реальном времени часто используются proxy-объекты (light probes, reflection probes) для имитации сложного освещения.
- Камера — параметры наблюдения: положение, направление, угол обзора (FOV), ближняя и дальняя плоскости отсечения (near/far clipping planes), соотношение сторон.
Эти данные загружаются в память GPU через буферы и текстурные объекты. Важно: передача данных между CPU и GPU — дорогая операция с точки зрения задержки. Поэтому современные API (Vulkan, DX12) требуют явного управления: выделение памяти, staging-буферы, синхронизация через барьеры и семафоры — чтобы избежать простоев и конфликтов.
2. Вершинная обработка (Vertex Processing)
На этом этапе обрабатываются вершины геометрических примитивов (обычно треугольников). Каждая вершина поступает в vertex shader — программируемый блок, исполняемый параллельно для всех вершин в draw call.
Основные задачи vertex shader:
- Применение модельно-видовой трансформации: перенос вершины из локального пространства объекта (
object space) в пространство камеры (view space). Это достигается умножением вектора положения на матрицуModelView. - Применение проекционной трансформации: преобразование координат из
view spaceвclip space— однородное 4D-пространство, в котором дальнейшая обработка (отсечение, перспективное деление) становится унифицированной. Результат —gl_Position(в OpenGL) илиSV_Position(в HLSL). - Передача интерполируемых атрибутов во фрагментный шейдер: нормали, UV-координаты, цвет вершины. Эти значения будут плавно изменяться между вершинами при растеризации.
Важно: vertex shader работает на одну вершину, без знания о соседних. Это обеспечивает параллелизм, но ограничивает возможности: нельзя, например, сгладить нормали без предварительного расчёта на CPU или в geometry shader.
В некоторых сценариях используется tessellation shader (Hull + Domain в DX11, Tessellation Control + Evaluation в OpenGL) — этап, вставляемый после vertex shader, позволяющий динамически детализировать геометрию на основе уровня детализации (LOD) или кривизны поверхности. Например, плоская сетка может быть разбита на тысячи мелких треугольников для изображения каменистой поверхности — без увеличения объёма данных, передаваемых с CPU.
3. Преобразование примитивов и сборка (Primitive Assembly & Clipping)
После vertex shader полученные вершины группируются в примитивы (точки, линии, треугольники). Затем выполняется отсечение (clipping) — удаление частей примитивов, лежащих вне видимой области (frustum). Frustum задаётся шестью плоскостями (left, right, top, bottom, near, far); всё, что находится за ними, отбрасывается.
Отсечение происходит в clip space, до перспективного деления. Если примитив частично выходит за пределы frustum, он разрезается, и образуются новые вершины на пересечении с плоскостями. Этот этап, как правило, реализован в фиксированной логике GPU (fixed-function hardware), не программируется пользователем.
После отсечения проводится перспективное деление (perspective divide): координаты (x, y, z, w) преобразуются в (x/w, y/w, z/w, 1), переходя из однородных в нормализованные координаты устройства (NDC — Normalized Device Coordinates), где X и Y лежат в диапазоне [-1, +1], а Z — в [0, 1] (в DirectX) или [-1, +1] (в OpenGL/Vulkan).
4. Преобразование в экранные координаты (Viewport Transform)
NDC-координаты преобразуются в координаты экрана — целочисленные позиции пикселей в буфере кадра. Это делается с помощью viewport transform: масштабирование и смещение, чтобы уместить изображение в заданную прямоугольную область (viewport) на экране. Z-координата сохраняется для depth buffer.
На этом этапе также может выполняться back-face culling — отбрасывание треугольников, обращённых «обратной стороной» к камере (определение по порядку обхода вершин — clockwise/counterclockwise). Это простая, но эффективная оптимизация: в закрытых объектах внутренние грани никогда не видны.
5. Растеризация (Rasterization)
Ключевой этап конвейера — преобразование геометрических примитивов (в основном треугольников) в фрагменты — кандидаты на пиксели. Растеризатор определяет, какие пиксели покрываются треугольником, и для каждого такого пикселя генерирует фрагмент (fragment), содержащий:
- Экранные координаты (x, y),
- Интерполированное значение Z (для depth test),
- Интерполированные атрибуты из vertex shader (нормаль, UV, цвет и т.д.).
Интерполяция — перспективно-корректная: чем дальше точка, тем сильнее «растягивается» интерполяция, что предотвращает искажение текстур и освещения. Это требует деления на w при интерполяции — механизм, заложенный в аппаратуру GPU.
Растеризация — высокопараллельная операция: миллионы треугольников могут обрабатываться независимо. Современные GPU используют tile-based rendering (в мобильных чипах: PowerVR, Mali, Adreno), где экран делится на маленькие тайлы (например, 32×32 пикселя), и растеризация выполняется по тайлам, чтобы минимизировать обращения к памяти.
6. Фрагментная обработка (Fragment Processing)
Каждый фрагмент поступает во фрагментный шейдер (fragment shader / pixel shader). Это наиболее вычислительно ёмкий этап: для FullHD-кадра может выполняться более двух миллионов вызовов шейдера за 16 мс.
Задачи фрагментного шейдера:
- Выборка текстур (texture sampling) — чтение значений из текстурных буферов по UV-координатам. Здесь применяются фильтрация (linear, anisotropic), mipmapping (автоматический выбор уровня детализации текстуры в зависимости от расстояния), wrapping modes (repeat, clamp).
- Расчёт освещения — на основе полученных нормалей, параметров материала и данных о свете. В простейшем случае — диффузное (Lambert) и зеркальное (Phong) отражение; в сложных — full PBR с image-based lighting (IBL), parallax mapping, subsurface scattering.
- Обработка прозрачности — смешивание цвета фрагмента с уже записанным в буфер (blending). Требует сортировки прозрачных объектов по глубине (от дальних к ближним), что нарушает параллелизм.
- Произвольная логика — генерация эффектов: волны воды, искажение (refraction), пост-обработка на уровне объекта (outlines, toon shading), отбрасывание фрагмента (
discard), например, для альфа-тестирования (листья, решётки).
Фрагментный шейдер работает независимо для каждого фрагмента, без доступа к соседним — это гарантирует параллелизм, но затрудняет реализацию эффектов, требующих локального контекста (например, edge detection). Такие задачи выносятся в пост-обработку или compute shaders.
Перед записью результата фрагмент проходит серию тестов:
- Depth test — сравнение Z-значения фрагмента с текущим значением в depth buffer. Если фрагмент дальше, он отбрасывается (раннее отбрасывание — early-Z). Это критически важно для производительности: позволяет не запускать фрагментный шейдер для невидимых пикселей (при условии, что шейдер не меняет глубину и не использует discard).
- Stencil test — проверка по маске (stencil buffer), используемой для сложных эффектов: теней, зеркал, порталов, выделения объектов.
- Scissor test, alpha test — дополнительные условия отсечения.
7. Запись в буфер кадра (Framebuffer Operations)
Если фрагмент прошёл все тесты, его цвет записывается в буфер кадра (framebuffer). Framebuffer — это совокупность буферов:
- Color buffer — хранит итоговый цвет (обычно RGBA16F или RGBA8),
- Depth buffer — хранит Z-значения (обычно 24 или 32 бита),
- Stencil buffer — 8-битная маска.
Запись может включать:
- Blending — смешивание нового цвета со старым (например,
src * alpha + dst * (1 - alpha)), - Logic operations — побитовые операции (редко используются),
- Dithering — добавление шума для уменьшения полос (banding) при 8-битной цветопередаче.
Современные рендереры редко рисуют сразу в «экран». Вместо этого используется рендер в текстуру (render-to-texture):
- сначала сцена рендерится в offscreen framebuffer (например, для теней — в depth-only buffer),
- затем результат используется как текстура в основном проходе (shadow mapping),
- многократные проходы (multipass rendering) позволяют реализовать deferred shading, screen-space reflections, SSR, SSAO.
8. Постобработка и вывод
После завершения всех геометрических проходов выполняется постобработка (post-processing): серия эффектов, применяемых к уже сформированному изображению как к текстуре. Типичные этапы:
- Tone mapping — преобразование HDR-значений в LDR для дисплея (ACES, Reinhard),
- Bloom — имитация рассеяния света в объективе,
- Color grading — коррекция цвета по 3D-таблице (LUT),
- Anti-aliasing — сглаживание: MSAA (на этапе растеризации), FXAA/SMAA (пост-обработка), TAA (temporal, с учётом предыдущих кадров),
- Motion blur, depth of field — имитация оптики.
Затем изображение передаётся в систему отображения:
- При включённой вертикальной синхронизации (vsync) кадр ожидает начала нового цикла развёртки дисплея.
- Используется двойная буферизация (front/back buffer): пока один буфер отображается, следующий рендерится. При тройной — добавляется промежуточный, чтобы избежать ожидания.
- На мобильных устройствах и VR применяется асинхронная смена буферов (Adaptive Sync, G-Sync, FreeSync) — дисплей подстраивает частоту обновления под FPS приложения, устраняя tearing и stuttering.
Отклонения от классического конвейера
Классический растеризационный конвейер — не единственный путь. Рассмотрим альтернативы:
Compute-based rendering
Вместо фиксированного конвейера приложение использует compute shaders — программы общего назначения, выполняемые на GPU без привязки к графическим этапам. В них можно реализовать:
- Полностью кастомный рендерер (например, software rasterizer на GPU),
- Гибридные подходы: растеризация основной геометрии + ray tracing для отражений,
- GPGPU-ускоренные эффекты: частицы, ткань, волосы, физика жидкости.
Vulkan и DX12 предоставляют тесную интеграцию compute и graphics queues, позволяя переключаться между ними в рамках одного кадра.
Трассировка лучей (Ray Tracing)
В отличие от растеризации, где лучи «идут от камеры к объектам» только косвенно (через Z-buffer), в ray tracing каждый пиксель порождает луч, который проходит через сцену, сталкивается с объектами, отражается, преломляется — имитируя реальные законы оптики.
Этапы ray tracing pipeline:
- Генерация первичных лучей (по одному на пиксель или сэмпл),
- Пересечение лучей с геометрией (через BVH — bounding volume hierarchy),
- Для каждой точки пересечения — расчёт цвета (освещение, материал),
- Генерация вторичных лучей (отражение, преломление, тень),
- Рекурсивное повторение до предела глубины или порога энергии.
Проблема: вычислительная сложность. Даже с аппаратным ускорением (RT-ядра) полный path tracing в реальном времени невозможен. Поэтому применяется гибридный рендеринг:
- Основная видимость — растеризация,
- Отражения, тени, глобальное освещение — ray tracing,
- Шум от недостаточного числа сэмплов — подавляется denoising-нейросетями (OptiX, XeSS).
Deferred Rendering
Альтернативная организация конвейера, где сначала в G-buffer записываются геометрические и материал-параметры (позиция, нормаль, albedo, roughness...), а освещение рассчитывается отдельно, уже в screen space. Это позволяет использовать сотни источников света без повторного рендеринга геометрии — но требует больших объёмов памяти и плохо совместимо с прозрачностью.
Текстуры и материалы
Геометрия определяет форму объекта. Текстуры и материалы определяют его визуальные свойства: цвет, рельеф, блеск, прозрачность, износ, возраст, происхождение. Благодаря им один и тот же куб может быть бетонной стеной, деревянным ящиком, зеркальной панелью или старинной книгой — без изменения самой сетки.
Термин «текстура» в компьютерной графике исторически возник как аналог тканевой текстуры — повторяющегося узора, накладываемого на поверхность. Сегодня же под текстурой понимается любой растровый ресурс, используемый в шейдере для модуляции параметров отрисовки. Это может быть изображение, но также — карта нормалей, карта высот, карта шероховатости, таблица поиска цвета (LUT), маска анимации, шум Перлина в сжатом виде и даже данные для вычислений (например, таблица интегралов для IBL).
Семантические роли текстур
Не все текстуры «красивые». Некоторые полностью невидимы пользователю, но критичны для физики отображения. Условно их можно разделить на группы по назначению:
-
Цветовые текстуры — определяют базовый визуальный облик.
- Albedo / Base Color — чистый цвет поверхности без теней и освещения. В PBR-подходе этот канал не должен содержать теней, бликов или ambient occlusion — только «фотометрически нейтральная» информация.
- Diffuse — устаревший термин из non-PBR-рендеринга; часто включал в себя и влияние окружающего света, что затрудняло повторное освещение.
- Detail maps — мелкомасштабные текстуры, накладываемые поверх основных для увеличения разрешения (например, царапины на металле при близком рассмотрении).
-
Геометрические текстуры — имитируют или изменяют форму поверхности.
- Normal map — хранит направления нормалей в касательном пространстве (tangent space), позволяя создавать иллюзию рельефа без увеличения числа полигонов. Каждый пиксель кодирует вектор (X, Y, Z), преобразуемый в пространство камеры и используемый при расчёте освещения.
- Height map / Displacement map — одно- или многоканальная карта, задающая смещение вершин (в tessellation или геометрических шейдерах) или фрагментов (в parallax mapping). Height map — грубая аппроксимация, displacement — реальное изменение геометрии.
- Ambient Occlusion (AO) map — премаппинг затемнённых участков (стыки, углубления), где мало отражённого света. Используется для усиления ощущения глубины, особенно при слабом освещении. В современных движках часто заменяется на screen-space AO (SSAO, HBAO+), но pre-baked AO остаётся важен для статичных сцен.
-
Физические параметры — ключевые для PBR.
- Roughness map — степень шероховатости поверхности (0 — идеально гладкая, 1 — матовая). Определяет форму бликов и рассеяние отражённого света.
- Metallic map — бинарная или градиентная карта, указывающая, является ли участок металлом (1) или диэлектриком (0). В PBR металлы не имеют диффузного отражения — весь свет либо отражается, либо поглощается.
- Specular — устаревший аналог roughness+metallic в non-PBR; задавал интенсивность и цвет зеркального отражения напрямую.
-
Управляющие текстуры — не несут визуальной информации, но управляют логикой отрисовки.
- Alpha map — канал прозрачности. Может использоваться для alpha testing (discard фрагментов с alpha < порога), alpha blending (полупрозрачность) или alpha-to-coverage (антиалиасинг прозрачных краёв).
- Mask maps — объединяют несколько параметров в один канал (например, R — metallic, G — roughness, B — AO) для экономии памяти и количества сэмплов.
- Vertex color / Lightmap — запечённое освещение, нанесённое непосредственно на UV-развёртку. Используется в статичных сценах (архитектура, уровни игр) для экономии ресурсов.
Важно: ни одна из этих карт не существует изолированно. Их комбинация образует материал — логический объект, связывающий набор текстур, параметры шейдера, логику смешивания и реакцию на освещение.
Материал как программируемая сущность
В ранних системах (OpenGL 1.x, DirectX 7) материал задавался фиксированным набором параметров: diffuse color, specular color, shininess, emissive. Это был material state — глобальное состояние конвейера, изменяемое вызовами вроде glMaterialfv.
С переходом к программируемым шейдерам (начиная с DirectX 8 / OpenGL 2.0) понятие материала стало контекстно-зависимым. Материал — это интерфейс между данными и шейдером:
- Он определяет, какие текстуры должны быть привязаны к каким юнитам (texture units),
- Какие uniform-параметры передать (например,
float roughnessMultiplier), - Какой шейдерный вариант использовать (например, «металл», «стекло», «кожа» — с разной логикой в fragment shader),
- Как обрабатывать специальные случаи: параллакс, subsurface scattering, emissive glow.
Современные движки (Unreal Engine, Unity HDRP, Filament) используют material graphs или shader variants — системы, позволяющие визуально или декларативно собирать материалы, автоматически генерируя шейдерный код под конкретный набор параметров. Это позволяет:
- Избегать ветвлений в шейдере (if/else), снижающих производительность,
- Компилировать только нужные комбинации (например, материал без emissive не включает соответствующий код),
- Обеспечивать единообразие на всём проекте.
Материал также несёт семантическую нагрузку для инструментов: система освещения может автоматически применять IBL только к PBR-материалам, а система постобработки — исключать emissive-поверхности из tone mapping.
Текстурные координаты и развёртка
Текстура — двумерный массив данных. Чтобы наложить его на трёхмерную поверхность, требуется отображение — соответствие между точками поверхности и точками текстуры. Это достигается с помощью UV-координат: двухмерных значений (U, V), приписанных каждой вершине, интерполируемых при растеризации.
UV-координаты нормализованы: (0,0) — нижний левый угол текстуры, (1,1) — верхний правый (в OpenGL; в DirectX — (0,0) вверху, что требует вертикального флипа при загрузке). Значения вне [0,1] обрабатываются в соответствии с режимом наложения (wrapping mode):
REPEAT— текстура повторяется (для бесшовных материалов: кирпич, трава),CLAMP_TO_EDGE— крайние пиксели растягиваются (для некафельных изображений: лица, интерфейс),MIRROR_REPEAT— зеркальное повторение (редко, для специфических эффектов).
Качество наложения зависит от UV-развёртки — процесса «разглаживания» 3D-поверхности в 2D-плоскость. Плохая развёртка (с перекрытиями, искажениями, разрывами) приводит к артефактам: растяжению текстур, видимым швам, несоответствию масштаба. В профессиональном 3D-моделировании этому уделяется столько же внимания, сколько самой геометрии.
Современные подходы включают:
- UDIM — система, позволяющая использовать несколько текстурных плиток (tiles) для одной модели, нумеруемых по схеме U+1000×V. Это позволяет достичь высокого разрешения (8K+ на объект) без ограничений GPU на размер текстуры (макс. 16K в 2025 г.).
- Triplanar mapping — наложение текстур по трём осям (X, Y, Z) с весами, зависящими от нормали. Устраняет необходимость UV-координат для простых объёмных объектов (скалы, террейн).
- World-space UVs — координаты зависят от мирового положения, а не от развёртки. Применяется для procedural текстуризации (шум, градиенты).
Сжатие и хранение текстур
Текстуры — основной объём видеопамяти. Изображение 4K (3840×2160) в формате RGBA8 занимает ~63 МБ. При этом в сцене может быть сотни таких текстур.
Для экономии применяется аппаратное сжатие текстур — форматы, декодируемые GPU «на лету» при выборке:
- S3TC / DXT (BC1–BC7) — стандарт де-факто на PC и консолях. BC1 — 4 бита/пиксель (RGB + 1-битная альфа), BC7 — 8 бит/пиксель (высококачественное RGBA). BC4/5 — для одно- и двухканальных данных (roughness, normal.xy).
- ETC2 / EAC — стандарт для OpenGL ES и мобильных устройств (Android), требует меньших ресурсов декодера.
- ASTC — адаптивное сжатие, поддерживает произвольные размеры блоков (от 4×4 до 12×12), балансируя качество и объём. Широко используется в мобильной графике и WebGPU.
- Basis Universal / KTX2 — транспортные форматы, сжимающие текстуру один раз, а затем транскодирующие в BCn/ETC2/ASTC на целевом устройстве. Важны для веба и кроссплатформенных приложений.
Сжатие — не PNG или JPEG. Оно потеряющее, но оптимизировано под визуальное восприятие и равномерную ошибку. Особенно критично для normal map: даже небольшие искажения цвета приводят к «пузырькам» и шуму на поверхности.
Mipmapping
Когда текстурированный объект удаляется от камеры, один пиксель экрана может покрывать сотни пикселей текстуры. Прямая выборка (nearest/linear) вызывает алиасинг — мерцание, шум, муар.
Mipmapping решает это, заранее создавая иерархию уменьшенных копий текстуры (mip levels): 1024×1024 → 512×512 → 256×256 → … → 1×1. При рендеринге GPU автоматически выбирает уровень, соответствующий экранной площади одного текселя (texture element), и применяет фильтрацию между уровнями (trilinear filtering).
Ключевые свойства:
- Уменьшает шум и повышает стабильность изображения,
- Улучшает кэширование текстур: близкие пиксели читают данные из одного блока памяти,
- Требует ~33% дополнительного объёма (сумма ряда 1 + 1/4 + 1/16 + … = 4/3),
- Может использоваться селективно: например, отключать для текстур интерфейса (где важна чёткость), или использовать только чётные уровни для экономии.
Современные API позволяют генерировать mipmaps на GPU (автоматически при загрузке) или управлять ими вручную — например, для streaming-систем, где уровни подгружаются по мере надобности.
Атласы и массивы текстур
Для снижения числа переключений текстур (дорогая операция — state change) используются объединения:
- Texture atlas — одна большая текстура, содержащая множество мелких (иконки, спрайты, GUI-элементы). Требует аккуратной UV-развёртки и padding между элементами во избежание «утечки» соседних пикселей при фильтрации.
- Array texture — стек одинаковых по размеру текстур, доступных по индексу в шейдере (
sampler2DArray). В отличие от атласа, не страдает от артефактов фильтрации на границах, поддерживает mipmapping по элементам. Используется для terrain blending, skinning в 2D-анимации, material layering. - Sparse textures / Virtual texturing — технология, при которой только видимые части огромной текстуры (например, 128K×128K) подгружаются в память. Применяется в симуляторах, open-world играх (id Tech 5, Unreal Engine 5 Nanite+Virtual Shadow Maps).
Unreal Engine 5 ввела Virtual Texture Streaming, где текстуры разбиваются на страницы (pages), и рендерер динамически определяет, какие страницы нужны для текущего кадра — на основе расстояния, угла, важности объекта. Это позволяет использовать текстуры общим объёмом в десятки гигабайт даже на консолях.
Анимация и динамические текстуры
Не все текстуры статичны. Анимированные текстуры — последовательность кадров, переключаемых по времени или событию:
- Sprite-листы (spritesheets) — решётка кадров анимации, переключаемых через смещение UV,
- Texture arrays как анимационные слои — индекс кадра передаётся как uniform,
- Render-to-texture — динамическая генерация: отражения в «зеркале», проекции (light cookies), UI-рендеринг в 3D-пространство (например, экраны в киберпанке),
- GPU-driven animation — изменение текстуры внутри compute shader (например, волна на воде, тепловое искажение).
Особый класс — procedural текстуры. Они генерируются по формуле или алгоритму в шейдере: шум Перлина, вороной-ячейки, градиенты, фракталы. Преимущества:
- Бесконечное разрешение (без потери качества при приближении),
- Минимальный объём памяти,
- Параметрическое управление (например, «сделать камень более треснувшим» — изменить один слайдер).
Недостатки: вычислительная нагрузка, сложность контроля, невозможность тонкой художественной правки. Часто используется как база, дополняемая hand-painted деталями.
Проблемы и ограничения
Несмотря на зрелость технологии, текстуризация сталкивается с системными ограничениями:
- Лимиты аппаратуры: максимальный размер текстуры (16384×16384 на большинстве GPU 2025 г.), число одновременно привязанных текстур (16–128 в зависимости от API и шейдера), пропускная способность памяти (memory bandwidth) — часто узкое место при использовании высокочастотных карт (normal, roughness).
- Синхронизация CPU–GPU: загрузка текстуры — асинхронная операция, но может вызывать stall, если шейдер пытается использовать её до завершения передачи.
- Кроссплатформенность: BCn не поддерживаются на iOS (там PVRTC/ASTC), ETC2 — на старых Adreno. Требуется runtime feature detection и fallback-форматы.
- Лицензирование и инструменты: многие advanced-форматы (BC6H/7) требуют лицензирования от Khronos или Microsoft; генерация качественных mipmaps и normal maps требует специализированных инструментов (Substance 3D, xNormal, NVIDIA Texture Tools).