私からも意見を申し上げさせていただくと、やはりsakura_hanaさんのおっしゃるようにUnityに搭載されているミップマップ機能を使った方が無難かもしれません。スクリプト側で毎フレーム全オブジェクトを総なめしてテクスチャをセットするというのは何だか大変そうな気がしますし、なるべくGPU側に処理を任せるのがいいんじゃないかと思います。
たとえばスクリプトを下記のようにすると、縮尺に応じてテクスチャの見た目がなめらかに変化するはずです。
C#
1using UnityEngine;
2
3public class MipMapExample : MonoBehaviour
4{
5 public Texture2D tex128128;
6 public Texture2D tex6464;
7 public Texture2D tex3232;
8 GameObject[] Quads = new GameObject[900];
9 public GameObject Quad;
10
11 // tex128128、tex6464、tex3232を一つにまとめたテクスチャ
12 // 本来はシリアライズするべきフィールドではないが、できあがったテクスチャの内容を
13 // インスペクター上で手軽に確認できるようSerializeFieldを付けた
14 [SerializeField] private Texture2D tex;
15
16 private void Start()
17 {
18 // 3レベルのミップマップを持つテクスチャを作成し...
19 tex = new Texture2D(tex128128.width, tex128128.height, tex128128.format, 3, false);
20
21 // tex128128、tex6464、tex3232のデータを各レベルにセットする
22 // なお、GetRawTextureDataを使うにはテクスチャの「Read/Write Enabled」をオンにしておく必要がある
23 tex.SetPixelData(tex128128.GetRawTextureData(), 0);
24 tex.SetPixelData(tex6464.GetRawTextureData(), 1);
25 tex.SetPixelData(tex3232.GetRawTextureData(), 2);
26
27 // フィルターモードはトライリニア補間とする
28 tex.filterMode = FilterMode.Trilinear;
29
30 // 必要に応じてミップマップレベル選択にバイアスを設けることもできる
31 // 通常はバイアスは0にしておけば最適なはずだが、ミップマップが切り替わる
32 // タイミングを調整したい場合があるかもしれない
33 // たとえば下記のように-1とすると、仮に自動選択されたミップマップが
34 // レベル1...つまりtex6464であるような拡縮条件では、このレベルが1段階
35 // 下がって0となり、レベル0...つまりtex128128が表示されるはず
36 // 大ざっぱに言うと、バイアスをマイナスに振れば高解像度テクスチャ...つまり
37 // tex128128やtex6464が表示されやすく、プラスに振れば低解像度テクスチャ...
38 // つまりtex6464やtex3232が表示されやすいということになる
39 tex.mipMapBias = -1.0f;
40
41 // テクスチャをGPU側にアップロードする
42 tex.Apply(false, true);
43
44 // Quadをインスタンス化して配置する前に、まずQuadのマテリアルを複製してしまい...
45 Renderer quadRenderer = Quad.GetComponent<Renderer>();
46 Material quadMaterial = quadRenderer.sharedMaterial;
47 Material newQuadMaterial = Instantiate(quadMaterial);
48
49 // マテリアルにテクスチャをセットし...
50 newQuadMaterial.mainTexture = tex;
51
52 // それをquadRendererの共有マテリアルとする
53 // インスタンス化されたすべてのQuadには共通のテクスチャを持たせているようだったので、
54 // それならばいっそマテリアルごと共通化してしまっていいんじゃないかと思い、このようにしてみた
55 quadRenderer.sharedMaterial = newQuadMaterial;
56
57 int index = 0;
58 for(int x = 0; x < 30; x++)
59 {
60 for(int y = 0; y < 30; y++)
61 {
62 Vector2 pos = new Vector2(x, y);
63 Quads[index] = Instantiate(Quad, pos, Quaternion.identity);
64 index++;
65 }
66 }
67
68 // プレハブのマテリアルは元に戻しておく
69 quadRenderer.sharedMaterial = quadMaterial;
70 }
71}
こういった形なら、Orthographic Sizeやゲーム画面の解像度だとかをいちいち考慮しなくても、縮尺に合わせて最適なミップマップレベルが選択されるでしょうからおすすめだと思います。
それとも、ご質問者さんのコードですとOrthographic Sizeを見てテクスチャを切り替えていますが、ご質問の文面通り「Orthographic Sizeが○○の時はミップマップレベル△△」みたいにOrthographic Sizeに依存した切り替え方をしたいということでしょうか?
そういった場合にはおそらくマテリアルのシェーダーコードもカスタマイズする必要があるんじゃないかと思います。
スクリプトを下記のようにして...
C#
1using UnityEngine;
2
3public class MipMapExample2 : MonoBehaviour
4{
5 public float level0Size = 7.5f;
6 public Texture2D tex128128;
7 public float level1Size = 15.0f;
8 public Texture2D tex6464;
9 public float level2Size = 20.0f;
10 public Texture2D tex3232;
11 public GameObject Quad;
12
13 GameObject[] Quads = new GameObject[900];
14
15 [SerializeField] private Texture2D tex;
16
17 private void Start()
18 {
19 // MipMapExampleと同様にテクスチャを作成する
20 // バイアスは0のままいじらないでおく
21 tex = new Texture2D(tex128128.width, tex128128.height, tex128128.format, 3, false);
22 tex.SetPixelData(tex128128.GetRawTextureData(), 0);
23 tex.SetPixelData(tex6464.GetRawTextureData(), 1);
24 tex.SetPixelData(tex3232.GetRawTextureData(), 2);
25 tex.filterMode = FilterMode.Trilinear;
26 tex.Apply(false, true);
27
28 // マテリアルも同様に準備し...
29 Renderer quadRenderer = Quad.GetComponent<Renderer>();
30 Material quadMaterial = quadRenderer.sharedMaterial;
31 Material newQuadMaterial = Instantiate(quadMaterial);
32 newQuadMaterial.mainTexture = tex;
33 quadRenderer.sharedMaterial = newQuadMaterial;
34
35 // ミップマップレベル選択用パラメーターを決める
36 // まずゲーム画面のピクセル単位の高さを取得する
37 int screenHeight = Screen.height;
38
39 // 各レベルのV変化率を求める
40 float dVdy0 = (this.level0Size * 2.0f) / screenHeight;
41 float dVdy1 = (this.level1Size * 2.0f) / screenHeight;
42 float dVdy2 = (this.level2Size * 2.0f) / screenHeight;
43
44 // レベル間は3次スプライン曲線でつなぐことにする
45 // そこでレベル0から1をつなぐ3次曲線とレベル1から2をつなぐ3次曲線の係数を決める
46 // 計算手順は http://www.yamamo10.jp/yamamoto/lecture/2006/5E/interpolation/interpolation_html/node3.html の方法を使った
47 // 曲線は「レベル0の時のV変化率にかけることで目的のV変化率を得るスケール値」を表しており、
48 // シェーダー上で実測したV変化率がdVdy0の時は1.0、dVdy1の時は2.0、dVdy2の時は4.0を返すようにする
49 float h0 = dVdy1 - dVdy0;
50 float h1 = dVdy2 - dVdy1;
51 float v1 = 6.0f * ((2.0f / h1) - (1.0f / h0));
52 float u1 = (v1 * 0.5f) / (h0 + h1);
53 float b1 = u1 * 0.5f;
54 float a0 = u1 / (6.0f * h0);
55 float a1 = -u1 / (6.0f * h1);
56 float c0 = (1.0f / h0) - ((h0 * u1) / 6.0f);
57 float c1 = (2.0f / h1) - ((h1 * 2.0f * u1) / 6.0f);
58 Vector4 coefficients0 = new Vector4(a0, 0.0f, c0, 1.0f);
59 Vector4 coefficients1 = new Vector4(a1, b1, c1, 2.0f);
60
61 // マテリアルにパラメーターをセットする
62 newQuadMaterial.SetVector("_ControlPoints", new Vector3(dVdy0, dVdy1, dVdy2));
63 newQuadMaterial.SetVector("_Coefficients0", coefficients0);
64 newQuadMaterial.SetVector("_Coefficients1", coefficients1);
65
66 int index = 0;
67 for(int x = 0; x < 30; x++)
68 {
69 for(int y = 0; y < 30; y++)
70 {
71 Vector2 pos = new Vector2(x, y);
72 Quads[index] = Instantiate(Quad, pos, Quaternion.identity);
73 index++;
74 }
75 }
76
77 // プレハブのマテリアルは元に戻しておく
78 quadRenderer.sharedMaterial = quadMaterial;
79 }
80}
マテリアルは下記のようにし...
ShaderLab
1Shader "Unlit/RemappedMipmap"
2{
3 Properties
4 {
5 _MainTex ("Texture", 2D) = "white" {}
6 _ControlPoints ("Reference V Gradients", Vector) = (0, 0, 0, 0)
7 _Coefficients0 ("Coefficients for Level 0 to 1", Vector) = (0, 0, 0, 0)
8 _Coefficients1 ("Coefficients for Level 1 to 2", Vector) = (0, 0, 0, 0)
9 }
10 SubShader
11 {
12 Tags { "Queue"="Transparent" "RenderType"="Transparent" }
13 Pass
14 {
15 CGPROGRAM
16 #pragma vertex vert
17 #pragma fragment frag
18
19 #include "UnityCG.cginc"
20
21 struct appdata
22 {
23 float4 vertex : POSITION;
24 float2 uv : TEXCOORD0;
25 };
26
27 struct v2f
28 {
29 float2 uv : TEXCOORD0;
30 float4 vertex : SV_POSITION;
31 };
32
33 sampler2D _MainTex;
34 float4 _MainTex_ST;
35 float4 _MainTex_TexelSize;
36 float3 _ControlPoints;
37 float4 _Coefficients0;
38 float4 _Coefficients1;
39
40 // 実測したV変化率からV変化率スケールを算出する
41 float getScale(float v)
42 {
43 v = clamp(v, _ControlPoints.x, _ControlPoints.z);
44 float segment = step(_ControlPoints.y, v);
45 float x = v - lerp(_ControlPoints.x, _ControlPoints.y, segment);
46 float x2 = x * x;
47 return dot(lerp(_Coefficients0, _Coefficients1, segment), float4(x2 * x, x2, x, 1.0f));
48 }
49
50 v2f vert(appdata v)
51 {
52 v2f o;
53 o.vertex = UnityObjectToClipPos(v.vertex);
54 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
55 return o;
56 }
57
58 fixed4 frag(v2f i) : SV_Target
59 {
60 float2 gradient = float2(_MainTex_TexelSize.y * getScale(abs(ddy(i.uv.y))), 0.0);
61 return tex2Dgrad(_MainTex, i.uv, gradient, gradient.yx);
62 }
63
64 ENDCG
65 }
66 }
67}
各レベルは下図のような画像を使ったところ...
下図のような見た目になりました。Orthographic Sizeが7.5までは赤色で、7.5から15にかけて次第に緑色に変わっていき、15から20にかけて次第に青色に変化しています。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2020/08/20 08:21