🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

562閲覧

Unity テクスチャ 反復周期

退会済みユーザー

退会済みユーザー

総合スコア0

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2019/11/16 15:50

前提・実現したいこと

テクスチャの反復周期を長くしたい

該当のソースコード

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using System.Linq; 5 6public class GenerateTerrain : MonoBehaviour 7{ 8 Mesh mesh; 9 Mesh treeMesh; 10 Matrix4x4[][] matrices; 11 int count; 12 public Material material; 13 public Material treeMaterial; 14 public int rows = 250; 15 public int columns = 250; 16 private void Start() 17 { 18 mesh = new Mesh(); 19 mesh.vertices = new Vector3[] { 20 new Vector3 (0, 0, 0), 21 new Vector3 (0, 1, 0), 22 new Vector3 (1, 0, 0), 23 new Vector3 (1, 1, 0), 24 }; 25 26 mesh.uv = new Vector2[] { 27 new Vector2 (0, 0), 28 new Vector2 (0, 1), 29 new Vector2 (1, 0), 30 new Vector2 (1, 1), 31 }; 32 33 mesh.triangles = new int[] { 34 0, 1, 2, 35 1, 3, 2, 36 }; 37 38 mesh.RecalculateNormals(); 39 mesh.RecalculateBounds(); 40 41 // 各インスタンスの姿勢はMatrix4x4として与える 42 count = rows * columns; 43 var flatMatrices = new Matrix4x4[count]; 44 for (var i = 0; i < rows; i++) 45 { 46 for (var j = 0; j < columns; j++) 47 { 48 var index = (i * columns) + j; 49 50 var position = new Vector3(j, i, 0.0f); 51 52 var rotation = Quaternion.identity; 53 54 var scale = Vector3.one; 55 56 flatMatrices[index] = Matrix4x4.TRS(position, rotation, scale); 57 } 58 } 59 60 // 一度に描画できるインスタンスは1023個までなので、あらかじめそれを超えないよう切り分けておく 61 matrices = flatMatrices.Select((m, i) => (m, i / 1023)) 62 .GroupBy(t => t.Item2) 63 .Select(g => g.Select(t => t.Item1).ToArray()).ToArray(); 64 } 65 66 void Update() 67 { 68 foreach (var m in matrices) 69 { 70 Graphics.DrawMeshInstanced(mesh, 0, material, m); 71 } 72 } 73} 74

ShaderLab

1Shader "Unlit/Terrain" 2{ 3 Properties 4 { 5 _MainTex ("Texture", 2D) = "white" {} 6 [IntRange] _Magnification ("Magnification", Range(1, 32)) = 8 7 } 8 SubShader 9 { 10 Tags { "Queue"="Transparent" "RenderType"="Transparent" } 11 LOD 100 12 13 Pass 14 { 15 ZWrite Off 16 ZTest Always 17 Blend SrcAlpha OneMinusSrcAlpha 18 19 CGPROGRAM 20 #pragma vertex vert 21 #pragma fragment frag 22 #pragma multi_compile_instancing 23 // make fog work 24 #pragma multi_compile_fog 25 26 #include "UnityCG.cginc" 27 28 struct appdata 29 { 30 float4 vertex : POSITION; 31 float2 uv : TEXCOORD0; 32 UNITY_VERTEX_INPUT_INSTANCE_ID 33 }; 34 35 struct v2f 36 { 37 float2 uv : TEXCOORD0; 38 UNITY_FOG_COORDS(1) 39 float4 vertex : SV_POSITION; 40 }; 41 42 sampler2D _MainTex; 43 float4 _MainTex_ST; 44 int _Magnification; 45 46 v2f vert (appdata v) 47 { 48 v2f o; 49 UNITY_SETUP_INSTANCE_ID(v) 50 o.vertex = UnityObjectToClipPos(v.vertex); 51 o.uv = TRANSFORM_TEX(v.uv, _MainTex); 52 UNITY_TRANSFER_FOG(o,o.vertex); 53 o.uv = v.vertex.xy / _Magnification; 54 return o; 55 } 56 57 fixed4 frag (v2f i) : SV_Target 58 { 59 // sample the texture 60 fixed4 col = tex2D(_MainTex, i.uv); 61 // apply fog 62 UNITY_APPLY_FOG(i.fogCoord, col); 63 return col; 64 } 65 ENDCG 66 } 67 } 68} 69

試したこと

1024×1024の画像を使って、タイル数250×250のメッシュを生成しているため、テクスチャが潰れて見えてしまいます。シェーダーを使って、タイル数32×32のマップにしてみようとしましたが、単純に拡大されるだけで、上手くいきません。

使用した画像↓
イメージ説明

どのように書き換えればよいでしょうか? 回答お願いします。加えて、こういったタイリングに関するシェーダーの勉強法なども出来れば教えてもらいたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

シェーダーコードを下記のようにしてみましたが、どうでしょうか?
コード中のコメントとして反復の理屈を説明してみましたが、文章だけだとちょっとややこしかったかもしれません。

ShaderLab

1Shader "Unlit/Terrain" 2{ 3 Properties 4 { 5 _MainTex ("Texture", 2D) = "white" {} 6 [IntRange] _Magnification ("Magnification", Range(1, 32)) = 8 7 } 8 SubShader 9 { 10 Tags { "Queue"="Transparent" "RenderType"="Transparent" } 11 LOD 100 12 13 Pass 14 { 15 ZWrite Off 16 ZTest Always 17 Blend SrcAlpha OneMinusSrcAlpha 18 19 CGPROGRAM 20 #pragma vertex vert 21 #pragma fragment frag 22 #pragma multi_compile_instancing 23 // make fog work 24 #pragma multi_compile_fog 25 26 #include "UnityCG.cginc" 27 28 struct appdata 29 { 30 float4 vertex : POSITION; 31 float2 uv : TEXCOORD0; 32 UNITY_VERTEX_INPUT_INSTANCE_ID 33 }; 34 35 struct v2f 36 { 37 float2 uv : TEXCOORD0; 38 UNITY_FOG_COORDS(1) 39 float4 vertex : SV_POSITION; 40 }; 41 42 sampler2D _MainTex; 43 float4 _MainTex_ST; 44 int _Magnification; 45 46 v2f vert (appdata v) 47 { 48 v2f o; 49 UNITY_SETUP_INSTANCE_ID(v) 50 o.vertex = UnityObjectToClipPos(v.vertex); 51 52 // まず、メッシュのモデル座標をワールド座標に直す 53 // タイルはXY平面上に0~250の範囲で並べられているため、ワールド座標も0~250の値をとる 54 float3 worldPosition = mul(unity_ObjectToWorld, v.vertex); 55 56 // ワールド座標のXYを_Magnification(たとえば8とする)で割れば、その値は0~31.25の範囲の値をとる 57 float2 blockCoord = worldPosition.xy / _Magnification; 58 59 // 8×8のタイルの集まりを仮に「ブロック」と呼ぶことにすると、blockCoordの整数部分はブロックのインデックス... 60 // つまりX方向に何番目の、Y方向に何番目のブロックであるかを表していると解釈できる 61 // 今回はブロックのインデックスに特に使い道はないため、そちらは使用しない 62 63 // 一方、blockCoordの小数部分(0以上1未満の値をとる)だけを抜き出すと、その値はブロック内における位置... 64 // つまり(0, 0)はブロックの左下、(0, 1)は左上、(1, 0)は右下、(1, 1)は右上となるような座標を表しているといえる 65 // この値をテクスチャのUV座標として使用すれば、ブロック単位でテクスチャが貼り付けられるはずである 66 // ただしその小数部分だけをo.uvに代入して使おうとしても、ブロックの右端・上端のタイルに正しくテクスチャが貼られないはず 67 // ブロックの右端・上端は次のブロックの左端や下端でもあるため、これらの区別がつかないことによる 68 // そこで、vert内では小数部分の抜き出しを行わず、blockCoordをそのままfragへ送ることにする 69 // これにより整数部分も含めて座標が線形補間されるため、frag内で小数部分を取り出すと意図通りの値が得られる 70 o.uv = TRANSFORM_TEX(blockCoord, _MainTex); 71 72 UNITY_TRANSFER_FOG(o,o.vertex); 73 return o; 74 } 75 76 fixed4 frag (v2f i) : SV_Target 77 { 78 // i.uvから小数部分を取り出して最終的なUV座標とする 79 // ちなみに、テクスチャの「Wrap Mode」が「Repeat」ならば0~1の範囲外は反復処理されるため 80 // i.uvをそのまま使ってもかまわない 81 float2 uv = frac(i.uv); 82 83 // sample the texture 84 fixed4 col = tex2D(_MainTex, uv); 85 // apply fog 86 UNITY_APPLY_FOG(i.fogCoord, col); 87 return col; 88 } 89 ENDCG 90 } 91 } 92}

学習方法としてはどういうやり方がいいのか、おそらく人によってさまざまのように思いますのでなんとも言いがたいですね...すみません。
たとえばUnityでシェーダを学ぶ時に参考した本とか - Qiitaで紹介されているようなサイトや書籍でいろいろな表現方法が紹介されているかと思いますので、それらのコードを読解して応用する...とかでしょうか。コードを部分的に改変してみて、そこの改変によって挙動がどう変化するか確認いただくのも理解の助けになるかと思います(普通のスクリプトと違って、シェーダーコードは基本的に描画結果をたよりにデバッグしなければならないのでやっかいですね...)。

投稿2019/11/18 22:23

Bongo

総合スコア10811

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/11/19 05:02

いつも分かりやすい回答、本当にありがとうございます。コード中のコメントがあったため、理解しやすかったです。記載されているURLをもとに、シェーダの学習をしてみることにします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問