Ask me anything
Ithy Logo
Sign in to save

Эффективная окраска стен в Unity с использованием текстурного атласа

Руководство по реализации независимой окраски сторон стен в рантайме для вашего игрового редактора уровня

wall-painting-unity-6edhhwrb

Ключевые моменты

  • Оптимизация производительности: Использование текстурного атласа снижает количество draw calls, что критично для мобильных устройств и сложных сцен, позволяя эффективно управлять текстурами без потери FPS.
  • Независимая окраска сторон: С помощью правильной UV-раскладки в Blender и скриптов в Unity, каждая сторона стены может быть окрашена отдельно, обеспечивая гибкость, как в The Sims.
  • Простота реализации: Система на основе индексов текстур (0-7) и кликов мыши позволяет игрокам легко выбирать и применять текстуры, с минимальными изменениями в коде для поддержки рантайм-редактора.

Подготовка 3D-модели стены в Blender

Перед тем как перейти к реализации в Unity, важно правильно подготовить модель стены в Blender. Это обеспечит, что каждая сторона стены может быть окрашена независимо без лишних затрат на производительность. Стена, как простая лоуполи-модель, должна иметь отдельные UV-острова для каждой грани, чтобы текстуры могли применяться selectively.

В Blender создайте базовую геометрию стены. Для достижения независимой окраски сторон, разделите модель на подмодели или используйте UV-раскладку, где каждая сторона (внутренняя и внешняя) имеет свой собственный UV-пространство. Это можно сделать с помощью инструментов UV Editor:

  • Выделите грани стены и используйте Unwrap (Ctrl+E) для создания отдельных UV-островов. Например, назначьте UV-координаты так, чтобы внутренняя сторона занимала один диапазон, а внешняя — другой.
  • Поскольку текстуры будут храниться в атласе 8x8 (с индексами от 0 до 7), настройте UV-координаты в диапазоне от 0 до 1 для каждой стороны, но с возможностью смещения для выбора конкретной текстуры из атласа.

Экспортируйте модель в FBX или OBJ формат, чтобы импортировать её в Unity. Убедитесь, что UV-каналы сохранены. Это позволит в Unity манипулировать UV-координатами через код для изменения текстуры на лету.

Преимущества использования UV-островов

Разделение UV на острова предотвращает искажения текстур и упрощает управление. Например, если внутренняя сторона стены имеет UV от (0,0) до (0.5,1), а внешняя — от (0.5,0) до (1,1), то в атласе вы можете назначать разные секции текстуры без изменения геометрии модели.

Пример UV-раскладки в атласе

Изображение: Пример UV-карты для текстурного атласа, показывающее разделение на секции. Это помогает визуализировать, как индексы текстур (0-7) отображаются на модель.


Настройка текстурного атласа в Unity

Текстовый атлас — это ключ к оптимизации, так как он объединяет все текстуры в один файл, снижая количество draw calls. В вашем случае, с 8 текстурами в сетке, атлас можно создать вручную или с помощью инструментов Unity.

Создайте текстурный атлас в Photoshop или TexturePacker, разместив текстуры в 2x4 или 4x2 сетку (в зависимости от размера). Импортируйте атлас в Unity как Texture2D. Затем назначьте его материалу, который будет использоваться для стен.

Для управления текстурами через код используйте свойства материала, такие как mainTextureOffset и mainTextureScale, чтобы смещать UV-координаты и выбирать нужную секцию атласа. Поскольку текстуры имеют индексы от 0 до 7, рассчитайте UV-смещение на основе индекса:

  • Если атлас разделен на 8 секций (например, 2 строки и 4 столбца), то для индекса i UV-offset будет (i % 4 / 4, Math.Floor(i / 4) / 2) для нормализации в диапазоне [0,1].

Код для применения текстуры

В скрипте C# реализуйте систему, где игрок выбирает текстуру по индексу, а затем кликает на стену. Используйте Raycast для определения, какая сторона стены была задета. Затем измените UV-координаты или материал для этой грани.

using UnityEngine;

public class WallPainter : MonoBehaviour
{
    public Texture2D textureAtlas; // Атлас текстур
    public int selectedTextureIndex = 0; // Индекс выбранной текстуры (0-7)

    private Material wallMaterial; // Материал стены

    void Start()
    {
        // Присвойте материал объекту стены
        Renderer renderer = GetComponent<Renderer>();
        if (renderer != null)
        {
            wallMaterial = renderer.material;
            wallMaterial.mainTexture = textureAtlas; // Назначьте атлас текстур
        }
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0)) // Клик левой кнопкой мыши
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                // Проверьте, что hit.collider — это стена
                if (hit.collider.gameObject == gameObject) // Или используйте тег/компонент для идентификации
                {
                    PaintWallSide(hit, selectedTextureIndex);
                }
            }
        }
    }

    public void SetSelectedTexture(int index)
    {
        if (index >= 0 && index <= 7)
        {
            selectedTextureIndex = index;
        }
    }

    private void PaintWallSide(RaycastHit hit, int textureIndex)
    {
        // Рассчитайте UV-смещение на основе индекса
        float atlasWidth = 4.0f; // Ширина атласа в секциях (4 столбца)
        float atlasHeight = 2.0f; // Высота атласа в секциях (2 строки для 8 текстур)
        float uOffset = (textureIndex % 4) / atlasWidth;
        float vOffset = Mathf.Floor(textureIndex / 4.0f) / atlasHeight;

        // Примените смещение к UV-координатам. Это упрощенный подход; для точности используйте Mesh.vertices и Mesh.uv
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        Vector2[] uvs = mesh.uv;

        // Найдите UV для hit.triIndex (индекс треугольника)
        int triangleIndex = hit.triangleIndex * 3; // Каждый треугольник имеет 3 вершины
        for (int i = 0; i < 3; i++)
        {
            // Измените UV для вершин треугольника. Это может потребовать более сложной логики для независимых сторон.
            uvs[mesh.triangles[triangleIndex + i]] = new Vector2(uvs[mesh.triangles[triangleIndex + i]].x + uOffset, uvs[mesh.triangles[triangleIndex + i]].y + vOffset);
        }
        mesh.uv = uvs; // Примените изменения UV
        mesh.UploadMeshData(false); // Обновите mesh для рендеринга

        // Альтернативно, если используете отдельные материалы для сторон, измените material index
    }
}

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

Преимущества текстурного атласа

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


Управление текстурами в рантайме

В вашем редакторе уровня игроки должны уметь выбирать текстуру и окрашивать сегменты стен. Для этого интегрируйте UI-элементы, такие как кнопки для выбора индекса текстуры, и обработку ввода для кликов.

Чтобы обеспечить независимую окраску, модель стены должна быть разделена на подмесхи (submeshes), где каждая сторона — отдельный submesh с собственным материалом. Это позволит назначать разные текстуры без изменения UV глобально.

  • Подход с submeshes: В Blender создайте отдельные объекты для внутренней и внешней сторон стены, экспортируйте как один mesh с несколькими submeshes. В Unity назначьте разные материалы или один материал с атласом и изменяйте индекс текстуры.
  • Shader-based подход: Используйте кастомный шейдер, который принимает индекс текстуры и вычисляет UV на основе атласа. Это может быть эффективнее, но требует знаний HLSL.

Для кликов используйте Raycast с учетом нормали грани (hit.normal), чтобы определить, внутренняя или внешняя сторона была задета. Затем примените текстуру через код.

Таблица индексов текстур в атласе

Для ясности, вот таблица, показывающая, как индексы текстур (0-7) отображаются на UV-координатах в атласе размером 4x2 секции. Это поможет в расчете смещений.

Индекс U-координата (offset) V-координата (offset) Описание
0 0.0 - 0.25 0.0 - 0.5 Текстура для стены, например, кирпич
1 0.25 - 0.5 0.0 - 0.5 Дерево или другой материал
2 0.5 - 0.75 0.0 - 0.5 Камень
3 0.75 - 1.0 0.0 - 0.5 Металл
4 0.0 - 0.25 0.5 - 1.0 Обои
5 0.25 - 0.5 0.5 - 1.0 Плитка
6 0.5 - 0.75 0.5 - 1.0 Краска
7 0.75 - 1.0 0.5 - 1.0 Другой материал

Эта таблица показывает, как на основе индекса рассчитывать UV-смещение. Используйте её в коде для точного позиционирования текстуры.

Интеграция с редактором уровня

В вашем рантайм-редакторе добавьте UI для выбора текстуры (например, кнопки с индексами). После выбора индекса, при клике на стену, вызовите метод окраски. Для поддержки окраски отдельных сегментов, разделите стены на мелкие объекты или используйте компоненты для хранения текстурного состояния.


Добавление визуальных элементов и видео

Чтобы лучше понять концепцию текстурных атласов, посмотрите это видео, которое демонстрирует, как использовать SpriteAtlas в Unity для похожих целей. Видео фокусируется на 2D, но принципы применимы и к 3D-моделям.

Это видео объясняет, как настроить SpriteAtlas и применить его к материалам, что напрямую связано с вашей задачей. Оно показывает, как уменьшить draw calls и управлять текстурами эффективно, что критично для вашего сценария с окраской стен.


Часто задаваемые вопросы (FAQ)

Что делать, если текстура растягивается на стенах?

Чтобы избежать растяжения, убедитесь, что UV-координаты в Blender настроены на единообразное tiling. В Unity используйте свойства material.mainTextureScale для корректировки размера текстуры.

Как оптимизировать производительность для большого количества стен?

Используйте статический батчинг в Unity, комбинируя стены в один mesh, и держите текстурный атлас как можно меньшим. Избегайте частых изменений UV на лету; вместо этого используйте precomputed варианты.

Можно ли использовать шейдеры для более сложной окраски?

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

Что если игрок хочет отменить окраску?

Храните историю изменений или используйте undo-систему в коде, сохраняя исходные UV или индексы текстур для каждой грани.


Ссылки

docs.unity3d.com
Unity3d
docs.unity3d.com
Texture atlases

Last updated May 7, 2025

AI-assisted research. Sources, methodology and corrections · Source-checked guides and tools · Explore published answers

Ask Ithy AI