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

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

新規登録して質問してみよう
ただいま回答率
85.46%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

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

Q&A

解決済

2回答

2589閲覧

Unity テクスチャをフェードさせたい

退会済みユーザー

退会済みユーザー

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

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

0グッド

1クリップ

投稿2020/08/18 09:11

前提・実現したいこと

マテリアルに適応したテクスチャを、カメラのorthographicSizeに応じてフェードさせたい

該当のソースコード

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEditor; 5 6public class MipMapExample : MonoBehaviour 7{ 8 float cameraSize; 9 public Texture2D tex128128; 10 public Texture2D tex6464; 11 public Texture2D tex3232; 12 GameObject[] Quads = new GameObject[900]; 13 public GameObject Quad; 14 15 private void Start() 16 { 17 int index = 0; 18 for(int x = 0;x < 30; x++) 19 { 20 for(int y = 0;y < 30; y++) 21 { 22 Vector2 pos = new Vector2(x, y); 23 Quads[index] = Instantiate(Quad, pos, Quaternion.identity); 24 index++; 25 } 26 } 27 } 28 29 private void Update() 30 { 31 cameraSize = Camera.main.orthographicSize; 32 33 foreach(GameObject item in Quads) 34 { 35 if (cameraSize < 7.5f) 36 { 37 item.GetComponent<Renderer>().material.mainTexture = tex128128; 38 } 39 else if (cameraSize < 15) 40 { 41 item.GetComponent<Renderer>().material.mainTexture = tex6464; 42 } 43 else if (cameraSize < 20f) 44 { 45 item.GetComponent<Renderer>().material.mainTexture = tex3232; 46 } 47 } 48 } 49} 50

試したこと

カメラのorthographicSizeが大きくなると、テクスチャが潰れて見えてしまうため、orthographicSizeに応じて、

128×128

64×64

32×32

という風に、小さいサイズのテクスチャに変更するようにしたのですが、テクスチャが突然変更されるため、違和感があります。orthographicSizeに応じて、テクスチャが緩やかに変更されていくようにする方法は、あるでしょうか?

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

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

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

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

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

guest

回答2

0

ベストアンサー

私からも意見を申し上げさせていただくと、やはり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}

各レベルは下図のような画像を使ったところ...

tex128128tex6464tex3232
図1図2図3

下図のような見た目になりました。Orthographic Sizeが7.5までは赤色で、7.5から15にかけて次第に緑色に変わっていき、15から20にかけて次第に青色に変化しています。

図4

投稿2020/08/19 22:33

Bongo

総合スコア10807

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

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

退会済みユーザー

退会済みユーザー

2020/08/20 08:21

回答ありがとうございました。参考になりました。
guest

0

上手くいくか分かりませんが、間にもう一段階挟み、「128×128で見た目を64×64に近付けたテクスチャ」「64×64で見た目を32×32に近付けたテクスチャ」をセットすることで擬似的に補間出来ないでしょうか。

また、今回のニーズに合うか分かりませんが、Unity標準のmipmapシステムも確認してみるとよいかと思います。

投稿2020/08/19 00:47

sakura_hana

総合スコア11427

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

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

退会済みユーザー

退会済みユーザー

2020/08/19 04:07

回答ありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問