Unity グラフィック2
メモしたのを書きなぐります
・公式マニュアルのサンプルで学ぶUnityのシェーダー
ポイントはソースのコメントを参照
1.ワールド空間でメッシュ法線を表示するシェーダー
Shader "Unlit/WorldSpaceNormals"
{
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// UnityObjectToWorldNormal ヘルパー関数を含むファイルを含みます
#include "UnityCG.cginc"
struct v2f {
half3 worldNormal : TEXCOORD0;
float4 pos : SV_POSITION;
};
v2f vert (float4 vertex : POSITION, float3 normal : NORMAL)
{
v2f o;
o.pos = UnityObjectToClipPos(vertex);
// ワールド空間の法線に変換
o.worldNormal = UnityObjectToWorldNormal(normal);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 c = 0;
// 法線は、xyz 成分をもつ 3D ベクトル ; 範囲は -1..1
// カラーとして表示するには、範囲を 0..1 にし、
// 赤、緑、青 の成分にします。
c.rgb = i.worldNormal*0.5+0.5;
return c;
}
ENDCG
}
}
}
参照サイト
2.ワールド空間法線を使った環境リフレクション
実装イメージ以下の図
Shader "Unlit/SkyReflection"
{
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
half3 worldRefl : TEXCOORD0;
float4 pos : SV_POSITION;
};
v2f vert(float4 vertex : POSITION, float3 normal : NORMAL)
{
v2f o;
o.pos = UnityObjectToClipPos(vertex);
// 頂点のワールド空間座標を取得
float3 worldPos = mul(unity_ObjectToWorld, vertex).xyz;
// ワールド空間のビューベクトルを取得
// UnityWorldSpaceViewDirは正規化されていないので正規化する
float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
// ワールド空間法線を取得
float3 worldNormal = UnityObjectToWorldNormal(normal);
// ワールド空間反射ベクトルを取得
// ビューベクトルは本来はカメラからサーフェイスへベクトルが向いているため内積の規則により反転させる
o.worldRefl = reflect(-worldViewDir, worldNormal);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
// キューブマップとベクトルを渡すことでワールド空間反射ベクトル方向の色を取得することができる
half4 skyData = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, i.worldRefl);
// キューブマップデータを実際のカラーにデコードします。
// Unityのキューブマップはエンコードされるため、実際の色を取り出すにはデコードしないといけない
half3 skyColor = DecodeHDR(skyData, unity_SpecCube0_HDR);
// 出力します
fixed4 c = 0;
c.rgb = skyColor;
return c;
}
ENDCG
}
}
}
参照サイト
3.法線マップを使った環境リフレクション
上の「ワールド空間法線を使った環境リフレクション」は頂点シェーダーで反射ベクトルを計算しているが法線マップを利用する場合は、ピクセルシェーダーで反射ベクトルを使用する必要がある。
法線マップの法線を利用する際は、接空間かワールド空間どちらかを基準にする必要がある。
今回の場合は、接空間を基準にしている。
ワールド空間を基準にしているパターンはこちらの17章を参照。
Shader "Unlit/SkyReflection Per Pixel"
{
Properties{
// 法線マップテクスチャ
_BumpMap("Normal Map", 2D) = "bump" {}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float3 worldPos : TEXCOORD0;
half3 tspace0 : TEXCOORD1;
half3 tspace1 : TEXCOORD2;
half3 tspace2 : TEXCOORD3;
float2 uv : TEXCOORD4;
float4 pos : SV_POSITION;
};
v2f vert(float4 vertex : POSITION, float3 normal : NORMAL, float4 tangent : TANGENT, float2 uv : TEXCOORD0)
{
v2f o;
o.pos = UnityObjectToClipPos(vertex);
o.worldPos = mul(unity_ObjectToWorld, vertex).xyz;
half3 wNormal = UnityObjectToWorldNormal(normal);
// ワールド空間の接線を取得
half3 wTangent = UnityObjectToWorldDir(tangent.xyz);
// プラットフォームごとの右手系/左手系の差異を吸収するもの。Unityで従法線を使用する際はこれが必要らしい
half tangentSign = tangent.w * unity_WorldTransformParams.w;
// 法線と接線を外積すると従法線を取得できる
half3 wBitangent = cross(wNormal, wTangent) * tangentSign;
// 接空間マトリクス行列を出力します
// 接空間は、X軸が接線、Y軸が従法線、Z軸が法線が基準となる
o.tspace0 = half3(wTangent.x, wBitangent.x, wNormal.x);
o.tspace1 = half3(wTangent.y, wBitangent.y, wNormal.y);
o.tspace2 = half3(wTangent.z, wBitangent.z, wNormal.z);
o.uv = uv;
return o;
}
sampler2D _BumpMap;
fixed4 frag(v2f i) : SV_Target
{
// 法線マップから法線を取得
// 法線マップは、法線の-1~1の値を0~1へ変換したものである。なので法線として利用するにはこの関数で-1~1に戻してやる必要がある
half3 tnormal = UnpackNormal(tex2D(_BumpMap, i.uv));
// 法線を接空間からワールド空間に変換します
half3 worldNormal;
worldNormal.x = dot(i.tspace0, tnormal);
worldNormal.y = dot(i.tspace1, tnormal);
worldNormal.z = dot(i.tspace2, tnormal);
half3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
half3 worldRefl = reflect(-worldViewDir, worldNormal);
half4 skyData = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, worldRefl);
half3 skyColor = DecodeHDR(skyData, unity_SpecCube0_HDR);
fixed4 c = 0;
c.rgb = skyColor;
return c;
}
ENDCG
}
}
}
参照サイト
4.ベースマップとオクルージョンマップ
Shader "Unlit/More Textures"
{
Properties{
_MainTex("Base texture", 2D) = "white" {}
_OcclusionMap("Occlusion", 2D) = "white" {}
_BumpMap("Normal Map", 2D) = "bump" {}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float3 worldPos : TEXCOORD0;
half3 tspace0 : TEXCOORD1;
half3 tspace1 : TEXCOORD2;
half3 tspace2 : TEXCOORD3;
float2 uv : TEXCOORD4;
float4 pos : SV_POSITION;
};
v2f vert(float4 vertex : POSITION, float3 normal : NORMAL, float4 tangent : TANGENT, float2 uv : TEXCOORD0)
{
v2f o;
o.pos = UnityObjectToClipPos(vertex);
o.worldPos = mul(unity_ObjectToWorld, vertex).xyz;
half3 wNormal = UnityObjectToWorldNormal(normal);
half3 wTangent = UnityObjectToWorldDir(tangent.xyz);
half tangentSign = tangent.w * unity_WorldTransformParams.w;
half3 wBitangent = cross(wNormal, wTangent) * tangentSign;
o.tspace0 = half3(wTangent.x, wBitangent.x, wNormal.x);
o.tspace1 = half3(wTangent.y, wBitangent.y, wNormal.y);
o.tspace2 = half3(wTangent.z, wBitangent.z, wNormal.z);
o.uv = uv;
return o;
}
sampler2D _MainTex;
sampler2D _OcclusionMap;
sampler2D _BumpMap;
fixed4 frag(v2f i) : SV_Target
{
half3 tnormal = UnpackNormal(tex2D(_BumpMap, i.uv));
half3 worldNormal;
worldNormal.x = dot(i.tspace0, tnormal);
worldNormal.y = dot(i.tspace1, tnormal);
worldNormal.z = dot(i.tspace2, tnormal);
half3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
half3 worldRefl = reflect(-worldViewDir, worldNormal);
half4 skyData = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, worldRefl);
half3 skyColor = DecodeHDR(skyData, unity_SpecCube0_HDR);
fixed4 c = 0;
c.rgb = skyColor;
// ベースマップから取得
fixed3 baseColor = tex2D(_MainTex, i.uv).rgb;
// オクルージョンマップから取得
fixed occlusion = tex2D(_OcclusionMap, i.uv).r;
c.rgb *= baseColor;
c.rgb *= occlusion;
return c;
}
ENDCG
}
}
}
参照サイト
5.プロシージャルな市松模様
Shader "Unlit/Checkerboard"
{
Properties
{
// 数値2~50の範囲
_Density("Density", Range(2,50)) = 30
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
float _Density;
v2f vert(float4 pos : POSITION, float2 uv : TEXCOORD0)
{
v2f o;
o.vertex = UnityObjectToClipPos(pos);
// uvは0~1の範囲であるが、0~_Densityになる
o.uv = uv * _Density;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
float2 c = i.uv;
// 小数値の整数部分を返す
c = floor(c) / 2;
// 小数値の小数部分を返す
float checker = frac(c.x + c.y) * 2;
return checker;
}
ENDCG
}
}
}
参照サイト
6.環境光を考慮したディフューズライティング
ちなみにここでいうと環境光とは、SkyboxではなくEnvironment LightingのSourceかGradientのこと。SkyBoxの色は反映されません。
Shader "Lit/Diffuse With Ambient"
{
Properties
{
[NoScaleOffset] _MainTex("Texture", 2D) = "white" {}
}
SubShader
{
Pass
{
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
struct v2f
{
float2 uv : TEXCOORD0;
fixed4 diff : COLOR0;
float4 vertex : SV_POSITION;
};
v2f vert(appdata_base v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
half3 worldNormal = UnityObjectToWorldNormal(v.normal);
// _WorldSpaceLightPos0は光源の座標
// ディレクショナルライトならflaot(ワールド空間方向ベクトル,0)
// 非ディレクショナルライトならflaot(ワールド空間座標,1)
half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
// _LightColor0はライトの色
o.diff = nl * _LightColor0;
// ShadeSH9の引数にワールド法線と1にすると環境光を取得できる
o.diff.rgb += ShadeSH9(half4(worldNormal,1));
return o;
}
sampler2D _MainTex;
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col *= i.diff;
return col;
}
ENDCG
}
}
}
参照サイト
7.キャストシャドウ
影を描画させるには、キャストシャドウ側でシャドウマップを生成する必要がある。
下記の画像だと、影がついていないがこれは、レシーブシャドウをレシーブするオブジェクトのためのシェーダーを作成していないためである。
レシーブシャドウのシェーダーに関しては後述する。
Shader "Lit/Shadow Casting"
{
SubShader
{
Pass
{
// メインのディレクショナルライト、頂点単位ライト、アンビエントライト、SH(球面調和)ライトがこのパスで実行される
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
fixed4 diff : COLOR0;
float4 vertex : SV_POSITION;
};
v2f vert(appdata_base v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
half3 worldNormal = UnityObjectToWorldNormal(v.normal);
o.diff.rgb = ShadeSH9(half4(worldNormal,1));
o.diff.a = 1;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
return i.diff;
}
ENDCG
}
Pass
{
// ShadowCasterのパスを記載すると、ライトからのデプス値をシャドウマップに描く
Tags {"LightMode" = "ShadowCaster"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// キャストシャドウ周りのシェーダーバリアントを有効にするために必要。なくてもいいみたいだが安全性を考慮して
#pragma multi_compile_shadowcaster
#include "UnityCG.cginc"
struct v2f {
// V2F_SHADOW_CASTERの実装中身は以下である
// float3 vec : TEXCOORD0;
// float4 pos : SV_POSITION;
V2F_SHADOW_CASTER;
};
v2f vert(appdata_base v)
{
v2f o;
// ライトからのデプス値をシャドウマップに描く際の定型処理
// TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)の実装中身は以下である
// o.vec = mul(unity_ObjectToWorld, v.vertex).xyz - _LightPositionRange.xyz;
// o.pos = UnityObjectToClipPos(v.vertex);
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
return o;
}
float4 frag(v2f i) : SV_Target
{
// ライトからのデプス値をシャドウマップに描く際の定型処理
// SHADOW_CASTER_FRAGMENT(i)の実装中身は以下である
// return UnityEncodeCubeShadowDepth (
// (length(i.vec) + unity_LightShadowBias.x) * _LightPositionRange.w);
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
}
参照サイト
8.レシーブシャドウ
上でキャストシャドウを実装していたので、今回はレシーブシャドウのシェーダーを作成する。
レシーブシャドウの作成したので影が描画されている。
Shader "Lit/ShadowsRecive"
{
Properties
{
[NoScaleOffset] _MainTex("Texture", 2D) = "white" {}
}
SubShader
{
Pass
{
Tags {"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
// shadow helper 関数とマクロ
#include "AutoLight.cginc"
struct v2f
{
float2 uv : TEXCOORD0;
// シャドウのデータを TEXCOORD1 に格納
// SHADOW_COORDS(1)の実装中身は以下である
// float4 _ShadowCoord : TEXCOORD1;
SHADOW_COORDS(1)
fixed3 diff : COLOR0;
fixed3 ambient : COLOR1;
float4 pos : SV_POSITION;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
// ライトをカメラ視点とした頂点のクリップ空間座標を再度算出し、フラグメントシェーダーに渡します。
// TRANSFER_SHADOW(o)の実装中身は以下である
// o._ShadowCoord = mul( unity_WorldToShadow[0], mul( unity_ObjectToWorld, v.vertex ) );
TRANSFER_SHADOW(o)
return o;
}
sampler2D _MainTex;
fixed4 frag(v2f i) : SV_Target
{
// カメラとライトの位置から遮蔽されているピクセルを判定し影をつける
// SHADOW_ATTENUATIONの実装中身は以下である(ディレクショナルライトの場合)
// inline fixed unitySampleShadow (float4 shadowCoord){
// // デプスバッファから深度比較結果を取得
// //_ShadowMapTexture:シャドウマップ(内部定義)
// fixed shadow = tex2Dproj(_ShadowMapTexture, float4(shadowCoord.xyz,1).r;
// // 深度比較結果から、影による減衰率を算出
// //_LightShadowData.r:影の強さ(内部定義)
// shadow = _LightShadowData.r + shadow * (1-_LightShadowData.r);
// return shadow;}
fixed shadow = SHADOW_ATTENUATION(i);
return shadow;
}
ENDCG
}
// 投影サポート
UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
}
}
参照サイト
9.Fogを適用させる
Shader "Custom/TextureCoordinates/Fog" {
Properties
{
_MainColor("Main Color", Color) = (1, 0, 0, 1)
}
SubShader{
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//fog がコンパイルされるのに必要です
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct vertexInput {
float4 vertex : POSITION;
};
struct fragmentInput {
float4 position : SV_POSITION;
// fog の量を渡すために使用されます。
// UNITY_FOG_COORDS(1)の実装の中身は以下である
// float1 fogCoord : TEXCOORD1;
UNITY_FOG_COORDS(1)
};
float4 _MainColor;
fragmentInput vert(vertexInput i) {
fragmentInput o;
o.position = UnityObjectToClipPos(i.vertex);
// フォグの処理に必要なマクロ
// このマクロ以降で、実行環境が低スペックだと頂点単位で処理、高スペックだとピクセル単位で処理を行う
// FogのMode別の処理も行っている
UNITY_TRANSFER_FOG(o,o.position);
return o;
}
fixed4 frag(fragmentInput i) : SV_Target {
fixed4 color = _MainColor;
// フォグの処理に必要なマクロ
// Fogで定義されるColorとシェーダ内の色とで色を算出する
UNITY_APPLY_FOG(i.fogCoord, color);
return color;
}
ENDCG
}
}
}
参照サイト
10.UVが0~1以外の箇所青くし、不適切なUVを見つける
Shader "Debug/UV 1" {
SubShader{
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
// もし第2UVを調べたいときは以下に変更すればよい
// float4 texcoord1 : TEXCOORD1;
};
struct v2f {
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
};
v2f vert(appdata v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = float4(v.texcoord.xy, 0, 0);
return o;
}
half4 frag(v2f i) : SV_Target {
half4 c = frac(i.uv);
// saturateは入力値を0~1に返すもの
// anyは0以外の場合、trueとなる
// つまり、uvが0~1以外だとtrueになり、そのピクセルは青くなる
// 例えばuvが1を超えていたらsaturateの結果は1なので、anyはtrueとなる
// 逆に、uvがマイナスであればsaturateの結果は0なので、anyはtrueとなる
if (any(saturate(i.uv) - i.uv))
c.b = 0.5;
return c;
}
ENDCG
}
}
}
参照サイト
11.頂点カラーを表示する
Shader "Debug/Vertex color" {
SubShader{
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
fixed4 color : COLOR;//頂点カラー
};
struct v2f {
float4 pos : SV_POSITION;
fixed4 color : COLOR;
};
v2f vert(appdata v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.color = v.color;
return o;
}
fixed4 frag(v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
参照サイト
12.法線の可視化
Shader "Debug/Normals" {
SubShader{
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
// 出力カラー値。テクスチャ以外の色データを設定
fixed4 color : COLOR;
};
v2f vert(appdata v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
// 法線は-1~1の範囲であるが、色はマイナスの値を取らないので0~1の範囲に変換する
o.color.xyz = v.normal * 0.5 + 0.5;
o.color.w = 1.0;
return o;
}
fixed4 frag(v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
参照サイト
13.接線の可視化
Shader "Debug/Tangents" {
SubShader{
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float4 tangent : TANGENT;//接線
};
struct v2f {
float4 pos : SV_POSITION;
fixed4 color : COLOR;
};
v2f vert(appdata v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
// 接線は-1~1の範囲であるが、色はマイナスの値を取らないので0~1の範囲に変換する
o.color = v.tangent * 0.5 + 0.5;
return o;
}
fixed4 frag(v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
参照サイト
14.従法線の可視化
Shader "Debug/Bitangents" {
SubShader{
Pass {
Fog { Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};
struct v2f {
float4 pos : SV_POSITION;
float4 color : COLOR;
};
v2f vert(appdata v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
// 外積を使用すると、互いに交わるベクトルの垂直ベクトルを取得できる
// v.tangent.wでプラットフォーム間の際を吸収している
float3 bitangent = cross(v.normal, v.tangent.xyz) * v.tangent.w;
// 従接線は-1~1の範囲であるが、色はマイナスの値を取らないので0~1の範囲に変換する
o.color.xyz = bitangent * 0.5 + 0.5;
o.color.w = 1.0;
return o;
}
fixed4 frag(v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
参照サイト
15._CameraDepthTextureから深度値を取得し、深度値のポストエフェクトかける
//カメラにアタッチ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DepthTexture : MonoBehaviour
{
[SerializeField]
private Shader _shader;
private Material _material;
void Start()
{
// PCやコンソールのみ以外で、シェーダーでカメラからの深度テクスチャを参照する際はこの設定が必要
// またShadow TypeがNo Shadowsのときに、この設定しておかないと深度テクスチャをシェーダで参照できない
GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;
_material = new Material(_shader);
}
// 全てのレンダリングが完了した後に呼ばれる。
private void OnRenderImage(RenderTexture source, RenderTexture dest)
{
// sourceは、全てのレンダリングが完了した際のRTで、それをdestにShaderを適用させてそれを画面に表示させる
Graphics.Blit(source, dest, _material);
}
}
Shader "ShowDepthTexture"
{
SubShader
{
Cull Off
ZTest Always
ZWrite Off
//Tags { "RenderType" = "Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _CameraDepthTexture;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
// Near プレーンから Far プレーンまでのデプス値を取得
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
/* ただ、上のdepthは1~0の範囲。この値は非線形なので線形形の0~1へ変換します。
非線形だと、NearClip が 0, FarClip が 10 だとして、Z = 5 の位置にあるポリゴンの深度(Z 値) は 0.5 になりません。
これは非常に直感的ではないため、ふつうはを正規化します。*/
depth = Linear01Depth(depth);
return depth;
}
ENDCG
}
}
}
_CameraDepthTextureと_LastCameraDepthTextureの違い以下である
_CameraDepthTexture は、常にカメラの最初の深度テクスチャを示します。反対に _LastCameraDepthTexture は、カメラに最後にレンダリングされた深度テクスチャを示します。例えば、スクリプトで解像度が半分の深度テクスチャを 2番目のカメラを使ってレンダリングし、ポストプロセスシェーダーに利用する場合に役に立ちます。
深度テクスチャの質が悪くなる可能性があるので、ZWrite Offにしたほうが良い
ケースによっては深度テクスチャはネイティブの Z バッファから直接取得されている場合があります。もし深度テクスチャで画像の乱れがある場合、それを使用するシェーダーが Z バッファに 書き込まないように してください (ZWrite Off を使用してください)。
また、ポストエフェクトを実装する際は、プラットフォーム間のレンダリングの違いを知っておいたほうがよい
参照サイト、参照サイト、参照サイト、参照サイト
16._CameraDepthNormalsTextureからビュー法線を取得し、ビュー法線のポストエフェクトかける
//カメラにアタッチ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DepthNormalTexture : MonoBehaviour
{
[SerializeField]
private Shader _shader;
private Material _material;
void Start()
{
// _CameraDepthNormalsTextureを生成するようにする設定。これシェーダーで使用する
// _CameraDepthNormalsTextureは、カメラからの深度とビュー空間の法線が入ったテクスチャである
GetComponent<Camera>().depthTextureMode |= DepthTextureMode.DepthNormals;
_material = new Material(_shader);
}
// 全てのレンダリングが完了した後に呼ばれる。
private void OnRenderImage(RenderTexture source, RenderTexture dest)
{
// sourceは、全てのレンダリングが完了した際のRTで、それをdestにShaderを適用させてそれを画面に表示させる
Graphics.Blit(source, dest, _material);
}
}
Shader "DepthNormalTexture"
{
SubShader
{
Cull Off
ZTest Always
ZWrite Off
Tags{ "RenderType" = "Opaque" }
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _CameraDepthNormalsTexture;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
// _CameraDepthNormalsTextureからサンプリング
float4 cdn = tex2D(_CameraDepthNormalsTexture, i.uv);
// ビュー空間の法線を取得する
// Z軸にマイナスを掛けて軸を反転させる
float3 n = DecodeViewNormalStereo(cdn) * float3(1.0, 1.0, -1.0);
return float4(n, 1.0);
}
ENDHLSL
}
}
}
もし、Z軸にマイナスを掛けないとこのようになる。
カメラの後ろが正の方向になるのでこのようになる。
参照サイト、参照サイト
17._CameraDepthNormalsTextureからビュー法線を取得し、アウトラインのポストエフェクトをかける
適用前
適用後
//カメラにアタッチ
using UnityEngine;
[ExecuteAlways]
public class Example : MonoBehaviour
{
[SerializeField, Range(0.5f, 1.0f)]
private float _thickness;
[SerializeField, Range(0.1f, 3.0f)]
private float _threshold;
[SerializeField]
private Shader _shader;
private Material _material;
void Start()
{
// _CameraDepthNormalsTextureを生成するようにする設定。これシェーダーで使用する
// _CameraDepthNormalsTextureは、カメラからの深度とビュー空間の法線が入ったテクスチャである
GetComponent<Camera>().depthTextureMode |= DepthTextureMode.DepthNormals;
_material = new Material(_shader);
}
// 全てのレンダリングが完了した後に呼ばれる。
private void OnRenderImage(RenderTexture source, RenderTexture dest)
{
_material.SetFloat("_Thickness", _thickness);
_material.SetFloat("_Threshold", _threshold);
// sourceは、全てのレンダリングが完了した際のRTで、それをdestにShaderを適用させてそれを画面に表示させる
Graphics.Blit(source, dest, _material);
}
}
Shader "Unlit/NormalOutline"
{ Properties
{
_Thickness("Thickness", float) = 1.0
_Threshold("Threshold", float) = 0.0
}
SubShader
{
Cull Off
ZTest Always
ZWrite Off
Tags{ "RenderType" = "Opaque" }
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _CameraDepthNormalsTexture;
float4 _CameraDepthNormalsTexture_TexelSize;
float _Thickness;
float _Threshold;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
float3 sampleNormal(float2 uv)
{
// _CameraDepthNormalsTextureからサンプリング
float4 cdn = tex2D(_CameraDepthNormalsTexture, uv);
// ビュー空間の法線を取得する
float3 n = DecodeViewNormalStereo(cdn);
return n;
}
/* ソーべルフィルターでエッジ検出
近隣の法線をサンプリングし、法線同士で差が大きければエッジを検出する
*/
fixed4 frag(v2f i) : SV_Target
{
// _CameraDepthNormalsTexture_TexelSize.xは1.0/横の解像度。1ピクセルの横のサイズ
float diffU = _CameraDepthNormalsTexture_TexelSize.x * _Thickness;
// _CameraDepthNormalsTexture_TexelSize.yは1.0/縦の解像度。1ピクセルの縦のサイズ
float diffV = _CameraDepthNormalsTexture_TexelSize.y * _Thickness;
// 近隣の法線をサンプリング
half3 norm00 = sampleNormal(i.uv + half2(-diffU, -diffV));
half3 norm01 = sampleNormal(i.uv + half2(-diffU, 0.0));
half3 norm02 = sampleNormal(i.uv + half2(-diffU, diffV));
half3 norm10 = sampleNormal(i.uv + half2(0.0, -diffV));
half3 norm12 = sampleNormal(i.uv + half2(0.0, diffV));
half3 norm20 = sampleNormal(i.uv + half2(diffU, -diffV));
half3 norm21 = sampleNormal(i.uv + half2(diffU, 0.0));
half3 norm22 = sampleNormal(i.uv + half2(diffU, diffV));
// 水平方向のコンボリューション行列適用後の法線を求める
half3 horizontalValue = 0;
horizontalValue += norm00 * -1.0;
horizontalValue += norm01 * -2.0;
horizontalValue += norm02 * -1.0;
horizontalValue += norm20;
horizontalValue += norm21 * 2.0;
horizontalValue += norm22;
// 垂直方向のコンボリューション行列適用後の法線を求める
half3 verticalValue = 0;
verticalValue += norm00;
verticalValue += norm10 * 2.0;
verticalValue += norm20;
verticalValue += norm02 * -1.0;
verticalValue += norm12 * -2.0;
verticalValue += norm22 * -1.0;
// この値が大きく正の方向を表す部分がアウトライン
half3 outlineValues = verticalValue * verticalValue + horizontalValue * horizontalValue;
half outlineValue = outlineValues.x + outlineValues.y + outlineValues.z;
return outlineValue - _Threshold > 0 ? 0 : 1;
}
ENDHLSL
}
}
}
参照サイト、参照サイト
18._CameraMotionVectorsTextureからモーションベクターを取得し、モーションブラーのポストエフェクトをかける
//カメラにアタッチ
using UnityEngine;
public class Test2 : MonoBehaviour
{
[SerializeField]
private Shader _shader;
private Material _material;
void Start()
{
// _CameraMotionVectorsTextureを生成するようにする設定。これシェーダーで使用する。
// _CameraMotionVectorsTextureは、その画素が前のフレームから比較してどれだけスクリーン上を動いたかを表す値です。
// スクリーン平面上の 2 次元のベクトルとして表されます。
GetComponent<Camera>().depthTextureMode |= DepthTextureMode.MotionVectors;
_material = new Material(_shader);
}
// 全てのレンダリングが完了した後に呼ばれる。
private void OnRenderImage(RenderTexture source, RenderTexture dest)
{
// sourceは、全てのレンダリングが完了した際のRTで、それをdestにShaderを適用させてそれを画面に表示させる
Graphics.Blit(source, dest, _material);
}
}
Shader "Hidden/MotionBlur"
{
Properties
{
[HideInInspector]
_MainTex ("Texture", 2D) = "white" {}
_BlurPower ("BlurPower", Range(0, 5)) = 1.5
}
SubShader
{
Cull Off
ZWrite Off
ZTest Always
Pass
{
CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert_img
#pragma fragment frag
sampler2D _MainTex;
sampler2D _CameraMotionVectorsTexture;
float _BlurPower;
float4 frag(v2f_img input) : SV_Target
{
float4 color = 0;
float2 motion = tex2D(_CameraMotionVectorsTexture, input.uv).xy;
for (int i = 0; i < 10; i++)
{
color += tex2D(_MainTex, input.uv - motion * i / 10 *_BlurPower);
}
return color / 10;
}
ENDCG
}
}
}
・Scale Factor
3DCGでツールで作成したモデルに対して、Scale Factorをかけてモデルの大きさを調整する。
例えば、Mayaのscaleのデフォルト値はセンチメートル単位で、Unityのscaleはメートルが単位であるので、Mayaのscaleと一致させるには、Unity側でScale Factorを0.01にすればMayaのscaleと同じになる。
以下が拡張子(fbx、mb...)によって設定すべきScale Factorの値。拡張子にあわせてこちらの値を設定すれば3DCGツールで作成したモデルのScaleとUnityのScaleが一致する。
ファイル形式 | デフォルト値 |
---|---|
.fbx, .max, .jas, .c4d | 0.01 |
.mb, .ma, .lxo, .dxf, .blend, .dae | 1 |
.3ds | 0.1 |
Scale Factorが0.01
Scale Factorが0.05
参考サイト、参考サイト
・Convert Units
これをチェック入れて、Scale Factorに1を入れると拡張子にUnityが正しいScaleになるように自動調整してくれる
拡張子が、dae、fbx、objのモデルを用意して実験してみた。
三つのScale Factorが1で、Convert Unitsにチェック入れるとUnityが勝手に拡張子に合わせて変換してくれる。
画像から分かる通り、拡張子が異なる三つのモデルがすべて同じ大きさであることが分かる
dae
fbx
obj
参考サイト
・Bake Axis Conversion
Unity とは異なる軸システムを使用しているモデルをインポートするときに、軸変換の結果をアプリケーションのアセットデータ (例えば、頂点やアニメーションのデータ) に直接ベイクします。このプロパティを無効にすると、ランタイムにルートゲームオブジェクトの Transform コンポーネントを補正して、軸変換のシミュレーションを行います。
例えば、UnityとBlenderは軸が違うので、Unity基準にしたい場合はこれを有効にする。
軸変換のシュミレーションを行うと負荷がかかると思うので、使用している3DCGツールの軸が、Unityと違う場合はこちらをチェックしたほうが良さそう。
ただ、3DCG側で軸の設定できるから3DCG側で設定したほうが良さそう。また、Bake Axis Conversionをチェックにするとアセットデータをベイクするするので容量も増えそうだし、3DCG側で軸設定したほうが良いと思う。
一応、軸が変わるのかblenderで作成したモデルで実験してみた
Bake Axis Conversionオフ
Bake Axis Conversionオン
参考サイト、参考サイト、参考サイト
・Import Blendshapes
Blend Shape使用するときに必要な設定。
SkinnedMeshRenderer のBlendShapesの値をいじるとアニメーションが変化する。
ただ、Blend Shapeを使用すると頂点の数に応じて容量が増えていく。
参考サイト、参考サイト、参考サイト
・Import Visibility
これをチェックすると、3DCGツールのオブジェクトを表示・非表示する設定をUnityに反映させる。
試しに実験してみた。
Blenderで、可視性設定をオフにしてオブジェクトを非表示にし、エクスポート。
Import Visibilityをオフにすると、モデルは表示され、
Import Visibilityをオンにすると、モデルが非表示で、MeshRenderがオフになっていることが分かる。
Import Visibilityオフ
Import Visibilityオン
参考サイト、参考サイト
・Import Cameras
これをチェックにすると 3DCGツールのカメラの設定をUnityに反映させる。
試しに実験してみた。
Blenderで、カメラの焦点距離を14にし、エクスポート。
14で反映されていることが分かる。
Import Camerasオン
なお、Unityで対応しているサポートは以下である
参考サイト
・Import Lights
これをチェックにすると 3DCGツールのライトの設定をUnityに反映させる。
試しに実験してみた。
Blenderで、ライトをディレクショナルライト、カラーを赤、強さを1500にし、エクスポート。
ディレクショナルライト、colorが赤、Intensityが1500で反映されていることが分かる
Import Lightsオン
なお、Unityで対応しているサポートは以下である
参照サイト
・Preserve Hierarchy
a.fbxにモデルX
b.fbxにモデルXとアニメーション
これらをUnityでインポートするとアニメーションが壊れるっぽい。なので、Preserve Hierarchyをオンにすると解消できるっぽい。
正直よくわからない。
以下公式ドキュメント抜粋。
これを有効にすると、このモデルにルートが 1 つしかない場合でも、必ず明示的なプレハブルートを作成します。 通常、FBX インポーターは最適化の方法としてモデルから空のルートノードを取り除きます。 ただし、同じ階層の一部を含む複数の FBX ファイルがある場合は、このオプションを使用して元の階層を維持することができます。
例えば、file1.fbx にはリグとメッシュが含まれ、file2.fbx にも同じリグが含まれていますが、そのメッシュのアニメーションのみが含まれています。 このオプションを有効にせずに file2.fbx をインポートすると、Unity はルートノードを取り除くため階層が一致せず、アニメーションは壊れます。
・Sort Hierarchy By Name
階層内でゲームオブジェクトをアルファベット順に並べることができます。
このプロパティを無効にすると、FBX ファイルで定義された階層の順序が維持されます。
参照サイト
・Legacy Blend Shape Normals
カスタム法線とシェイプキー法線が競合して、ブレンドシェイプを使用して表情が変わった際に陰影がおかしくなる問題を解決できる項目。
チェックにすると解決できる。
ただ、Blend Shape Normalsでもこの問題を解決できるのでわざわざLegacyを使用する必要なさそう
参照サイト、参照サイト
・Swap UVs
メインのUVとライトマップ用のUVが逆に読み込まれてしまっている場合に有効にするみたい。
また、公式ドキュメントによると
これを有効にすると、メッシュの UV チャンネルを入れ替えます。ディフューズテクスチャがライトマップからの UV を使用している場合は、この設定を使用してください。Unity は最大 8 つの UV チャンネルをサポートしますが、すべての 3D アプリケーションが 2 つ以上の UV をエクスポートするわけではありません。
・Material Creation Mode
3DCGツールで、マテリアルをfbxファイルに含ませるかどうか
実際に実験してみた。
Blenderでマテリアルをモデルにつけてエクスポート
Noneは、マテリアルを含ませない。
Standard(Legacy)、Import via MaterialDescriptionは、マテリアルを含ませる。
なお、Standard(Legacy)、Import via MaterialDescriptionは、Import via MaterialDescriptionのほうが3DCGで作成したマテリアルより正確な結果が得られ、より幅広いマテリアルタイプをサポートしているのでこっちを利用したほうが良い。
具体的なサポートを公式ドキュメントから抜粋。
これらのデフォルトの実装では、マテリアルのインポートの扱いが ImportStandard モードとは異なり、以下のような改良が加えられています。
・より多くのマテリアルタイプをサポートしています。例えば、オートデスクの Arnold や Interactive、Physical、Unity の HDRP Materials など。
・エミッシブマテリアル をサポートします。
・ディフューズテクスチャが設定されている場合、ディフューズ色は無視されます (これは Autodesk® Maya® と Autodesk® 3ds Max® での動作と同じです)。
・バンプファクター、エミッシブカラー、エミッシブファクターを考慮します。
FBX ファイルで定義されている場合、エミッシブカラーのアニメーションをインポートします。
ノート: 3ds Max はエミッシブカラーのアニメーションをエクスポートしません。そのため、Unity はそれをインポートすることができません。
・透明なマテリアルを完全に透明なものとしてインポートします。従来のシステムでは、完全に不透明なものとしてインポートします。
またImport via MaterialDescriptionはAssetPostProcessor.OnPreprocessMaterialDescription のアセットインポーターを使用してインポーターした際の設定をスクリプトから制御できる。
参照サイト
・sRGB Albedo Colors
ガンマ空間のアルベドカラーを使用するには、このオプションを有効にします。
リニアの色空間 を使用しているプロジェクトではこれを無効にしてください。
なお、Material Creation ModeがStandard(Legacy)のみ表示される。
参照サイト
・Location
マテリアルとテクスチャへのアクセス方法を定義します。これらのオプションのどれを選択するかによって、設定可能なプロパティが変わります。
設定できるプロパティが変わるだけでなく、Use Embedded Materialsのほうは、3DCGで作成したマテリアルが表示されている。
①Use Embedded Materials
②Use External Materials (Legacy)
・ MaterialsとTextures
これらのボタンをクリックすると、そのマテリアルとテクスチャをエクスポートできる。
ただマテリアルやテクスチャーがfbxファイルに含まれていないと非活性になる
参照サイト
・Naming とSearch
3DCGツールで作成したマテリアルの一覧を表示する際に必要な設定項目。
この二つの設定によってマテリアルがNoneとなったりするので調整する。
Search and Remapボタンを押下すると一覧を表示できる。
Naming
Search
参照サイト
・SketchUpのImport Settings
SketchUp は建築モデリングによく使用されるソフトウェアです。 Unity は SketchUp ファイルを直接読み込み、以下の SketchUp 機能をサポートします
参照サイト
・SpeedTree の Import Settings
SpeedTreeのImport周りを設定する。
参照サイト
・可変メッシュ
Unityでは、通常のメッシュの他に、可変 (deformarable) メッシュもサポートしています。
可変メッシュで スケルタルアニメーション 、ラグドール、モーフターゲットアニメーション 、Cloth コンポーネント を使用できる。
通常のメッシュは Mesh Renderer コンポーネントで、可変メッシュは Skinned Mesh Renderer コンポーネントで描画する
参照サイト
・メッシュ
通常メッシュは以下のデータを持っている。
①頂点
②トポロジー
③インデックス
可変メッシュだとこれらに加えて以下のデータを持っている。
①ブレンドシェイプ
②バインドポーズ
参照サイト
・頂点
頂点データの要素は、頂点属性 と呼ばれる。
各頂点は以下の属性を持っている。
C# では、Unity はVertexAttribute enum で利用可能な頂点属性を表します。Mesh クラスのインスタンスが指定された頂点属性を持つかどうかは、Mesh.HasVertexAttribute 関数で確認することができます。
①位置(Position)
この頂点属性はすべてのメッシュに必要である。
Mesh クラスで、位置(Position)にアクセスする最も簡単な方法は、Mesh.GetVertices とMesh.SetVertices を使うことです。また、Unity はこのデータを Mesh.vertices に保存しますが、この古いプロパティは効率と使い勝手があまり良くありません。
②法線(Normal)
この頂点属性は必須ではありません。
Mesh クラスで、法線にアクセスする最も簡単な方法は、Mesh.GetNormals とMesh.SetNormals を使うことです。また、Unity はこのデータをMesh.normals に保存しますが、この古いプロパティは効率と使い勝手があまり良くありません。
③接線(Tangent)
Unity では、頂点接線は、追加のデータとともに 4 成分のベクトルとして保存されます。ベクトルの x,y,z 成分は接線を表し、ベクトルの w 成分はその 向き を表します。Unity では、w の値を使用して、接線と法線のクロス積である 従法線 を計算します。
Unity は、法線マッピングに接線値と従法線値を使用します。
この頂点属性は必須ではありません。
④テクスチャ座標 (UV)
メッシュは最大 8 つの テクスチャ座標 を持つことができます。
UV チャンネルは一般に、最初のチャンネルを “UV0”、2 番目のチャンネルを “UV1”、以降 “UV7” まで同じ要領で呼ばれます。チャンネルはそれぞれ、シェーダーセマンティクス TEXCOORD0、TEXCOORD1 以降 TEXCOORD7 までにマップされます。
デフォルトでは、Unity は最初のチャンネル (UV0) を使用して、ディフューズマップやスペキュラーマップなどの通常テクスチャの UV を保存します。2 番目のチャンネル (UV1) にはベイクされたライトマップ UV を保存し、3 番目のチャンネル (UV2) にはリアルタイムのライトマップ UV の入力データを保存できます。
ライトマップ UV と Unity がこれらのチャンネルをどのように使用するかの詳細については、ライトマップ UV を参照してください。
⑤頂点カラー(Color)
この色は、メッシュが使用するテクスチャとは無関係に存在します。
この頂点属性は必須ではありません。
Mesh クラスで、頂点カラーにアクセスする最も簡単な方法は、Mesh.GetColors とMesh.SetColors を使うことです。また、Unity はこのデータをMesh.colors に保存しますが、この古いプロパティは効率と使い勝手があまり良くありません。
⑥ブレンドインデックスとボーンウェイト(スキンされたメッシュのみ)
スキンされたメッシュでは、 ブレンドインデックス によってどのボーンが頂点に影響を与えるかを示し、ボーンウェイト によってそれらのボーンが頂点に与える影響の強さを表します。
Unity では、これらの頂点属性は一緒に保存されます。
Unity はブレンドインデックスとボーンウェイトを使用して、スケルトンの動きに基づいてスキンしたメッシュを変形させます。詳細は、Skinned Mesh Renderer を参照してください。
これらの頂点属性は、スキンされたメッシュに必須です。
以前は、Unity は 1 つの頂点に影響を与えるボーンを最大 4 つまでしか許可しませんでした。このデータは Mesh.boneWeights 配列の BoneWeight 構造体に格納されていました。現在、Unity では頂点に影響を与えるボーンを最大 256 個まで使用できます。このデータは BoneWeight1 構造体に格納され、Mesh.GetAllBoneWeights とMesh.SetBoneWeights を使ってアクセスすることができます。
参照サイト
・トポロジー
Unity は以下のメッシュトポロジーをサポートします。
Triangle
Quad
Lines
LineStrip
Points
Points トポロジーは面を作成しません。その代わり、Unity は各位置に 1 つの点を描画します。他のすべてのメッシュトポロジーは、面またはエッジ (辺) を作成するために複数のインデックスを使用します。
Mesh クラスで、Mesh.GetTopology によってトポロジーを取得し、それを Mesh.SetIndices のパラメーターとして設定しできます。
サポートされるメッシュトポロジーの詳細は、MeshTopology enum のドキュメントを参照してください。
他のモデリング技術 (NURBS や NURMS/Subdivision Surfaces モデリングなど) を使用するメッシュは、Unity で使用する前に、モデリングソフトウェアに適応する形式に変換する必要があります。
参照サイト
・インデックス
Unity はインデックスを使用して、頂点の位置を面に接続します。各面を作るインデックスの数は、メッシュのトポロジーに依存します。
Mesh クラスで、Mesh.GetIndices でこのデータを取得し、Mesh.SetIndices で設定します。また、Unity はこのデータを Mesh.triangles に保存しますが、この古いプロパティは効率性と使い勝手があまり良くありません。
インデックス配列における各グループの頂点の順序は、巻き順 と呼ばれます。 Unity は時計回りの巻き順で、インデックスが時計回りにつながっている面を表向きと見なします。デフォルトでは、正面を向いたポリゴンをレンダリングし、背面を向いたポリゴンをカリングします。
参照サイト
・ブレンドシェイプ
ブレンドシェイプのデータはブレンドシェイプの頂点として保存されます。すべてのメッシュ頂点に対してブレンドシェイプ頂点があるわけではなく、メッシュ頂点が変形した場合にのみ対応するブレンドシェイプ頂点があります。
Meshクラスでは、Mesh.GetBlendShapeBuffer でブレンドシェイプの頂点データにアクセスできます。これは GPU 上のブレンドシェイプ頂点データへのアクセスを提供する GraphicsBuffer を返します。このメソッドでは、2 つの異なるバッファを選択できます。1 つはブレンドシェイプごとにデータを並べるもので、もう 1 つはメッシュ頂点ごとにデータを並べるものです。バッファの選択によって、インデッ クス値の意味とバッファ内のデータのレイアウトが決まります。バッファレイアウトの詳細については、BlendShapeBufferLayout を参照してください。
このデータは必須ではありません
参照サイト
・バインドポーズ
スキンされたメッシュでは、ボーンの バインドポーズ は、スケルトンがそのデフォルトの位置 (バインドポーズとも呼ばれる) にあるときのボーンの位置を表します。
Mesh クラスで、このデータを Mesh.bindposes で取得設定することができます。各要素には、同じインデックスを持つボーンのデータが含まれています。
このデータは、スキンされたメッシュに必要なデータです。
参照サイト
・メッシュの情報
メッシュの情報をUnity側で見れる。
頂点属性の一覧、各頂点属性のデータ型とそのバイト数、頂点数とその容量、インデックス数とその容量、ボーンの数、BlendWeightとBlendIndicesのデータ型とそのバイト数、ブレンドシェイプの一覧、Bounds CenterとBounds Size、Read/Writeの有無(Read/Write Enabled チェックボックスで設定できる)
参照サイト
・メッシュプレビュー
メッシュの様々な状態を視覚して確認できる。
①Shaded
ライトのシェーディングを視覚化する
②UV Checker
メッシュの UV マップがどのようにテクスチャを適用するかを視覚化する
③UV Layout
UVLayoutを視覚化する。
④Vertex Color
頂点カラーを視覚化する。
⑤Normals
法線を視覚する。
⑦Tangents
接線を視覚する。
⑧Blendshapes
ブレンドシェイプの一覧を表示できる。
参照サイト
・Mesh RendererのCast Shadows
影の設定する。
①On
メッシュが影を落とす。
FrameDebuggerを見ると、12ドローコールで、2draw callsと表示されている。
②Off
メッシュが影を落とさない。
FrameDebuggerを見ると、12ドローコールで、2draw callsと表示されていない。
③Two Sided
表面、背面のカリングをオフにする。
メッシュの一部が隙間がある場合、隙間の中は裏面はカリングされているので不自然な影が描画される。
この不自然な影をなくすためにTwo Sidedに設定する。
ただ、Enlighten (非推奨) とプログレッシブライトマッパーはこれをサポートしていない。
詳しい内容はこちらを参照。
FrameDebuggerを見ると、14ドローコールで、2draw callsと表示されていない。
④Shadows Only
影は表示されるが、メッシュは表示されない。
FrameDebuggerを見ると、12ドローコールで、2draw callsと表示されていない。(不透明なオブジェクトのPassでも)
参照サイト
・Mesh RendererのStatic Shadow Caster
公式ドキュメントに載っていない。
参照サイト
・Mesh RendererのContribute Global Illumination
チェックすると、GIの対象にする。
①Contribute Global Illuminationオフ
②Contribute Global Illuminationオン
参照サイト参照サイト
・Mesh RendererのReceive Global Illumination
ライトマップを使用するか、ライトプローブを使用するかの設定
ライトマップだとオブジェクトが動くとGIがリアルタイムに反映されないが、ライトプローブだとリアルタイムで反映される。
①Lightmaps
②Light Probes
参照サイト
・Prioritize illumination
シーン内の遠くのオブジェクトまで間接光を放射したり、シャドウを落としたい場合に、有効にすると良いらしい。
ただ、Contribute GIでRealtime Global Illumination オンの時表示される。
一応、間接光を受けるオブジェクト離して実験してみたが変わらなかった。
①Prioritize illuminationオフ
②Prioritize illuminationオン
参照サイト、参照サイト
・Skinned Mesh Renderer の可視性に関するトラブルシューティング
UnityはメッシュのBounds(バウンディングボックス)がカメラの外にあるとその外にあるメッシュを描画しない。
こちらの画像は、バウンディングボックスを赤色で描画しているが、Capsuleオブジェクトの一部のメッシュが描画されていないことが分かる。
これは、一部のバウンディングボックスがカメラに映っていないためである。
MeshRenderのメッシュの場合、メッシュが可変ではないので表示されるべき時に表示されないことということは基本的にはありえない。
Skinned Mesh Renderer の場合は、インポート時に存在するすべてのアニメーションを考慮して最大のバウンディングボリュームを計算し、この値を使用して可視性を決定する。ただし、インポート後に発生する以下の状況では、頂点やボーンが既知の最大Boundsの外に押し出される可能性があります。
・アニメーションを追加する場合
・ランタイムにスクリプトからボーンの位置を変更する場合
・頂点位置を変更する頂点シェーダーを使用する場合
・ラグドールを使用する場合
頂点やボーンが境界の外に押し出されると、Unity がメッシュの可視性を正しく判断できず、表示されるべき時に表示されないことがあります。
このような場合は、以下のいずれかの解決策で問題を解決できます。
①Skinned Mesh Renderer のBoundsを修正する
パフォーマンスの向上のために、可能であればこのオプションを使用したほうが良い。
②Skinned Mesh Renderer のUpdate When Offscreen を有効
これにより、Unity はメッシュが表示されないときでも、常にメッシュの境界を計算し続けます。パフォーマンスがあまり気にならない場合や、バウンディングボリュームのサイズを予測できない場合 (ラグドールを使用する場合など) にこのオプションを使用する。
参照サイト、参照サイト、参照サイト
・Skinned Mesh Renderer のBounds
Boundsを使用することでバウンディングボックスを調整し、メッシュの可視を調整できる。
Centerでバウンディングボックスの位置を調整。
Extentでバウンディングボックスの大きさを調整できる。
参照サイト、参照サイト
・Skinned Mesh Renderer のBlendShapes
メッシュに定義された ブレンドシェイプ に使用するウェイト値を調整できる。
スクリプトから調整できるが別途まとめる。
参照サイト
・C#でメッシュを生成
using UnityEngine;
public class QuadCreator : MonoBehaviour
{
public float width = 1;
public float height = 1;
public void Start()
{
MeshRenderer meshRenderer = gameObject.AddComponent<MeshRenderer>();
//マテリアルをメッシュレンダラーにアタッチ
meshRenderer.sharedMaterial = new Material(Shader.Find("Universal Render Pipeline/Lit"));
MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>();
Mesh mesh = new Mesh();
Vector3[] vertices = new Vector3[4]
{
new Vector3(0, 0, 0),
new Vector3(width, 0, 0),
new Vector3(0, height, 0),
new Vector3(width, height, 0)
};
//頂点の座標を設定
mesh.vertices = vertices;
int[] tris = new int[6]
{
// 左下の三角形
0, 2, 1,
// 右上の三角形
2, 3, 1
};
//頂点インデックスを設定
mesh.triangles = tris;
Vector3[] normals = new Vector3[4]
{
Vector3.forward,
-Vector3.forward,
-Vector3.forward,
Vector3.forward
};
//頂点の法線を設定
mesh.normals = normals;
Vector2[] uv = new Vector2[4]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
//頂点のuvを設定(テクスチャを使用していないので意味なし)
mesh.uv = uv;
meshFilter.mesh = mesh;
}
}
・メッシュのLOD設定
メッシュのLODは2つの方法で設定できる。
LODは最大8まで設定できる。
①3DCGで設定
3DCG側で、
ExampleMeshName_LOD0
ExampleMeshName_LOD1
ExampleMeshName_LOD2
のように名前を指定して、UnityにインポートすればLOD設定できる
②Unity側でLOD Group設定
参照サイト、参照サイト
・LODのLod Bias
Lod Biasを調整して、LODを変える。
参照サイト
・LOD GroupのFade Mode
LODが切り替わったときの切り替わりの挙動を変更できる。
①None
いきなりLODが変わるような挙動をする。
②Cross Fade、Animate Cross-fadingオフ
LODの切り替わりが徐々に切り替わっている
Cross-fadingオフにすると距離によって徐々に切り替わる
③Cross Fade、Animate Cross-fadingオン
LODの切り替わりが徐々に切り替わっている
Cross-fadingオンにすると時間によって切り替わる
時間はデフォルトでは、0.5sでLODGroup.crossFadeAnimationDuration = 3.0f;で時間を変更できる。
ただ、Cross FadeにするとNoneに比べて描画負荷が2倍になるので注意。
参照サイト、参照動画
・LOD Cross FadeとLOD Cross Fade Dithering Type
LOD Cross Fadeをオンにすると、LOD GroupのFade ModeのCross Fadeを使用できる。
LOD Cross Fade Dithering Typeは、Cross Fadeの方法を決定する。
Blue Noise、Bayer Matrixの2種類ある。
Blue Noiseの方がBayer Matrixより綺麗にFadeしてくれるが、Bayer Matrixより負荷が高い。
参照動画
・Unityがサポートするファイル形式
BMP
EXR
GIF
HDR
IFF
JPG
PICT
PNG
PSD
TGA
TIFF
参照サイト
・テクスチャのインポート設定 Texture Type
■Default
おおむねのテクスチャーはこちらの設定。それ以外はこれから紹介する
■Normal Map
ノーマルマップを使用するときに設定
■Editor GUI and Legacy GUI
昔使われていた機能。正直よくわからない。
ただ、アプリのアイコンがぼやけたりうまく描画されない場合はこの設定で解決できるらしい。
■Sprite (2D and UI)
テクスチャを 2D ゲームの スプライト として使用する場合に選択。
2Dのゲーム作成する場合はこの設定にしたほうが、Sprite Creator、Sprite Editor、Sprite Renderer、Sprite Packerとかを利用できるので開発しやすい。
■Cursor
カーソルにする場合にこれを設定。
Texture TypeをDefaultにしてもカスタムのカーソルにできたしいまいち、カーソルの場合これを設定する意図がよくわからない。
ただ、テクスチャインポートの設定項目がCursorだとDefaultに比べて削減されてたしカーソルにする場合は、素直にCursorにした方が良さそう。
なお、カーソルの設定仕方はこちら。
using UnityEngine;
public class Test : MonoBehaviour
{
//設定したいカーソル
public Texture2D handCursor;
void Start()
{
Cursor.SetCursor(handCursor, Vector2.zero, CursorMode.Auto);
}
}
■Cookie
ライトでクッキーを使用できるようにする設定。
なお
クッキーを作成するライトのタイプに合わせて Light Typeを、Alpha Source を From Gray Scale に設定しないとクッキーを適用できない。
■Lightmap、Directional Lightmap、Shadowmask
ライトマップをUnityでベイクすると自動的に設定される。
ただ、Shadowmaskはなぜか生成されなかった
■Single Channel
チャンネルを、Rとアルファに指定できる設定。
Default
Single ChannelでChannelがRed
Single ChannelでChannelがAlpha
参照サイト
・テクスチャのインポート設定 Texture Shape
■2D
ほとんどはこれを設定。例外はこれから紹介するもの
■Cube
スカイボックスやリフレクションプローブ使用する際に設定する。
スカイボックスにしたい画像をCubeに変更して、UnityのビルトインシェーダーのCubemapの項目にアタッチ。そのあと、そのマテリアルをSkybox Materialにアタッチ
なお、スカイボックスの画像の作り方は特殊なのでこちらを参照
リフレクションプローブだと、Reflection Probeオブジェクトにアタッチした状態で、Bakeしたりすると自動的に生成され設定される
■2D Array
Columns (列) と Rows (行)を設定して、一枚の画像を複数にする。GPU からは単体のオブジェクトのように見えるので一枚一枚画像を使用するよりパフォーマンス良さそう。
実際の使用例を下記動画にしてみた
ソースはこちらを参照
Shader "Sample2DArrayTexture"
{
Properties
{
_TexArray("Texture Array", 2DArray) = "" {}
_TexArrayIndex("Texture Array Index", float) = 0.0
}
SubShader
{
Tags
{
"RenderType" = "Opaque"
"RenderPipeline" = "UniversalPipeline"
"IgnoreProjector" = "True"
}
Pass
{
Tags
{
"LightMode" = "UniversalForward"
}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma require 2darray
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
TEXTURE2D_ARRAY(_TexArray);
SAMPLER(sampler_TexArray);
float4 _TexArray_ST;
float _TexArrayIndex;
Varyings vert(Attributes IN)
{
Varyings OUT;
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
OUT.uv.xy = TRANSFORM_TEX(IN.uv, _TexArray);
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
return SAMPLE_TEXTURE2D_ARRAY(_TexArray, sampler_TexArray, IN.uv.xy, _TexArrayIndex);
}
ENDHLSL
}
}
}
①プラットフォームサポート
Direct3D 11/12 (Windows)、OpenGL Core (Mac OS X, Linux)、Metal (iOS, Mac OS X)、OpenGL ES 3.0 (Android, WebGL 2.0)をサポートします。
他のプラットフォームはテクスチャ配列をサポートしません (OpenGL ES 2.0 or WebGL 1.0)。
ランタイムにテクスチャ配列のサポートを定義するには、SystemInfo.supports2DArrayTextures を使用します。
②スクリプトによるテクスチャ配列の作成と操作
上の例のように、Texture Shapeを2D Arrayにして、Columns (列) と Rows (行)を設定してテクスチャ配列を作成する方法があるが、昔は、Texture2DArrayとAssetDatabase.CreateAssetを使用して作成していた。
具体的なソースはこちらを参照
④レンダリングターゲットとしてのテクスチャ配列の使用できる
実装方法は割愛する
■3D
3D テクスチャは、フォグや煙などのボリュメトリック効果をシミュレートしたり、ボリュメトリックな 3D メッシュを近似したり、アニメーション化されたテクスチャを格納してそれらを滑らかにブレンドしたりするためによく使用されます。
この動画を見ると、Unity側で3D テクスチャを適用するために、2Dテクスチャ作成する際は少し特殊である。
以下の画像用に、1024×32pxで拡張子はtgaにする必要がある。
Substanceデザイナーで作成するとやりやすいみたい。
また、3Dテクスチャは、下記画像のように、立方体をZ軸方向に輪切りしたものである。
実際に、3Dテクスチャを使用した動画がこちらになります。
①パフォーマンス
メモリ内およびディスク上の 3D テクスチャのサイズは、解像度が増加するにつれて急速に増加することに注意してください。 ミップマップがなく、解像度が 16 x 16 x 16 の RGBA32 3D テクスチャのサイズは 128 KB ですが、解像度が 256 x 256 x 256 の場合は 512 MB になります。
3D テクスチャの最大解像度は 2048 x 2048 x 2048 です。
②スクリプトから 3D テクスチャを作成
Texture Shapeを3Dにすれば、3D テクスチャを作成できるので割愛。
ソースコードはこちら
③3D テクスチャのプレビュー
作成した3Dテクスチャをプレビューできる機能がある。
また、
Handles.DrawTexture3DVolume
Handles.DrawTexture3DSlice
Handles.DrawTexture3DSDF
で自前でプレビューを実装できる。
参照サイト、参照サイト、参照サイト
・テクスチャのインポート設定 Mapping
Texture ShapeがCubeのときにできる項目で、Mappingの設定によって作成するテクスチャの方法が変わる。詳しい内容はこちらを参照。
参照サイト
・テクスチャのインポート設定 Convolution Type
Texture ShapeがCubeのときにできる項目で、より正確にCubeMapを表現するための設定。
None、Specular (Glossy Reflection)、Diffuse (Irradiance)あるが正直よくわからない。
試しにやってみたが
NoneだとSpecular (Glossy Reflection)、Diffuse (Irradiance)が変な結果た
Specular (Glossy Reflection)、Diffuse (Irradiance)だと
参照サイト
・テクスチャのインポート設定 Fixup Edge Seams
この設定は、 None か Diffuse コンボリューション (フィルタリング) でのみ可能です。これは、ローエンドのプラットフォームで、キューブマップの面が誤ってフィルタリングされるなどの、フィルタリングの制限の回避策として使用します。
参照サイト
・テクスチャのインポート設定 Resize Algorithm
インポートしたサイズ>Max Sizeの場合、テクスチャがダウンスケールするがその際のアルゴリズムを選択
■Mitchell
Mitchell アルゴリズムを選択
Bilinearよりもジャギーがなくなっている。
■Bilinear
Bilinear アルゴリズムを選択
Mitchellよりもシャープに見える。
参照サイト
・テクスチャの圧縮
ビット毎ピクセル (bpp) は、1 つのテクスチャピクセルに必要なストレージの量です。bpp 値が低いテクスチャは、ディスク上およびメモリ上のサイズが小さくなります。bpp 値が低いということは、GPU がテクスチャピクセルを読み取るために使用するメモリ帯域幅が小さいことを意味します。GPU のメモリ帯域幅はフレームレートのボトルネックになることが多いので、テクスチャ圧縮はその回避に役立ちます。
テクスチャアセットの視覚的品質が高ければ高いほど、1 ピクセルあたりのビット数が増え、結果的にビルドサイズ、ロード時間、およびランタイムのメモリ使用量が増加します。すべてのテクスチャ圧縮形式は、ある程度、非可逆的です。非圧縮のテクスチャは最高の品質を提供しますが、1 ピクセルあたりのビット数も最も多くなります。様々なテクスチャ圧縮形式によって、様々な妥協策が可能です。
一般的に、ランタイムパフォーマンスを最高にしディスク上のサイズを最適にするには、ほとんどのテクスチャアセットについて、ターゲットデバイスでサポートされているテクスチャ圧縮形式を選択し、必要な視覚的品質を実現するためにピクセルあたりのビット数を最小にする必要があります。
テクスチャを特定の目的で使用する場合、個々の設定を変更することができます。たとえば、1 つのチャンネルしかないテクスチャをマスクとして使用する場合、ファイルサイズを減らしながら品質を維持するために BC4 形式を選択することができます。また、ピクセルパーフェクトの UI を実現するためにテクスチャを使用する場合は、圧縮なしを選択することも可能です。
ターゲットとするプラットフォームやデバイスがサポートする形式を選択してください。デバイスがサポートしない圧縮形式のテクスチャをロードすると、Unity は、そのプラットフォームのデフォルトの非圧縮形式にテクスチャを解凍し、非圧縮のコピーを元の圧縮テクスチャと一緒にメモリに保存します。これにより、テクスチャの読み込み時間が長くなり、追加のメモリが使用されます。デバイスがサポートする圧縮形式でテクスチャをロードすると、GPU は変換の必要なしにデータを使用することができます。
参照サイト
・圧縮テクスチャについて
圧縮テクスチャの代表例は、DXT、PVRTC、ETC、ATSC、BCである。
メリットデメリットは下記画像参照
参照サイト
・クランチ圧縮
Crunch (クランチ) 圧縮は、DXT または ETC 圧縮の上に動作する圧縮形式で、可変ビットレートの圧縮を追加します。
可変ビットレート (VBR) は、ピクセルあたりのビット数が固定値ではなく、実際のコンテンツに依存することを意味します。VBR は Crunch 圧縮 にのみ、そしてディスク上のテクスチャサイズにのみ適用されます。メモリ内のサイズは、基礎となるテクスチャ形式を使用する場合と同じです。
クランチ圧縮しない・するで検証している記事をみたところ、解凍によるオーバーヘッドがなくファイルサイズも少なくなるとのこと。
ただ非圧縮なので劣化は多少あるかもしれない。
■DXT または ETCの違い
すごくわかりやすい比較画像を見つけた。
DXTとETCは、隣り合っているピクセル同士が色相環的に近くにない色である場合、上手く圧縮できずにブロックノイズと呼ばれる圧縮する前の色と違う色になることがある。
DXTは4×4ピクセル、白または黒色はブロックノイズが発生することがある。
ETCは4×2ピクセル(または2×4ピクセル)、白または黒色はブロックノイズが発生しない。
という特徴がある。
DXTはETCに比べて、白または黒色を圧縮するのが苦手でブロックノイズが発生する確率が上がる。
ETCはにDXT比べて、圧縮する対象が狭いのですぐ近くで隣り合っているピクセル同士が色相環的に近くにない色である場合ブロックノイズが発生する確率が上がる。
■DXTのブロックノイズ対策
輪郭の太さを変更する
■DXTにもいろいろ種類があり画像に合わせて選択しないと見た目が劣化する。
参照サイト、参照サイト、参照サイト、参照サイト
・テクスチャのインポート設定 Override ETC2 fallback
TC2 をサポートしない Android デバイスでのFormat形式を設定。
32bit、16bit、32bit(half-resoulution)を選択できる。
参照サイト
・リニア色空間とガンマ色空間の違い
■ライトの減衰
■ライティングの強度
■色の合成
上の画像から分かるように、リニア色空間のほうが正しい見た目になるので、リニア色空間で開発するほうが良い。(特にPBRで開発するとき)
ただ、リニア色空間はすべてのプラットフォームでサポートされているわけではありません。
以下が対応しているプラットフォーム
Windows、Mac OS X、Linux (スタンドアロン)
Android(OpenGL ES 3.0 グラフィックス API と Android 4.3 が必要)
iOS(Metalグラフィックス API が必要)
WebGL(最低 WebGL 2.0 グラフィックス API が必要)
サポートしていないとアプリが落ちてしまう。
ちなみに設定は、Color SpaceをLinearにすればリニア色空間になる。
(ガンマ色空間は、Color SpaceをGamma)
リニア色空間とガンマ色空間関連の情報は参照サイトが非常に分かりやすいのでそっちを参照するのが一番良い。
端的にまとめると、
■リニア色空間とガンマ色空間はリニア変換されるタイミングが違うこちらの方の参照画像
ガンマ色空間だと、sRGB (Color Texture)がオンオフでもリニア変換される。
ただ、リニア色空間だとsRGB (Color Texture)オフの場合リニア変換されない。
■ガンマ空間のライティングが白くなる原因こちらの方の参照画像
ディレクショナルライトが二つあった場合、ガンマ空間だとリニア変換されないので白くみえてしまう。
・テクスチャのインポート設定 sRGB (Color Texture)。
この設定は、テクスチャがガンマ空間(sRGB色空間)にする。
使用が可能な設定はDefault、Sprite (2D and UI)。
■ガンマ色空間(Color SpaceをGamma)の場合
sRGB (Color Texture)がオンオフでもシェーダ計算後にリニア変換されるの特にテクスチャーの種類によってオンオフを気にしなくても良い。
■リニア色空間(Color SpaceをLinear)の場合
リニア色空間(Color SpaceをLinear)の場合は、注意が必要である。
リニア色空間で、sRGB (Color Texture)オンの場合は、リニア変換される。
リニア色空間で、sRGB (Color Texture)オフの場合は、リニア変換されない。
なので
アルベドテクスチャーなど色を表すテクスチャーは、sRGB (Color Texture)オン。
それ以外(ノーマルマップとかラフネスマップやディストーションマップなど)は、sRGB (Color Texture)オフ。
に設定にするのが良い。
アルベドテクスチャーなど色を表すテクスチャーは、人間の目で色を識別して作成しているので実際のエネルギーとは異なるのでリニア変換して正しいものにする必要がある。
ただ、ノーマルマップやラフネスマップやディストーションマップなどは色を識別して作成していないのでオフにしてシェーダにそのまま値を渡す必要がある。(データとしてテスクチャ使用している)
参照サイト、参照サイト
・テクスチャのインポート設定 Alpha Source
テクスチャのアルファチャンネルの生成方法を指定。
使用可能な設定は、Default、Editor GUI and Legacy GUI、Sprite (2D and UI)、Cursor、Cookie、Single Channel。
Noneは、アルファを取得しない。不透明画像で使用
Input Texture Alphaは、アルファチャネルからアルファ取得。透過あり画像で使用
From Gray Scaleは、RGBを平均値してアルファ取得。グレースケール画像で使用
FormatをAutomaticにしていると、Alpha Sourceを変えるごとにFormatが変わる。参照サイト
・テクスチャのインポート設定 Alpha Source
プロパティを有効にすると、指定したアルファ チャンネルが透明の場合に、色を拡張しエッジのアーティファクトのフィルタリングを回避することができる。
使用可能な設定は、Default、Editor GUI and Legacy GUI、Sprite (2D and UI)、Cursor、Cookie、Single Channel。
下記画像が分かりやすい。
参照サイト、参照サイト
・テクスチャのインポート設定 Remove Matte (PSD)
PSD ファイルで有効で、その際に発生するアーティファクトをなくす設定。
使用可能な設定は、Default、Editor GUI and Legacy GUI、Sprite (2D and UI)、Cursor、Cookie、Single Channel。
下記画像が分かりやすい。
Remove Matte (PSD)がオフになっている右側のキャラのアウトラインが白くなっていて不自然である。
一方Remove Matte (PSD)がオンになっているキャラのアウトラインはそういったアーティファクトがない。
なお、このアーティファクトはビルド後は発生しないらしい。あくまでもUnityEditor上で作業中に発生する。
参照サイト、参照サイト
・テクスチャのインポート設定 Ignore PNG file gamma
このプロパティを有効にすると、PNG ファイルのガンマ属性を無視します。このプロパティは他のファイル形式には影響しません。
正直なにに使用するかわからない。
使用可能な設定は、全て。
参照サイト
・テクスチャのインポート設定 Non Power of 2
テクスチャが 2 の累乗以外 (NPO) のテクスチャサイズを持つ場合、これによってインポート時にスケーリングできる。
NPOのテクスチャは負荷がかかるのでなるべくテクスチャサイズを2の累乗にすべきである。
もともとのサイズが642×760である画像で実験してみた。
■None
テクスチャサイズは変更されません。
サイズが642×760。
■To nearest
テクスチャを、インポート時に最も近い 2 のべき乗のテクスチャサイズにスケーリングします。
サイズが512×512。
■To larger
テクスチャを、インポート時に最も大きい 2 のべき乗のテクスチャサイズにスケーリングされます。
サイズが1024×1024。
■To smaller
テクスチャを、インポート時に最も小さい 2 のべき乗のテクスチャサイズにスケーリングします。
サイズが512×512。
参照サイト、参照サイト
・テクスチャのインポート設定 Swizzle
チャンネルのデータを変えたりできる。
参照サイト
・テクスチャのインポート設定 Wrap Mode
タイリングするときのテクスチャの動作を選択します。
下記画像を用意して実験。まだタイリングは、xyともに1の状態
xy2に変更
■Repeat
テクスチャを繰り返し表示
■Clamp
テクスチャ端のピクセルを引き伸ばす
■Mirror
Repeatと同じで繰り返しですが鏡のように反転させて表示します。
■Mirror Once
UV座標の0,0を中心にMirrorを一度だけ行い、移行はClampと同じ引き伸ばし処理をします。
Mirrorと変わらない結果になった。
なお、Mirror Onceは一部のモバイルでは対応しておらず、その場合はMirrorになる。
■Per-axis
U 軸と V 軸でテクスチャをラップする方法を個別に制御。
UをRepeat、VをClampにしてみた。
参照サイト、参照サイト
・テクスチャのインポート設定 Create From GrayscaleとBumpinessとFiltering
Texure TypeをNormal Map、Create From Grayscaleを有効にするとBumpinessとFilteringが表示される。
これらの設定はハイトマップから法線マップを生成する際の設定である。
Bumpinessは、
法線の強度を設定できる。この値が高いとより凸凹な表現ができる。
Filteringは、
凹凸の計算方法を指定できる。
Sharpは、Smoothよりも鮮明な法線マップを生成。
Smoothは、Sharpよりも鮮明でない法線マップを生成。
今回はこちらのグレースケールを用意して実験してみる。
■Bumpinessが0.3
■Bumpinessが0.001
■FilteringがSharp
SharpのほうがSmoothよりも、凸凹表現ができているように見える。
■FilteringがSmooth
参照サイト
・テクスチャのインポート設定 Flip Green Channel
Texure TypeをNormal Mapにすると表示され、法線を反転させる設定。
画像見ると、確かに赤枠の凸凹が反転しているのが分かる。
■Flip Green Channelがオフ
■Flip Green Channelがオン
参照サイト
・テクスチャのインポート設定 Pixels Per Unit
1 ユニットの含まれるピクセル数を設定。
そもそも1 ユニットとは以下のようなグレーの線のこと
Unityはこの1ユニットの長さを、1メートルで表現する。
256××256の画像を用意して実験してみた。
■Pixels Per Unitを256設定
256××256なので、1ユニットにぴったり収まっている。
Earth_2_nb (1)をx軸に+1して移動させても、1ユニットにぴったり収まっている。
■Pixels Per Unitを100設定
もし左の画像をx軸に256px移動させるためには、
移動させる距離 = 移動させたいピクセル ÷ Pixels Per Unit
となるので、
2.56 = 256px /100
つまり、xを2.56にすればよい。
参照サイト、参照サイト
・テクスチャのインポート設定 Extrude Edges
Spriteのメッシュのエッジを調整できる。
値が大きいほどエッジを大きくできる。
Extrude Edgesは、Texture TypeがSprite (2D and UI)のとき表示される。
参照サイトによると、用途的にはアウトラインを調整する際に使用することがあるみたい。
■Extrude Edgesが1
■Extrude Edgesが32
参照サイト、参照サイト
・テクスチャのインポート設定 Pivot
SpriteのPosition・Rotation・Scaleの基準点を設定する。
Pivotは、Texture TypeがSprite (2D and UI)のとき表示される。
設定できる基準点はこちら
実際に確認してみた。
■Center
Pivotが真ん中にある
■Bottom
Pivotが下にある。
参照サイト
・Render Texture (レンダーテクスチャ)
Render Texture (レンダーテクスチャ) は、カメラで写したのをテクスチャーとして扱えるもの。
設定方法は、Assets > Create > Render TextureでRender Textureを作成し、それを映したいカメラのOutput Textureにアタッチし、作成したRender Textureをオブジェクトにアタッチすればカメラに写っているテクスチャが反映される。
下記のような感じ。
RenderTextureCameraで見えているところを、QuadにRender Textureとして反映させたもの。
ただ、RenderTextureを使用するとドローコールが増えるので注意
今回はRender Textureの項目を見ていく。
■Dimension
2D、Cube、3Dを設定できる。
テクスチャのインポート設定のTexture Shapeと同じ設定
■Size
Render Textureのサイズを指定できる(2 の累乗の値のみ)
この値を大きくすると解像度が上がるが容量も大きくなる。
■Anti-Aliasing
アンチエイリアスを適用させるか。
None、2 samples、4 samples、8 samplesから選べる。
None<2 samples<4 samples<8 samplesの順で負荷が高くなるので注意。
■Enable Compatible Color Format
このボックスをチェックすると、定義された Color Format がプラットフォームでサポートされていない場合に、互換性のある形式をレンダーテクスチャに適用します。
■Color Format
カラー形式を選択
以下を選択できる。
チャンネルのビット数多いの選択すると容量増えるので注意
■Depth Buffer
深度バッファの形式。
以下を選択できる。
チャンネルのビット数多いの選択すると容量増えるので注意。
■Enable Mip Maps、
ミップマップを生成する。
■Auto generate Mip Maps
このボックスをチェックすると、生成されたミップマップに関連データが自動的に入力されます。 これを有効にしない場合は、GenerateMips 関数を使用してミップマップを手動で入力する必要があります。 あるいは、さまざまな SetRenderTarget 関数を呼び出すときに、どのミップにレンダリングするかを選択します。
■Dynamic Scaling
動的解像度を適用する。
■Wrap Mode
Repeat、Clamp、Mirror、Mirror Once、Per-axisを設定できる。
テクスチャのインポート設定のWrap Modeと同じ。
■Filter Mode
Point、Bilinear、Trilinearを設定できる。
テクスチャのインポート設定のFilter Modeと同じ。
参照サイト
・Custom Render Textures (カスタムレンダーテクスチャ)
テクスチャをシェーダーで加工して、それをテクスチャとして使用できたりできる。
Custom Render Textures側の設定もたくさんある。
下記動画のように、真ん中の黄色い丸のCustom Render Texturesをシェーダーで加工して、その加工したCustom Render Texturesを別のシェーダーで使用して水の波紋を生成している。
参照サイト、参照サイト
・スパーステクスチャ (Sparse texture)
公式ドキュメントで以下の記載があるが、何に使用するのかやメリットがいまいちわからない。
スパーステクスチャ (Sparse texture、タイル化されたテクスチャ、または メガテクスチャとも呼ばれます) は、そのままグラフィックメモリーにのせるには大きすぎるテクスチャのことを言います。Unity はそれらを扱う際、「タイル」と呼ぶ小さな四角形に分割します。個々のタイルは必要に応じて読み込まれます。例えば、カメラにスパーステクスチャの一部分しか映っていない場合、現在映っている部分のタイルだけがメモリー上に必要になります。
なんらかの理由で個別のタイルが読み込めなかった場合、その結果は常に同じではありません (読み込めなかったタイル部分を黒色で表示する GPU もありますが、このような挙動が標準というわけではありません)。
ハードウェアやプラットフォームのすべてがスパーステクスチャをサポートしているわけではありません。例えば、DirectX のシステムでは、DX11.2(Windows8.1) とかなり最近の GPU を必要とします。OpenGL では、ARB_sparse_texture の拡張サポートが必要です。スパーステクスチャは、圧縮されていないテクスチャ形式のみをサポートします。
Discussion