質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

88.77%

Unity テクスチャ 反復周期

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 275
退会済みユーザー

退会済みユーザー

前提・実現したいこと

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

該当のソースコード

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public class GenerateTerrain : MonoBehaviour
{
    Mesh mesh;
    Mesh treeMesh;
    Matrix4x4[][] matrices;
    int count;
    public Material material;
    public Material treeMaterial;
    public int rows = 250;
    public int columns = 250;
    private void Start()
    {
        mesh = new Mesh();
        mesh.vertices = new Vector3[] {
        new Vector3 (0, 0, 0),
        new Vector3 (0, 1, 0),
        new Vector3 (1, 0, 0),
        new Vector3 (1, 1, 0),
    };

        mesh.uv = new Vector2[] {
        new Vector2 (0, 0),
        new Vector2 (0, 1),
        new Vector2 (1, 0),
        new Vector2 (1, 1),
    };

        mesh.triangles = new int[] {
        0, 1, 2,
        1, 3, 2,
    };

        mesh.RecalculateNormals();
        mesh.RecalculateBounds();

        // 各インスタンスの姿勢はMatrix4x4として与える
        count = rows * columns;
        var flatMatrices = new Matrix4x4[count];
        for (var i = 0; i < rows; i++)
        {
            for (var j = 0; j < columns; j++)
            {
                var index = (i * columns) + j;

                var position = new Vector3(j, i, 0.0f);

                var rotation = Quaternion.identity;

                var scale = Vector3.one;

                flatMatrices[index] = Matrix4x4.TRS(position, rotation, scale);
            }
        }

        // 一度に描画できるインスタンスは1023個までなので、あらかじめそれを超えないよう切り分けておく
        matrices = flatMatrices.Select((m, i) => (m, i / 1023))
            .GroupBy(t => t.Item2)
            .Select(g => g.Select(t => t.Item1).ToArray()).ToArray();
    }

    void Update()
    {
        foreach (var m in matrices)
        {
            Graphics.DrawMeshInstanced(mesh, 0, material, m);
        }
    }
}
Shader "Unlit/Terrain"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        [IntRange] _Magnification ("Magnification", Range(1, 32)) = 8
    }
    SubShader
    {
        Tags { "Queue"="Transparent" "RenderType"="Transparent" }
        LOD 100

        Pass
        {
            ZWrite Off
            ZTest Always
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_instancing
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            int _Magnification;

            v2f vert (appdata v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v)
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                o.uv = v.vertex.xy / _Magnification;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

試したこと

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

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

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

Shader "Unlit/Terrain"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        [IntRange] _Magnification ("Magnification", Range(1, 32)) = 8
    }
    SubShader
    {
        Tags { "Queue"="Transparent" "RenderType"="Transparent" }
        LOD 100

        Pass
        {
            ZWrite Off
            ZTest Always
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_instancing
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            int _Magnification;

            v2f vert (appdata v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v)
                o.vertex = UnityObjectToClipPos(v.vertex);

                // まず、メッシュのモデル座標をワールド座標に直す
                // タイルはXY平面上に0~250の範囲で並べられているため、ワールド座標も0~250の値をとる
                float3 worldPosition = mul(unity_ObjectToWorld, v.vertex);

                // ワールド座標のXYを_Magnification(たとえば8とする)で割れば、その値は0~31.25の範囲の値をとる
                float2 blockCoord = worldPosition.xy / _Magnification;

                // 8×8のタイルの集まりを仮に「ブロック」と呼ぶことにすると、blockCoordの整数部分はブロックのインデックス...
                // つまりX方向に何番目の、Y方向に何番目のブロックであるかを表していると解釈できる
                // 今回はブロックのインデックスに特に使い道はないため、そちらは使用しない

                // 一方、blockCoordの小数部分(0以上1未満の値をとる)だけを抜き出すと、その値はブロック内における位置...
                // つまり(0, 0)はブロックの左下、(0, 1)は左上、(1, 0)は右下、(1, 1)は右上となるような座標を表しているといえる
                // この値をテクスチャのUV座標として使用すれば、ブロック単位でテクスチャが貼り付けられるはずである
                // ただしその小数部分だけをo.uvに代入して使おうとしても、ブロックの右端・上端のタイルに正しくテクスチャが貼られないはず
                // ブロックの右端・上端は次のブロックの左端や下端でもあるため、これらの区別がつかないことによる
                // そこで、vert内では小数部分の抜き出しを行わず、blockCoordをそのままfragへ送ることにする
                // これにより整数部分も含めて座標が線形補間されるため、frag内で小数部分を取り出すと意図通りの値が得られる
                o.uv = TRANSFORM_TEX(blockCoord, _MainTex);

                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // i.uvから小数部分を取り出して最終的なUV座標とする
                // ちなみに、テクスチャの「Wrap Mode」が「Repeat」ならば0~1の範囲外は反復処理されるため
                // i.uvをそのまま使ってもかまわない
                float2 uv = frac(i.uv);

                // sample the texture
                fixed4 col = tex2D(_MainTex, uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/11/19 14:02

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

    キャンセル

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

  • ただいまの回答率 88.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る