ãUnityãã«ã¡ã©ããã©ãã ãé¢ãã¦ããæä½1ãã¯ã»ã«ã¯è¡¨ç¤ºãããããã«ä¿éãã
é常3Dãªãã¸ã§ã¯ããã«ã¡ã©ããé¢ããããã¨ãã¬ã³ããªã³ã°ãµã¤ãºã1ãã¯ã»ã«ãä¸åã£ãæç¹ã§ç»é¢ã«æç»ãããªããªããã«ã¡ã©ã¨ã®ä½ç½®é¢ä¿ã«ãã£ã¦æç»ãåãããåºãããã¦ãã«ãã«ã¨è¡¨ç¤ºããããã¨ãããã¾ããä»åã¯ãã®åé¡ã®è§£æ±ºæ¹æ³ï¼ã¬ã³ããªã³ã°ã®æä½ãã¯ã»ã«ä¿éï¼ãå
±æãã¾ãã
èãæ¹
å®ç¾ããããã«ã¯ããå次ã¯ãªãã空éä¸ã§ãã«ãã¼ãã縦横ã«æå®ãã¯ã»ã«ãã¤å¤§ãããã¦æç»ãããã°è¯ããã¨ã«ãªãã¾ãã
座æ¨å¤æã«ã¤ãã¦ã¯ä»¥ä¸ã®ãµã¤ãã詳ãã解説ããã¦ãã¾ãã®ã§ãèå³ã®ããæ¹ã¯ã©ããã
3D座標変換 - ゲームプログラミングWiki
å®ç¾æ¹æ³
é ç¹æ
å ±ã¨ãã¦ä½ç½®ã¨æ³ç·ãä¸ãã¦ãé ç¹ã·ã§ã¼ãã¼ã§æ³ç·æ¹åã«æå®ãã¯ã»ã«åå¼ã延ã°ããã¨ã§å®ç¾ãã¾ãã
常ã«æå®ãã¯ã»ã«å大ãã表示ããã¦ãã¾ãã¾ããããã¾ã大ããªå¤ãå
¥ããªãéãã¯å¤§ä¸å¤«ãã¨ã
éã«ããã«ãã¼ãã®ãµã¤ãºã極端ã«å°ãããã¦ã常ã«åããã¯ã»ã«æ°ã§è¡¨ç¤ºããããããªãã¨ãå¯è½ã§ãã
ãã«ãã¼ã
using UnityEngine; using System.Collections; using System.Collections.Generic; public class MyBillBorad : MonoBehaviour { [SerializeField] private Vector2 size = new Vector2(1f, 1f); private void Update() { Camera mainCamera = Camera.main; if (mainCamera != null) { this.transform.LookAt(mainCamera.transform.position); } } private Mesh CreateMesh() { List<Vector3> vertices = new List<Vector3> (); List<int> triangles = new List<int> (); List<Vector2> uvs = new List<Vector2> (); List<Vector3> normals = new List<Vector3> (); float width = size.x * 0.5f; float height = size.y * 0.5f; // é ç¹ vertices.Add(new Vector3(-width, -height, 0f)); vertices.Add(new Vector3( width, -height, 0f)); vertices.Add(new Vector3(-width, height, 0f)); vertices.Add(new Vector3( width, height, 0f)); // ã¤ã³ããã¯ã¹ triangles.AddRange(new int[]{1, 2, 0}); triangles.AddRange(new int[]{3, 2, 1}); // uv uvs.Add(new Vector2(1f, 0f)); uvs.Add(new Vector2(0f, 0f)); uvs.Add(new Vector2(1f, 1f)); uvs.Add(new Vector2(0f, 1f)); // æ³ç· normals.AddRange(vertices.ToArray()); Mesh mesh = new Mesh (); mesh.vertices = vertices.ToArray (); mesh.triangles = triangles.ToArray (); mesh.uv = uvs.ToArray (); mesh.normals = normals.ToArray (); mesh.RecalculateBounds (); return mesh; } private void Awake() { MeshFilter meshFilter = GetComponent<MeshFilter> (); meshFilter.sharedMesh = CreateMesh (); } }
ã·ã§ã¼ãã¼
Shader "Unlit/MyBillBorad" { Properties { _MainTex ("Texture", 2D) = "white" {} _MinimunPixel ("Minimum Pixel", Float) = 1 } SubShader { Tags { "RenderType"="Opaque" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; }; sampler2D _MainTex; float _MinimunPixel; v2f vert (appdata_base v) { v2f o; float4 pos = mul(UNITY_MATRIX_MVP, v.vertex); // (注1)v.normalãfloat4ã«ãã£ã¹ãããªãã¨ãiOSã§ã·ã§ã¼ãã¼ãã«ãã«å¤±æãã float4 norm = mul(UNITY_MATRIX_MVP, float4(v.normal, 0)); // æ³ç·æ å ±ããã縦横ã®å¼ã伸ã°ãæ å ±ä»¥å¤ãæ¨ã¦ã norm = float4(sign(norm.x), sign(norm.y), 1, 1); // ã¹ã¯ãªã¼ã³ä¸ã®ãã¯ã»ã«ãµã¤ãºã«åããã¦å¼ã延ã°ã float px = (_ScreenParams.z - 1) * _MinimunPixel; float py = (_ScreenParams.w - 1) * _MinimunPixel; // (注2)MVPå¤æå¾ã®pos.wã«ã¹ã±ã¼ã«å¤ãæ ¼ç´ããã¦ãã float scale = pos.w; pos = pos + (norm * float4(px * scale, py * scale, 0, 0)); // ãã¯ã»ã«ã·ã§ã¼ãã¼ã¸æ å ±ã渡ã o.vertex = pos; o.uv = v.texcoord; return o; } fixed4 frag (v2f i) : SV_Target { return tex2D(_MainTex, i.uv); } ENDCG } } }
(注1)
v.normalãfloat3ã®ã¾ã¾è¡åå¤æãããã¨ããã¨ãiOSã§ã®ã¿ãnon-square matrices not supported (4x1)ãã¨ããã¨ã©ã¼ãåºã¦ã·ã§ã¼ãã¼ã³ã³ãã¤ã«ãã§ããªãç¾è±¡ãåºã¾ãããUnityEditorãAndroidã¯éãã¾ãã
(注2)
ãã¯ã»ã«ãµã¤ãºããã®ã¾ã¾è¶³ãããã¨ãä¸æããµã¤ãºä¿éãã§ãã¾ããï¼ã«ã¡ã©ããé¢ããã°é¢ããã»ã©px,pyã®å¤ãç¸å¯¾çã«å°ãããªãããï¼ãpos.wã«å
¥ã£ã¦ããã¹ã±ã¼ã«å¤ãããããã¨ã§æ£ããåä½ãã¾ãããã®ä»¶ã«ã¤ãã¦ã¯ã以ä¸ã®ãµã¤ãã詳ããã§ãã
3Dのタッチ操作と四次元の話 - ケイプロ奮闘記