Побаловался с синусами:
среда, 22 июня 2016 г.
четверг, 21 января 2016 г.
Unity3D – Chunky post process effect
Мы периодически встречаемся с друзьями из старой (древней) команды "Accept Corp".
SpeccyWiki: http://speccy.info/Accept_Corp
Вспоминаем былые времена, что творили на ZX Spectrum, немножко ностальгируем. Это всегда приятные встречи старых друзей.
Приветы:
Phantom Lord (Дмитрий Селин)
Cardinal (Виталий Казаков)
M.O.T (Виктор Васильев)
A.Soft (Владимир Коновалов)
DJ.Wolf (Сергей Малышев)
Cannibal (Григорий Садовой)
FF-Soft (Александр Макушин)
Shov (Олег Шашкин)
Layabout (Егор Волкодамов)
Y.Soft (Равиль Габитбаев)
Visual Graphics (Павел Мирчук)
К чему я это говорю? К тому что создание данного пост эффекта навеяно именно теми временами из 90х годов, когда появилась мода в Demo рендерить 3D сцены из блоков Chunky.
Как это выглядит:
Мы не будем останавливаться на моментах, описанных в предыдущей вводной статье:
Unity3D: Simple post process effect
Пропустим очевидные манипуляции. К тому же в данном подходе много общего.
Сама суть эффекта заключается в следующем:
- результат эффекта будет монохромный, черные пиксели на белом фоне;
- размер исходных блоков chunky сделаем 4x4 пикселя;
- спрайты chunky будем выбирать из заранее подготовленной текстуры. Выглядит она как полоска 64x4 пикселя, логически это наши 16 спрайтов 4x4 пикселя:
Маленькая правда? :) Для наглядности увеличим картинку в 4 раза:
- число спрайтов 16 соответствует количеству оттенков белого, которые мы будем использовать. Так же это обусловлено рисунком, комбинациями пикселей в каждой градации;
- мы выбираем из текстуры экрана цвет, приводим к чёрно-белому, условно соответствующему очередному блоку;
- приводим значение градации к индексу спрайта в листе chunky;
- и выводим сам спрайт.
А теперь по-настоящему.
Код шейдера:
Где:
1) - Уже знакомое нам, по прошлой статье, приведение экранных координат к текстурным
2) - Управление яркостью картинки, нужное больше для баловства и немножко для тестов;
3) - Перевод в grayscale;
4) - Индекс спрайта в листе;
5) - Расчет координат спрайта в листе chunky;
6) - Вывод.
Ни чего сложного не добавилось.
Знакомый нам исходный экран:
Результат:
SpeccyWiki: http://speccy.info/Accept_Corp
Вспоминаем былые времена, что творили на ZX Spectrum, немножко ностальгируем. Это всегда приятные встречи старых друзей.
Приветы:
Phantom Lord (Дмитрий Селин)
Cardinal (Виталий Казаков)
M.O.T (Виктор Васильев)
A.Soft (Владимир Коновалов)
DJ.Wolf (Сергей Малышев)
Cannibal (Григорий Садовой)
FF-Soft (Александр Макушин)
Shov (Олег Шашкин)
Layabout (Егор Волкодамов)
Y.Soft (Равиль Габитбаев)
Visual Graphics (Павел Мирчук)
К чему я это говорю? К тому что создание данного пост эффекта навеяно именно теми временами из 90х годов, когда появилась мода в Demo рендерить 3D сцены из блоков Chunky.
Как это выглядит:
Мы не будем останавливаться на моментах, описанных в предыдущей вводной статье:
Unity3D: Simple post process effect
Пропустим очевидные манипуляции. К тому же в данном подходе много общего.
Сама суть эффекта заключается в следующем:
- результат эффекта будет монохромный, черные пиксели на белом фоне;
- размер исходных блоков chunky сделаем 4x4 пикселя;
- спрайты chunky будем выбирать из заранее подготовленной текстуры. Выглядит она как полоска 64x4 пикселя, логически это наши 16 спрайтов 4x4 пикселя:
Маленькая правда? :) Для наглядности увеличим картинку в 4 раза:
- число спрайтов 16 соответствует количеству оттенков белого, которые мы будем использовать. Так же это обусловлено рисунком, комбинациями пикселей в каждой градации;
- мы выбираем из текстуры экрана цвет, приводим к чёрно-белому, условно соответствующему очередному блоку;
- приводим значение градации к индексу спрайта в листе chunky;
- и выводим сам спрайт.
А теперь по-настоящему.
Код шейдера:
Shader "Hidden/Chunky" { Properties { _MainTex("Texture", 2D) = "white" {} _SprTex("Texture", 2D) = "white" {} } SubShader { Pass { CGPROGRAM #pragma vertex vert_img #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; sampler2D _SprTex; float4 _Color = float4(1, 1, 1, 1); float2 BlockCount; float2 BlockSize; fixed4 frag(v2f_img i) : SV_Target { // (1) float2 blockPos = floor(i.uv * BlockCount); float2 blockCenter = blockPos * BlockSize + BlockSize * 0.5; // (2) float4 del = float4(1, 1, 1, 1) - _Color; // (3) float4 tex = tex2D(_MainTex, blockCenter) - del; float grayscale = dot(tex.rgb, float3(0.3, 0.59, 0.11)); grayscale = clamp(grayscale, 0.0, 1.0); // (4) float dx = floor(grayscale * 16.0); // (5) float2 sprPos = i.uv; sprPos -= blockPos*BlockSize; sprPos.x /= 16; sprPos *= BlockCount; sprPos.x += 1.0 / 16.0 * dx; // (6) float4 tex2 = tex2D(_SprTex, sprPos); return tex2; } ENDCG } } }
Где:
1) - Уже знакомое нам, по прошлой статье, приведение экранных координат к текстурным
2) - Управление яркостью картинки, нужное больше для баловства и немножко для тестов;
3) - Перевод в grayscale;
4) - Индекс спрайта в листе;
5) - Расчет координат спрайта в листе chunky;
6) - Вывод.
using UnityEngine; using UnityStandardAssets.ImageEffects; namespace Assets.Scripts.PostEffects { [ExecuteInEditMode] [AddComponentMenu("Image Effects/Color Adjustments/Chunky")] public class Chunky : ImageEffectBase { public Texture2D SprTex; public Color Color = Color.white; private void OnRenderImage(RenderTexture source, RenderTexture destination) { float k = Camera.main.aspect; float w = Camera.main.pixelWidth; float h = Camera.main.pixelHeight; Vector2 count = new Vector2(w/SprTex.height, h/SprTex.height); Vector2 size = new Vector2(1.0f/count.x, 1.0f/count.y); // material.SetVector("BlockCount", count); material.SetVector("BlockSize", size); material.SetColor("_Color", Color); material.SetTexture("_SprTex", SprTex); Graphics.Blit(source, destination, material); } } }
Ни чего сложного не добавилось.
Знакомый нам исходный экран:
Результат:
Конечно на живую в fullscreen и в динамике выглядит по интереснее.
Но, в любом случае, на картинки лучше кликать для просмотра.
Но, в любом случае, на картинки лучше кликать для просмотра.
среда, 20 января 2016 г.
Unity3D: Simple post process effect
В этой статье мы рассмотрим:
- порядок создания простого пост эффекта;
- некоторые нюансы приведения размеров.
Для
наших экспериментов нам потребуется сцена, с объектами или картинками, не
важно, главное по пестрее. Я набросал такую:
На этой
сцене отлаживался не один пост эффект, поэтому все что на ней присутствует –
закономерно и не лишнее.
Подготовим
файлы. Мы будем работать с файлом шейдера и скриптом.
Начнем
с шейдера.
В папке Assets кликаем правой кнопкой мыши и выбираем:
Create->Shader-> NewImageEffectShader.
Нам
будет предложено на выбор несколько типов шейдеров, но это не так важно,
внутренности мы перепишем. Я переименовал созданный файл в «Pixelation».
Открываем и зачищаем от всего лишнего до такого вида:
Shader "Hidden/Pixelation Effect" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Pass { CGPROGRAM #pragma vertex vert_img #pragma fragment frag #include "UnityCG.cginc" fixed4 frag (v2f_img i) : SV_Target { } ENDCG } } }
Обратите внимание на то, что входные данные пиксельного
(фрагментного, привык я к терминологии HLSL) шейдера описывает структура
v2f_img. Ее вполне достаточно для нас.
Далее добавляем входные параметры шейдера и необходимый код
как в примере:
Shader "Hidden/Pixelation Effect" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Pass { CGPROGRAM #pragma vertex vert_img #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; float2 BlockCount; float2 BlockSize; fixed4 frag (v2f_img i) : SV_Target { float2 blockPos = floor(i.uv * BlockCount); float2 blockCenter = blockPos * BlockSize + BlockSize * 0.5; float4 tex = tex2D(_MainTex, blockCenter); return tex; } ENDCG } } }
sampler2D _MainTex – буфер экрана как текстура;
float2 BlockCount – количество кирпичиков на экране (псевдопикселей)
по X и Y;
float2 BlockSize – размеры кирпичиков тоже по X и Y;
Шейдер простой, вся суть в
функции floor. Из справки:
floor(x) - возвращает самое большое целое число, которое
является меньше чем или равным x.
Назначение и подготовку BlockCount и BlockSize рассмотрим в
скрипте эффекта.
Как создать новый скрипт я писать не буду, но стоит уточнить
вот что.
Нам потребуется импортировать некоторые стандартные ассеты,
а именно:
Assets->Import package->Effects
С точки зрения изучения пост эффектов нам интересен весь
пакет, в дальнейшем можно самостоятельно почитать типовые эффекты, входящие в
него. Но пока на нужен только ImageEffectBase.cs что бы наследовать от него
класс нашего скрипта.
В результате у нас должен
получиться вот такой код:
using UnityEngine; using UnityStandardAssets.ImageEffects; namespace Assets.Scripts.PostEffects { [ExecuteInEditMode] [AddComponentMenu("Image Effects/Color Adjustments/Pixelation")] public class Pixelation : ImageEffectBase { [Range(64.0f, 512.0f)] public float BlockCount = 256; private void OnRenderImage(RenderTexture source, RenderTexture destination) { float k = Camera.main.aspect; Vector2 count = new Vector2(BlockCount, BlockCount/k); Vector2 size = new Vector2(1.0f/count.x, 1.0f/count.y); // material.SetVector("BlockCount", count); material.SetVector("BlockSize", size); Graphics.Blit(source, destination, material); } } }
Где:
BlockCount – исходное количество блоков по горизонтали;
k – понятно из определения, коэффициент соотношения сторон
экрана;
count – вектор в который складываем расчетные значения
количества кирпичиков по горизонтали и вертикали;
size – расчетное значение размеров кирпичиков, основанное на
их количестве и коэффициенте соотношения сторон экрана.
Может
быть лишнее, но я хотел бы пояснить то, что в шейдере мы имеем дело с
текстурами размером (1f, 1f) не зависимо от их реальных размеров в пикселях. И
т.к. текстурные координаты носят относительный характер, то эту самую
относительность мы и выражаем в size. Для пущей очевидности замечу, что size
делает условные пикселы квадратными на всех разрешениях мониторов с разным
соотношением сторон.
Далее
файл скрипта перетаскиваем на объект нашей сцены - камеру, в поле скрипта
Shader перетаскиваем наш шейдер. Итог:
Готово.
Запускаем.
воскресенье, 1 февраля 2015 г.
HLSL: Шейдер воды
Какое то время назад я показывал, в своей публикации, видео с примером реализации воды.
По многочисленным просьбам решил открыть код своего шейдера Water.fx:
float4x4 mWorld;
float4x4 mWorldBack;
float4x4 mWVP;
float4x4 mWVPreflection;
float3 LightDir;
float3 ViewDir;
float waveHeight;
float2 windDelCoord;
float width = 1000;
float heught = 1000;
Texture texRefraction;
sampler RefractionMapSampler = sampler_state
{
texture = ;
magfilter = ANISOTROPIC;
minfilter = LINEAR;
mipfilter = LINEAR;
MaxAnisotropy = 8;
AddressU = mirror;
AddressV = mirror;
};
Texture texReflection;
sampler ReflectionMapSampler = sampler_state
{
texture = ;
magfilter = ANISOTROPIC;
minfilter = LINEAR;
mipfilter = LINEAR;
MaxAnisotropy = 8;
AddressU = mirror;
AddressV = mirror;
};
Texture texBumpMapA;
sampler BumpMapSamplerA = sampler_state
{
texture = ;
magfilter = ANISOTROPIC;
minfilter = LINEAR;
mipfilter = LINEAR;
MaxAnisotropy = 8;
AddressU = mirror;
AddressV = mirror;
};
Texture texBumpMapB;
sampler BumpMapSamplerB = sampler_state
{
texture = ;
magfilter = LINEAR;
minfilter = LINEAR;
mipfilter = LINEAR;
AddressU = mirror;
AddressV = mirror;
};
struct VertexShaderInput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 TexCoordReflectionMap : TEXCOORD1;
float4 TexCoordRefractionMap : TEXCOORD2;
float2 TexCoordBumpMap : TEXCOORD3;
float4 Position3D : TEXCOORD4;
float3 LightTS : TEXCOORD5;
float3 ViewTS : TEXCOORD6;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, mWorld);
output.Position = mul(input.Position, mWVP);
output.TexCoordReflectionMap = mul(input.Position, mWVPreflection);
output.TexCoordRefractionMap = output.Position;
output.TexCoordBumpMap = input.TexCoord;
output.Position3D = worldPosition;
float3 tangent = float3(1,0,0);
float3 binormal = float3(0,0,1);
float3 normal = float3(0,1,0);
float3x3 matTS = float3x3( tangent, binormal, normal );
float3 Light = mul(LightDir, mWorldBack) - worldPosition;
float3 View = mul(ViewDir, mWorldBack) - worldPosition;
output.LightTS = normalize(mul(Light, matTS));
output.ViewTS = normalize(mul(View, matTS));
return output;
}
float4 cSpecularColor = float4(1, 1, 1, 1);
float fSpecularExponent = 300;
float4 WaterPS(VertexShaderOutput input) : COLOR0
{
float3 Distance = input.Position3D - ViewDir;
float rDistance = abs(length(Distance));
float rDistanceY = abs(length(Distance.y));
float rDistanceXZ = abs(length(Distance.xz));
float lerpDistanceA = 1 - saturate(rDistanceXZ / 1000);
float lerpDistanceB = 0.0;
if(rDistance > 50.0f)
{
lerpDistanceB = 1 - saturate(rDistance) / (1 * width);
}
else
{
lerpDistanceB = saturate(rDistanceXZ / 50.0f);
}
// reflection
float2 TexCoorReflection;
TexCoorReflection.x = input.TexCoordReflectionMap.x / input.TexCoordReflectionMap.w / 2.0f + 0.5f;
TexCoorReflection.y = -input.TexCoordReflectionMap.y / input.TexCoordReflectionMap.w / 2.0f + 0.5f;
float3 bumpNormalA = tex2D(BumpMapSamplerA, input.TexCoordBumpMap * 16 + windDelCoord) * 2 - 1;
float3 bumpNormalB = tex2D(BumpMapSamplerB, input.TexCoordBumpMap * 256 - windDelCoord * 2 ) * 2 - 1;
float2 moveA = bumpNormalA.xy * waveHeight * lerpDistanceA;
float2 moveB = bumpNormalB.xy * 0.2 * lerpDistanceB;
float2 TextCoordMove = moveA + moveB;
float2 TexCoordsMoveReflection = TexCoorReflection * 0.75f + TextCoordMove;
float4 reflectiveColor = tex2D(ReflectionMapSampler, TexCoordsMoveReflection) * 0.7f;
float3 NormalTS = tex2D( BumpMapSamplerA, input.TexCoordBumpMap * 16 + windDelCoord) * 2 - 1;
NormalTS = normalize( NormalTS);
float3 vReflectionTS = normalize( 2 * dot( input.ViewTS, NormalTS * 2 ) * NormalTS - input.ViewTS );
float fRdotL = dot( vReflectionTS, input.LightTS );
float4 cSpecular = saturate( pow( fRdotL, fSpecularExponent )) * cSpecularColor;
float light = clamp(dot(NormalTS, input.LightTS) * (reflectiveColor + cSpecular), 0, 1);
reflectiveColor += light * 0.9;
// refraction
float2 TexCoordRefraction;
TexCoordRefraction.x = input.TexCoordRefractionMap.x / input.TexCoordRefractionMap.w / 2.0f + 0.5f;
TexCoordRefraction.y = -input.TexCoordRefractionMap.y / input.TexCoordRefractionMap.w / 2.0f + 0.5f;
float2 TexCoordsMoveRefraction = TexCoordRefraction + TextCoordMove;// * lerpDistanceRefracion;
float4 refractiveColor = tex2D(RefractionMapSampler, TexCoordsMoveRefraction);
float3 eyeVector = normalize(ViewDir - input.Position3D);
float3 normalVector = float3(0,1,0);
float fNdotV = dot(eyeVector, normalVector);
float fFresnel = 1.0 - fNdotV;
// result
float4 resultColor = lerp(refractiveColor, reflectiveColor, fFresnel);
//resultColor.rgb *= (1.0 + resultColor.a * 1.2);
return resultColor;
}
technique Water
{
pass P0
{
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_3_0 WaterPS();
}
}
По многочисленным просьбам решил открыть код своего шейдера Water.fx:
float4x4 mWorld;
float4x4 mWorldBack;
float4x4 mWVP;
float4x4 mWVPreflection;
float3 LightDir;
float3 ViewDir;
float waveHeight;
float2 windDelCoord;
float width = 1000;
float heught = 1000;
Texture texRefraction;
sampler RefractionMapSampler = sampler_state
{
texture =
magfilter = ANISOTROPIC;
minfilter = LINEAR;
mipfilter = LINEAR;
MaxAnisotropy = 8;
AddressU = mirror;
AddressV = mirror;
};
Texture texReflection;
sampler ReflectionMapSampler = sampler_state
{
texture =
magfilter = ANISOTROPIC;
minfilter = LINEAR;
mipfilter = LINEAR;
MaxAnisotropy = 8;
AddressU = mirror;
AddressV = mirror;
};
Texture texBumpMapA;
sampler BumpMapSamplerA = sampler_state
{
texture =
magfilter = ANISOTROPIC;
minfilter = LINEAR;
mipfilter = LINEAR;
MaxAnisotropy = 8;
AddressU = mirror;
AddressV = mirror;
};
Texture texBumpMapB;
sampler BumpMapSamplerB = sampler_state
{
texture =
magfilter = LINEAR;
minfilter = LINEAR;
mipfilter = LINEAR;
AddressU = mirror;
AddressV = mirror;
};
struct VertexShaderInput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 TexCoordReflectionMap : TEXCOORD1;
float4 TexCoordRefractionMap : TEXCOORD2;
float2 TexCoordBumpMap : TEXCOORD3;
float4 Position3D : TEXCOORD4;
float3 LightTS : TEXCOORD5;
float3 ViewTS : TEXCOORD6;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, mWorld);
output.Position = mul(input.Position, mWVP);
output.TexCoordReflectionMap = mul(input.Position, mWVPreflection);
output.TexCoordRefractionMap = output.Position;
output.TexCoordBumpMap = input.TexCoord;
output.Position3D = worldPosition;
float3 tangent = float3(1,0,0);
float3 binormal = float3(0,0,1);
float3 normal = float3(0,1,0);
float3x3 matTS = float3x3( tangent, binormal, normal );
float3 Light = mul(LightDir, mWorldBack) - worldPosition;
float3 View = mul(ViewDir, mWorldBack) - worldPosition;
output.LightTS = normalize(mul(Light, matTS));
output.ViewTS = normalize(mul(View, matTS));
return output;
}
float4 cSpecularColor = float4(1, 1, 1, 1);
float fSpecularExponent = 300;
float4 WaterPS(VertexShaderOutput input) : COLOR0
{
float3 Distance = input.Position3D - ViewDir;
float rDistance = abs(length(Distance));
float rDistanceY = abs(length(Distance.y));
float rDistanceXZ = abs(length(Distance.xz));
float lerpDistanceA = 1 - saturate(rDistanceXZ / 1000);
float lerpDistanceB = 0.0;
if(rDistance > 50.0f)
{
lerpDistanceB = 1 - saturate(rDistance) / (1 * width);
}
else
{
lerpDistanceB = saturate(rDistanceXZ / 50.0f);
}
// reflection
float2 TexCoorReflection;
TexCoorReflection.x = input.TexCoordReflectionMap.x / input.TexCoordReflectionMap.w / 2.0f + 0.5f;
TexCoorReflection.y = -input.TexCoordReflectionMap.y / input.TexCoordReflectionMap.w / 2.0f + 0.5f;
float3 bumpNormalA = tex2D(BumpMapSamplerA, input.TexCoordBumpMap * 16 + windDelCoord) * 2 - 1;
float3 bumpNormalB = tex2D(BumpMapSamplerB, input.TexCoordBumpMap * 256 - windDelCoord * 2 ) * 2 - 1;
float2 moveA = bumpNormalA.xy * waveHeight * lerpDistanceA;
float2 moveB = bumpNormalB.xy * 0.2 * lerpDistanceB;
float2 TextCoordMove = moveA + moveB;
float2 TexCoordsMoveReflection = TexCoorReflection * 0.75f + TextCoordMove;
float4 reflectiveColor = tex2D(ReflectionMapSampler, TexCoordsMoveReflection) * 0.7f;
float3 NormalTS = tex2D( BumpMapSamplerA, input.TexCoordBumpMap * 16 + windDelCoord) * 2 - 1;
NormalTS = normalize( NormalTS);
float3 vReflectionTS = normalize( 2 * dot( input.ViewTS, NormalTS * 2 ) * NormalTS - input.ViewTS );
float fRdotL = dot( vReflectionTS, input.LightTS );
float4 cSpecular = saturate( pow( fRdotL, fSpecularExponent )) * cSpecularColor;
float light = clamp(dot(NormalTS, input.LightTS) * (reflectiveColor + cSpecular), 0, 1);
reflectiveColor += light * 0.9;
// refraction
float2 TexCoordRefraction;
TexCoordRefraction.x = input.TexCoordRefractionMap.x / input.TexCoordRefractionMap.w / 2.0f + 0.5f;
TexCoordRefraction.y = -input.TexCoordRefractionMap.y / input.TexCoordRefractionMap.w / 2.0f + 0.5f;
float2 TexCoordsMoveRefraction = TexCoordRefraction + TextCoordMove;// * lerpDistanceRefracion;
float4 refractiveColor = tex2D(RefractionMapSampler, TexCoordsMoveRefraction);
float3 eyeVector = normalize(ViewDir - input.Position3D);
float3 normalVector = float3(0,1,0);
float fNdotV = dot(eyeVector, normalVector);
float fFresnel = 1.0 - fNdotV;
// result
float4 resultColor = lerp(refractiveColor, reflectiveColor, fFresnel);
//resultColor.rgb *= (1.0 + resultColor.a * 1.2);
return resultColor;
}
technique Water
{
pass P0
{
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_3_0 WaterPS();
}
}
Unity 3D: Управление персонажем мышкой, вид с верху
Решаем задачу:
- Вид с верху;
- Персонаж (спрайт) должен перемещаться к месту клика мышью;
- Персонаж должен поворачиваться по направлению движения.
Решение:
using UnityEngine;
public class Player : MonoBehaviour
{
private Vector3 _positionMove;
private float _speed = 1f;
private void Start()
{
_positionMove = transform.position;
}
private void Update()
{
UpdateInput();
UpdateMove();
}
private void UpdateInput()
{
if (Input.GetMouseButtonDown(0))
{
_positionMove =
UnityEngine.Camera.main.ScreenToWorldPoint(Input.mousePosition);
_positionMove.z = 0;
}
}
private void UpdateMove()
{
float moveDelta = (_positionMove - transform.position).magnitude;
if (moveDelta <= _speed * Time.deltaTime)
{
transform.position = _positionMove;
return;
}
Vector3 moveDir = _positionMove - transform.position;
//
float angle = Mathf.Atan2(moveDir.y, moveDir.x) * Mathf.Rad2Deg - 90;
transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
//
moveDir.Normalize();
transform.position += moveDir * _speed * Time.deltaTime;
}
}
- Вид с верху;
- Персонаж (спрайт) должен перемещаться к месту клика мышью;
- Персонаж должен поворачиваться по направлению движения.
Решение:
using UnityEngine;
public class Player : MonoBehaviour
{
private Vector3 _positionMove;
private float _speed = 1f;
private void Start()
{
_positionMove = transform.position;
}
private void Update()
{
UpdateInput();
UpdateMove();
}
private void UpdateInput()
{
if (Input.GetMouseButtonDown(0))
{
_positionMove =
UnityEngine.Camera.main.ScreenToWorldPoint(Input.mousePosition);
_positionMove.z = 0;
}
}
private void UpdateMove()
{
float moveDelta = (_positionMove - transform.position).magnitude;
if (moveDelta <= _speed * Time.deltaTime)
{
transform.position = _positionMove;
return;
}
Vector3 moveDir = _positionMove - transform.position;
//
float angle = Mathf.Atan2(moveDir.y, moveDir.x) * Mathf.Rad2Deg - 90;
transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
//
moveDir.Normalize();
transform.position += moveDir * _speed * Time.deltaTime;
}
}
Unity 3D: FPS script
Скриптов для подсчета fps в Unity много. Способы подсчета основываются на различных исходных данных и принципах. На данный момент выбрал такой вариант:
using UnityEngine;
public class Fps : MonoBehaviour
{
private const float UpdateInterval = 1.0f;
private float _timeleft;
private float _lastTime;
private float _timeSpan;
private int _lastFrame;
private int _frames;
private float _fps;
void Update()
{
_timeleft += Time.deltaTime;
if (_timeleft > UpdateInterval)
{
_timeleft -= UpdateInterval;
_frames = Time.frameCount - _lastFrame;
_lastFrame = Time.frameCount;
_timeSpan = Time.realtimeSinceStartup - _lastTime;
_lastTime = Time.realtimeSinceStartup;
_fps = Mathf.RoundToInt(_frames/_timeSpan);
}
}
void OnGUI()
{
GUI.Box(new Rect(10, 10, 70, 25), string.Format("fps {0}", _fps));
}
}
using UnityEngine;
public class Fps : MonoBehaviour
{
private const float UpdateInterval = 1.0f;
private float _timeleft;
private float _lastTime;
private float _timeSpan;
private int _lastFrame;
private int _frames;
private float _fps;
void Update()
{
_timeleft += Time.deltaTime;
if (_timeleft > UpdateInterval)
{
_timeleft -= UpdateInterval;
_frames = Time.frameCount - _lastFrame;
_lastFrame = Time.frameCount;
_timeSpan = Time.realtimeSinceStartup - _lastTime;
_lastTime = Time.realtimeSinceStartup;
_fps = Mathf.RoundToInt(_frames/_timeSpan);
}
}
void OnGUI()
{
GUI.Box(new Rect(10, 10, 70, 25), string.Format("fps {0}", _fps));
}
}
пятница, 23 января 2015 г.
XNAdev.ru переехал на новый домен XNAdev-ru.1gb.ru
По бестолковым и не зависящим от нас обстоятельствам бывший сайт и форум XNAdev.ru переехал на новый домен - http://xnadev-ru.1gb.ru
Подписаться на:
Сообщения (Atom)







