alexprey alexprey

Добавил скриншоты на главную, позже загружу дневники разработки игры, где можно будет посмотреть с чего все начиналось :)

alexprey alexprey

EfReeZe, о да, тогда было знатное время и игра казалась сделано круто :D До сих пор иногда играю на телефоне от скуки)

EfReeZe EfReeZe

Это был наш далёкий 2014...

Jusper Jusper

Запись трансляции на YouTube

Jusper Jusper

Случайно сделали битву сварщиков
https://devtribe.ru/p/slash-polygon

Jusper Jusper

Внезапно на сайте потерялся 15-й выпуск. Перевыложили.

Jusper Jusper

Я вам еще не закончил писать обратную связь по боевке, есть много вещей которые немного смутили, но они поправимы. Завтра, если перестанут дергать - чиркану. Спасибо за демку!

Jusper Jusper

ruggaraxe,

Да, в этом плане все ок. Логично, что графен на старой машине, если не упарываться, не взлетит. Но я рад, что это было не 5 фпс, как даже в некоторых АА (типа Pillars of Eternity в некоторых схватках...

Jusper Jusper

ruggaraxe,

Подкреплю ее к публикации.

ruggaraxe ruggaraxe

Jusper, вот ссылка на анкету (я затупил со ссылкой с топике, сорри)
https://docs.google.com/forms/d/e/1FAIpQLSd_Wn53lJFrnfGpWI2IX...

ruggaraxe ruggaraxe

Jusper, честно говоря, да на 800х600 даже не проверяли... :) сорри. Ориентировались на FullHD и выше. Хотя над интерфейсом конечно же надо еще хорошенько поработать.
Тултипы постараемся сделать обязательно к следующей версии...

GenElCon GenElCon

Jusper,

Наверное. В прошлом они сделали Endless Legend - посмотри и сразу станет ясно в какую сторону они работают.

Jusper Jusper

GenElCon,

Я не очень понял по трейлеру геймплей. Это что-то типа цивы? Или это RTS?

GenElCon GenElCon

Humankind от разработчиков Endless Legends (и Space, но тут важно именно Legends).
А также согревающие сердца олдов трейлеры Port Royal 4 и Knights of Honor.

Jusper Jusper

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

Jusper Jusper

Первое, оно же самое тяжелое - UI. Я конечно, понимаю, что 800x600 совсем уже не в моде (завтра проверю на нормальной широформатной машине). Заблюренный текст я еще прочитать могу, но вот конкретно размер его крайне мал...

...
Jusper Jusper

ruggaraxe, я поиграл на старом маке 2012 года (Macbook Pro, Intel HD 4000), рад что с учетом довольно нагруженной по свету и теням картинке игруля не лагает как последняя сволочь (лагает конечно, но очень терпимо...

Логотип проекта Unity

#3 Vertex and Fragment Shader

Vertex and Fragment Shader

В этой статье мы напишем простой вертексно-пиксельный шейдер, который
будет натягивать текстуру(логотип XGM) на объект(в моем случае на
сферу).
Итак, приступим.
Для начала создадим папку, где будем хранить шейдеры. Назовем ее
Shaders. Далее создадим шейдер: правый клик по папке
Shaders>Create>Shader>Unlit Shader. Назовем шейдер xgmSkin.

#3 Vertex and Fragment Shader — Unity — DevTribe: Разработка игр

Перед нами открылось окно редактора с содержанием стандартного Unlit
Shader'а. Выделяем все и смело удаляем. Начнем, как говориться, "с чистого листа".
Из предыдущей статьи мы уяснили, что в Unity шейдер пишется внутри
SubShader'а. Так-что давайте сначала напишем "фундамент".

Shader "MyShaders/xgmSkin" // путь и имя шейдера в выпадающем окне 
материала
{
  Properties // отображаемые в инспекторе свойства
   { 
    
   }
   SubShader 
   {
     Pass 
      {
        CGPROGRAM
        // тут будет CG код
        CGEND
      }
   }
  Fallback "Diffuse" 
}

Начнем заполнять блок Properties. В нем мы обозначаем внешние
переменные, которые будут видны в окне материала в инспекторе. Здесь нам
многого не нужно, только текстурка. Пишем:

  Properties 
  {
    _xgmTex("Texture",2D) = "white" {} 
  }

Ну и всё, никаких тэгов писать не будем, нам подходят настройки по
дефолту, так что сразу спускаемся в блок CGPROGRAM.
В статье по теории я писал, что мы можем назначать, какие данные примет и
вернет шейдер при помощи семантики. Для удобства записи в CG программе
эти данные объединяют в структуры. Давайте опишем входящую(vertexInput) и
выходящую(vertexOutput) структуры для вертексного шейдера:

struct vertexInput // входящие данные
      {
        float4 vertex:POSITION; // позиция вершины в пространстве модели
        float2 uv:TEXCOORD0; // uv координаты данной вершины 
  
      };
      struct vertexOutput // выходящие данные
      {
       float4 position:SV_POSITION; // позиция 
       float2 uv:TEXCOORD0; // uv координаты
      };
После структур обязательно ставится знак ";"

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

#pragma vertex vert 
#pragma fragmet frag 

А вот собственно сам вертексный шейдер:

vertexOutput vert(vertexInput v) 
      {
        vertexOutput o; // создаем возвращаемую структуру 
        o.position = mul(UNITY_MATRIX_MVP,poss); // переводим координатыиз пространства модели в проекционное 
        o.uv = v.uv; // просто передаем uv координаты
        return o; 
      }

Пиксельный шейдер возвращает только цвет, так что нужды создавать
отдельную структуру для него у нас нет. Поэтому,назначаем семантику
прямо для самого возвращаемого значения функции frag(Семантика для цвета
COLOR или SV_Target ). Так же нам нужно вытащить текстуру из
Properties.Напомню, что имя внешней переменной должно быть такое-же, как в
Properties, что бы движок сам передал ей значение.

      uniform sampler2D _xgmTex; // внешняя текстура 

      fixed4 frag(vertexOutput v):SV_Target 
      {
        fixed4 col = tex2D(_xgmTex,v.uv);// берем цвет из текстуры по UV
 координатам
        return col;
      } 

Ну вот и всё, наш шейдер готов!

Shader "MyShaders/xgmSkin" 
{
  Properties 
  {
    _xgmTex("Texture",2D) = "white" {} 
  }

SubShader
 {
   Pass
   {
     CGPROGRAM 
     #pragma vertex vert // говорим имя у вертексного шейдера 
     #pragma fragment frag  // говорим имя пиксельного шейдера

      struct vertexInput 
      {
        float4 vertex:POSITION;
        float2 uv:TEXCOORD0;
      };
      struct vertexOutput
      {
       float4 position:SV_POSITION;
       float2 uv:TEXCOORD0;
      };
      vertexOutput vert(vertexInput v) 
      {
        vertexOutput o; // возвращаемая структура 
        o.position = mul(UNITY_MATRIX_MVP,v.vertex); // переводим координаты
        из пространства модели в проекционное 
        o.uv = v.uv; // просто передаем uv координаты
        return o;
      }
      uniform sampler2D _xgmTex; // внешняя текстура 

      fixed4 frag(vertexOutput v):SV_Target
      {
        fixed4 col = tex2D(_xgmTex,v.uv); // берем цвет из текстуры по 
UV координатам
        return col;
      } 
     ENDCG  
   } 
  } 
  Fallback "Diffuse"
 } 

Пора применить его на объекте! Для того что-бы применить шейдер для
какого-либо объекта, нужно создать новый материал и назначить наш шейдер
в выпадающем окне материала(если вы не забыли, наш шейдер находится в MyShaders>xgmSkin)

#3 Vertex and Fragment Shader — Unity — DevTribe: Разработка игр

Теперь выберем нужную текстуру в окне материала.
Вуаля!

#3 Vertex and Fragment Shader — Unity — DevTribe: Разработка игр

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

    _Color ("LogoColor",Color) = (0,0,0,0)

И объявим его внутри шейдера в том-же месте, где объявляли текстуру

 uniform fixed4 _Color;

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

      fixed4 frag(vertexOutput v):SV_Target
      {
        fixed4 col = tex2D(_xgmTex,v.uv); // берем цвет из текстуры по 
UV координатам
        return (1-col)*_Color;
      } 
1=(1,1,1,1); 0 = (0,0,0,0) //

В итоге,если мы установим _Color на зеленый цвет, у нас получилась
такая вот сфера, у которой мы можем менять цвет текстуры логотипа по
нашему желанию.)

#3 Vertex and Fragment Shader — Unity — DevTribe: Разработка игр

Итак, теперь мы, вроде, умеем делать простые-препростые шейдеры. Давайте
капнем немного глубже и сделаем нашей сфере дифузное освещение.
Вот формула, по которой рассчитывается освещенность для точки:
dif = max(0,(n*l)), где n - нормаль, l - направление света.

Заранее скажу, что рассчитывать освещение мы будет в мировых
координатах, следовательно, нормаль, которая дается в объектных
координатах придется переводить в мировые. Обычная матрица, которую мы
используем для частиц тут не подойдет, так-что для таких случаев
припасена встроенная инверсная матрица _World2Object.
Так-же хочу сказать о том, что в ShaderLab есть встроенная переменная
_WorldSpaceLightPos0. По названию можно понять, что это вектор, который
содержит мировые координаты источника света, но тут есть одна хитрость.
Если на карте используется только 1 источник света ( Direction light),
то тогда в эту переменную записывается вектор освещения, а если больше,
то ,действительно, положение источника света. В данном случае у нас один
источник, так что эта переменная нам подходит.
Еще кое-что.Как мы все знаем, семантика TEXCOORD используется для передачи
uv координат. Но, т.к. их может быть несколько штук, например,
TEXCOORD1,TEXCOORD2,TEXCOORD3..., ее удобно использовать, что-бы
передать нужные данные из вертексного шейдера в пиксельный, т.к. у
переменных во входящих/выходящих струтурах обязательно должна семантика.
Ну вот теперь вроде всё. Поехали!
Добавим в vertexInput строчку, которая будет запрашивать нормаль:

float3 norm:NORMAL;

И в vertexOutput переменную для хранения мировых координат нормали:

       float3 worldNormal:TEXCOORD1;

Далее идем в вертексный шейдер и переводим нормаль из объектного в
мировые координаты:

        o.worldNormal = mul(_World2Object,v.norm);

Ну и рассчитаем силу освещения в пиксельном шейдере:

      fixed4 frag(vertexOutput v):SV_Target
      {
        fixed4 col = tex2D(_xgmTex,v.uv); // берем цвет из текстуры по UV координатам
        float3 l = normalize(_WorldSpaceLightPos0); // нормализуем вектор освещения
        float3 n = normalize(v.worldNormal); // нормализуем вектор нормали 
        float dif = max(0.0,dot(n,l)); // рассчитываем освещенность пикселя 
        return ((1-col)*_Color)*dif; 
      } 

Ну вот как-то так. Теперь, если мы перейдем в юнити и изменим
направление лучей у Direction light'а, то заметим, что участки с
противоположной стороны от света затеняться.

#3 Vertex and Fragment Shader — Unity — DevTribe: Разработка игр

Shader "MyShaders/xgmSkin"
{
Properties
{
_xgmTex("Texture",2D) = "white" {}
_Color ("LogoColor",Color) = (0,0,0,0)
}

SubShader
{
Pass
{
Cull Off

CGPROGRAM
#pragma vertex vert // говорим имя у вертексного шейдера
#pragma fragment frag // говорим имя пиксельного шейдера

struct vertexInput
{
float4 vertex:POSITION;
float2 uv:TEXCOORD0;
float3 norm:NORMAL;
};
struct vertexOutput
{
float4 position:SV_POSITION;
float2 uv:TEXCOORD0;
float3 worldNormal:TEXCOORD1;
};
vertexOutput vert(vertexInput v)
{
vertexOutput o; // возвращаемая структура
o.position = mul(UNITY_MATRIX_MVP,v.vertex); // переводим координаты из пространства модели в проекционное
o.uv = v.uv; // просто передаем uv координаты
o.worldNormal = mul(_World2Object,v.norm); // переводим нормаль в мировые к-ты
return o;
}
uniform sampler2D _xgmTex; // внешняя текстура
uniform fixed4 _Color;

fixed4 frag(vertexOutput v):SV_Target
{
fixed4 col = tex2D(_xgmTex,v.uv); // берем цвет из текстуры по UV координатам
float3 l = normalize(_WorldSpaceLightPos0); // нормализуем вектор освещения
float3 n = normalize(v.worldNormal); // нормализуем вектор нормали
float dif = max(0.0,dot(n,l)); // рассчитываем освещенность пикселя
return ((1-col)*_Color)*dif;
}
ENDCG

}
}
Fallback "Diffuse"
}

Итог:

http://devtribe.ru/ext-files/562/174812/qwerty.unity3d

To be continued ...

P.S. спонсоры данных статьей - кофе и свободное время. Спасибо им за то что они есть.

Здесь еще никто не оставил комментарий

Справка