読者です 読者をやめる 読者になる 読者になる

ScreenPocket - 画面の隙間

Unityエンジニアの日々の雑記。たまにpython3とDirectXも触ります

外接円1.0の正多角形メッシュを作る

f:id:ScreenPocket:20160817025129p:plain
「あー、メッシュ欲しいなー、けどメタセコやMaya立ち上げて面張るのダルいなー」っていう時に使える関数。
この間の連休で作ったので共有。

public static Mesh GenerateRegularPolygonMeshXY(int vertexCount)
{
	//Meshの作成
	Mesh mesh = new Mesh();

	Vector2[] points = new Vector2[vertexCount];
	float div = 360f / (float)vertexCount;
	for (int i = 0; i < vertexCount; ++i)
	{
		float rad = div * (float)i * Mathf.Deg2Rad;
		points[i] = new Vector2(Mathf.Sin(rad), Mathf.Cos(rad));
	}

	//頂点
	var verticies = new Vector3[points.Length + 1];
	verticies[0] = Vector3.zero;//中心
	for (int i = 0, length= points.Length; i < length; ++i)
	{
		verticies[i+1] = new Vector3(points[i].x, points[i].y, 0f);
	}
	mesh.vertices = verticies;

	//色
	Color[] colors = new Color[points.Length + 1];
	colors[0] = Color.black;//中心
	for (int i = 1, length = colors.Length; i < length; ++i)
	{
		colors[i] = Color.white;
	}
	mesh.colors = colors;

	//面
	var indicies = new int[vertexCount * 3];
	for (int i = 0; i < vertexCount; ++i)
	{
		indicies[i * 3 + 0] = 0;
		indicies[i * 3 + 1] = i + 1;
		indicies[i * 3 + 2] = ((i + 2 >= verticies.Length) ? 1 : i + 2);
	}
	mesh.triangles = indicies;
	return mesh;
}

これで、外接円を1.0としたXY平面上の正多角形Meshを作成できます。
※外接円の半径が1.0なので、4角形を作った場合、1辺の長さが1.0になるわけではないのでご注意!

一応ですが、頂点カラーで中心黒~外周白で色付けもしています。

「pointsいらねぇじゃん」と思うかもしれないけど、
このpointsをPolygonCollider2Dのpointsに入れるとそのままぴったりサイズのコライダが出来るので
良い感じにカスタマイズして下さいな。
※記事頭のスクショは自前でシェーダを書いたものなので、上記の模様がそのまま表示はされないです。

d3dxefffects11.hとEffects11.libがほしい時の対処

※今回Unity関係ないです。
久々に新しいwinPCを入手したので、過去に作った自作DirectXライブラリをビルドしてみようと色々試したのですが、案の定簡単にはビルドが通りませんでした。

中でも、d3dxeffect11.h、Effects.libについては、以前はDIrectXSDKのSamplesフォルダ内のプロジェクトをビルドして作っていたのですが、
最新のVisualStudioCommunity2015を使用しているとビルドが通らなく、結構迷ってしまった;

結論としては、最新のFX11プロジェクトがgithubに上がっているので、そちらを使ってビルドすることで解決!
github.com
DirectXを触るのは3~4年ぶりですが、いやはや、時代は進歩したなぁ…と感慨深い;

BoxCollider2Dのsizeをfloat.MaxValueにすると当たらなくなってしまう

タイトルでオチてしまった。はい、それだけです。

無限遠の地面がほしいと思った時に横着してfloat.MaxValueを入れたところ、
全く当たらなくなってしまって原因究明に時間がかかってしまった。という覚え書き。

OnPostRender()でのスクリーンキャプチャ

f:id:ScreenPocket:20160805015044p:plain

前回、スクリーンエフェクトをかける場合は、
OnRenderImage()で行うと重そう(…と言うより、OnRenderImage()を定義するだけでも重そう)だから、
OnPostRender()でスクリーンキャプチャして画像加工すればいいんじゃない?

と書きましたが、じゃあOnPostRender()でスクリーンキャプチャってどうすれば良いのよ?

という事で、コード書きました。

 

public class OnPostRenderCapture : MonoBehaviour
{
[SerializeField]
private RenderTexture captureImage = null;

void OnPostRender()
{
if (captureImage == null)
{
return;
}

Graphics.Blit(null, captureImage);
}
}

このコンポーネントをカメラにくっつければOK。captureImageにはInspectorでRenderTextureをくっつけておくか、Awake()かStart()でRenderTextureを作ってくっつけるかするのを忘れすに!

…で、多分この画像をイタに貼っつけると、機種依存で上下が反転したりするので

Unity - マニュアル: プラットフォーム別のレンダリングの違い

この辺を見て、表示面用に上下反転させるシェーダを用意すると良いでしょう。

これを使えばわざわざCameraのRenderTargetにRenderTextureを入れなくても良いから楽です。

OnRenderImage()を定義するコストについて

ふと、OnRenderImageの第1引数をデバッガで参照した時にこんな記述が、

f:id:ScreenPocket:20160526022220p:plain

「ImageEffects Temp」…? ふむ、定義した覚えのないRenderTextureですが、Unityちゃんが自動で定義してくれたんだろう。

 

ん?ということは、OnRenderImage()を定義しただけで負荷が増すということか??

 

ということで調べてみました。

☆OnRenderImage()を定義していない場合
FrameDebug
f:id:ScreenPocket:20160630001103p:plain
プレーンなプロジェクトなので画面クリアだけ

Profiler-Memory-Detailed
f:id:ScreenPocket:20160630001218p:plain
RenderTextureは1枚

☆OnRenderImageを定義した場合

FrameDebug
f:id:ScreenPocket:20160630001220p:plain
なんか描画パス増えてる。

Profiler-Memory-Detailed
f:id:ScreenPocket:20160630001219p:plain
RenderTextureに ImageEffects Temp が2つ増えてる。 2つ!?(AA用?)

という事で、OnRenderImage()を定義しただけで、
・描画パスが増える
・RenderTextureが2つ増える(多分大きさは画面サイズに依存)
ようです。これってモバイル系だと結構無視できない負荷に思えます。

これがモバイルでも同じように動いているなら、特に必要ないようであればOnRenderImage()は定義しないほうが良さそう。

『そんなこと言われたって、スクリーンをキャプチャしなきゃ、色々なスクリーンエフェクトをかけられないじゃないか!』

 …という方はOnRenderImage()ではなく、OnPostRender()でScreen(フレームバッファ)の画像をRenderTextureにコピーすれば良いかと。

unity_FogParamsの値について

Builtin_Shadersの中で、UnityCG.cgincを見てみると、フォグに関わるマクロについては

UNITY_CALC_FOG_FACTOR フォグの強さを決める+変数定義
UNITY_FOG_COORDS_PACKED フォグ演算(の結果の値を渡すため)に使うテクスチャ座標の定義
UNITY_FOG_COORDS 同上
UNITY_TRANSFER_FOG VS側で使用。モバイル系だと色決め。UNITY_FOG_LERP_COLOR 線形(lerp)で色決め
UNITY_APPLY_FOG_COLOR UNITY_FOG_LERP_COLORで色決め。
UNITY_APPLY_FOG FS側で使用。UNITY_APPLY_FOG_COLORで色決め。

だいたいそんな感じ。

で、その中で使われている unity_FogColor、unity_FogParams ですが、
マニュアルを見るとRenderSettings.fogColorとRenderSettings.fog[Start,End]Distanceと値が紐付いている模様。

fogの設定を切って、自前Fog演算を作る際に、値を拝借してデータ量を削減しようと試みた所、
fogColorについてはunity_FogColorに値が渡されているようですが、
何とfog[Start,End]Distanceについては、unity_FogParams.zwに値が渡っていない…。

どうやら、fogの設定を切るとunity_FogParamsにRenderSettingsからの値が入らなくなるようです。

多分、UNITY_CALC_FOG_FACTORを見た感じ、
unity_FogParams.zには(-1/(end-start))が入っていて、
unity_FogParams.wには(end/(end-start))が入るようなので
その分の演算+値渡しが省かれているのかな?

結局Shader.GlobalVector()を使って、
自前Global変数に(-1/(end-start))と(end/(end-start))を渡すようにしましたが、果たして軽量化できているのか微妙ですね。。

 

iPhone用のSetPlatformTextureSettingsが反映されない場合の対処

Unity - Scripting API: TextureImporter.SetPlatformTextureSettings

 には、

platform の文字列は BuildTarget の列挙体を文字列へ変換したものと同じものです。

とか書いてあるから

Unity - Scripting API: BuildTarget

 を見て、iPhone用に第1引数に "iOS" って書いたのにiPhone用の設定が通らないでやんの。。

"iPhone" と書けば通りましたが、それなら何処かに書いておいてほしいなぁ。。