Среда, 27 Ноября 2024, 07:01

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Unity voxel block tutorial pt. 1 [ПЕРЕВОД]
FetBikoДата: Вторник, 19 Января 2016, 22:06 | Сообщение # 1
частый гость
Сейчас нет на сайте
ССЫЛКА НА ОРИГИНАЛ: http://alexstv.com/index.php/posts/unity-voxel-block-tutorial
Стоит ли продолжать перевод этой статьи и всего курса вообще?
Буду рад поддержке и помощи в переводе.

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

Начнем с пустого проекта unity, но, если вы хотите, можете расширить свой существующий проект. Начнем с чанков и блоков.
Чанк - это часть вокселей, что будут рендериться вместе.

Я использую чанки 16x16x16, но большие чанки (32х32х32) позволяют уменьшить количество вызовов отрисовки (Draw Calls), а маленькие чанки (16х16х16) будут использовать меньше ресурсов при изменении блоков (потому что весь чанк должен быть перезагружен) или загрузки чанка. Unity имеет ограничение на количество полигонов в мешах, а чанк имеет единый меш, так что, если он будет слишком большим, unity не сможет его отрендерить.

Создадим 3 скрипта: Chunk, Block и MeshData. Задачи Chunk - хранение данных о чанке, его содержании и создание меша своих вокселей для рендеринга и обработки столкновений. Block хранит данные об отдельном блоке и о том, как его нужно рендерить. MeshData обеспечит нас простым способом хранения данных меша.

Сейчас мы начнем с Chunk и добавим в него основные функции и методы:

Код
//Chunk.cs
using UnityEngine;
using System.Collections;

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshCollider))]

public class Chunk : MonoBehaviour {

     Block[ , , ] blocks;
     public static int chunkSize = 16;
     public bool update = true;

    //Use this for initialization
    void Start () {

    }

    //Update is called once per frame
    void Update () {

    }

     public Block GetBlock(int x, int y, int z)
     {
         return blocks[x, y, z];
     }

     //Updates the chunk based on its contents
     void UpdateChunk()
     {

     }

     //Sends the calculated mesh information
     //to the mesh and collision components
     void RenderMesh()
     {

     }

}


Во-первых, мы включим 3 компонента, без которых скрипт не сможет работать: MeshFilter, MeshRenderer and MeshCollider. Теперь, при создании нового GameObject'а с данным скриптом, эти компоненты будут автоматически добавляться. Нам нужны эти компоненты, чтобы рендерить чанк и обновлять его коллайдер.

Далее переменные. "blocks" - трехмерный массив для класса Block, таким образом в классах Block мы можем хранить данные обо всех интересующих нас блоках в классах Block. Статичная переменная chunkSize определяет сколько вокселей в каждом направлении может иметь наш чанк. В конце концов, мы используем булевую переменную update, которая показывает, что чанк был изменен и он нуждается в обновлении в конце данного кадра.

Из функций я добавил GetBlock, которая возвращает блок из чанка. UpdateChunk с циклом, перебирающим все блоки, для построяния 3D меша, исходя из наличия блоков и их типов, и отправления этого MeshRenderer’у, который отрендерит этот меш.

Далее, перейдем к MeshData, т.к. он понадобится нам прежде, чем мы вернемся к классу Block. Выглядит MeshData так:

Код
//MeshData.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class MeshData {
     public List<Vector3> vertices = new List<Vector3>();
     public List<int> triangles = new List<int>();
     public List<Vector2> uv = new List<Vector2>();

    public List<Vector3> colVertices = new List<Vector3>();
  public List<int> colTriangles = new List<int>();

    public MeshData() { }

}


Обратите внимание, MeshData не наследуется от MonoBehaviour, это не нужно, потому что мы будем использовать его только через код и сможем создать экземпляр с помощью конструктора “new MeshData();” в любое время. Переменными здесь являются 3 компонента меша: verts, tris и texture coordinates, и еще 2 для сетки коллайдера, содержащие только verts и tris.

Vertices are vector 3 positions in space that define the points or corners of every triangle in the mesh. Every three entries in the triangles list defines one triangle and the entry itself is the index of a vector 3 in the vertices array. The uv list is a vector 2 list of texture coordinates and there are two entries per triangle, the coordinates of the lower left of the triangle and the upper right of the triangle.
The col lists are the same as vertices and triangles but for use as the collider mesh so that you can pass a different mesh for the rendering and the collider.


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

Код

using UnityEngine;
using System.Collections;

public class Block {

     //Base block constructor
     public Block(){

     }

     public virtual MeshData Blockdata
         (Chunk chunk, int x, int y, int z, MeshData meshData)
     {
         return meshData;
     }

}


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

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

When we render voxels we don't need to render every side of every voxel. Some faces will be impossible for the player to see because they are covered by other voxels. In the case of square voxels we can always assume that a block adjacent to another the sides facing each other aren't visible so we don't need to render them. It's simple enough to only render faces of blocks facing empty spaces but we'll also handle non-cube blocks.


Личный сайт
Perfect Game Development — сообщество разработчиков игр.


Сообщение отредактировал FetBiko - Вторник, 19 Января 2016, 22:07
berilДата: Вторник, 19 Января 2016, 22:19 | Сообщение # 2
Я не ленивый, я — энергосберегающий
Сейчас нет на сайте
Лучше это в раздел "Статьи уроки" выложить cool



Накодил? Убери за собой!
Инвентарь в Unity(UI)
Инвентарь в Unity(GUI)
FetBikoДата: Суббота, 30 Января 2016, 15:03 | Сообщение # 3
частый гость
Сейчас нет на сайте
beril, хмм.. Да, а в этой теме можно вести небольшой блог и использовать её как черновик.

Добавлено (30 января 2016, 15:03)
---------------------------------------------
Извиняюсь, что нет никаких новостей. Времени очень мало, на статью не хватает.


Личный сайт
Perfect Game Development — сообщество разработчиков игр.
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг