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

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

詳細はこちら
C#

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

Unity

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

Q&A

解決済

1回答

2019閲覧

Unity2D テクスチャが潰れる

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

Unity

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

0グッド

0クリップ

投稿2019/07/04 11:03

前提・実現したいこと

描画しているメッシュのテクスチャを潰れないようにしたい

該当のソースコード

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class CameraControlScript : MonoBehaviour 6{ 7 public Vector2 SPEED = new Vector2(0.3f, 0.3f); 8 9 public float zoomSpeed = 100; 10 public float targetOrtho; 11 public float smoothSpeed = 200; 12 public float minOrtho = 20; 13 public float maxOrtho = 130; 14 15 // Use this for initialization 16 void Start() 17 { 18 targetOrtho = Camera.main.orthographicSize; 19 } 20 21 // Update is called once per frame 22 void LateUpdate() 23 { 24 Vector3 pos = transform.position; 25 pos.z = -10; 26 pos.x = Mathf.Clamp(pos.x, 75, 175); 27 pos.y = Mathf.Clamp(pos.y, 20, 230); 28 29 transform.position = pos; 30 Move(); 31 32 float scroll = Input.GetAxis("Mouse ScrollWheel"); 33 if (scroll != 0.0f) 34 { 35 targetOrtho -= scroll * zoomSpeed; 36 targetOrtho = Mathf.Clamp(targetOrtho, minOrtho, maxOrtho); 37 } 38 39 Camera.main.orthographicSize = Mathf.MoveTowards(Camera.main.orthographicSize, targetOrtho, smoothSpeed * Time.deltaTime); 40 41 float speed = Camera.main.orthographicSize / 43.333f; 42 SPEED = new Vector2(speed, speed); 43 } 44 45 // 移動関数 46 void Move() 47 { 48 Vector3 Position = transform.position; 49 50 if (Input.GetKey("left")) 51 { 52 Position.x -= SPEED.x; 53 } 54 else if (Input.GetKey("right")) 55 { 56 Position.x += SPEED.x; 57 } 58 else if (Input.GetKey("up")) 59 { 60 Position.y += SPEED.y; 61 } 62 else if (Input.GetKey("down")) 63 { 64 Position.y -= SPEED.y; 65 } 66 67 transform.position = Position; 68 } 69} 70

試したこと

Unityの2Dプロジェクトを使っています。
別のスクリプトでメッシュを生成しており、CameraのSizeを上記のスクリプトを使い、マウスのスクロールで変更させているのですが、Sizeが極端に小さくないと、テクスチャが綺麗に描画されません。Sizeが6を超えた辺りから、テクスチャが潰れて、ただの色にしか見えなくなってしまいます。

イメージ説明

使っているテクスチャ↓

イメージ説明

理想は、以下の画像のように、メッシュとの距離が遠くても、テクスチャが潰れない状態です。

イメージ説明

Cameraのズーム倍率を制御するCamera.fieldOfViewを使ってみましたが、2Dプロジェクトでは機能しませんでした。

Sizeを変更したときのメッシュのちらつきを消すために、Generate Mip Mapsをオンにしてあります。Filter ModeはPointで、Pixels Per Unitは、画像の縦幅と同じにしています。

CameraのSizeを変更しない方法があるのかもしれませんが、自分が調べた限りは出てきませんでした。どのようにすれば、テクスチャが潰れずに、ズーム出来るようになるでしょうか? 回答よろしくお願い致します。

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

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

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

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

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

guest

回答1

0

ベストアンサー

現状では画面上だと数ピクセル~数十ピクセル四方しかないタイル上に320×320のテクスチャを貼っている状態かと思いますので、テクスチャが縮小されすぎて潰れていると言えそうです。
ズームの仕組みをいじってもおそらくダメなんじゃないでしょうかね...?もし仮にカメラのSizeを変えずに、代わりにたとえばワールドマップのメッシュオブジェクトのスケールを拡大縮小することで縮尺を操作したとしても、結局遠距離視点では状況的に同じことになってディテールが潰れてしまうでしょう。

テクスチャの反復周期をもっと長くして、広い範囲にマッピングしてやる必要があるかと思います。先日C# - Unity2D 描画がちらつく|teratailの回答中で申し上げた「2枚ポリゴン化作戦」で使用したWorldシェーダーをベースに、下記のように改変してみました。

ShaderLab

1Shader "Unlit/World" 2{ 3 Properties 4 { 5 _MainTex ("Texture", 2D) = "white" {} 6 _DataTex ("Data", 2D) = "black" {} 7 _Width ("Width", Int) = 250 8 _Height ("Height", Int) = 250 9 [IntRange] _Magnification ("Magnification", Range(1, 32)) = 8 10 [Toggle] _Dynamic ("Dynamic", Float) = 0 11 } 12 SubShader 13 { 14 Tags { "RenderType"="Opaque" } 15 16 Pass 17 { 18 CGPROGRAM 19 #pragma vertex vert 20 #pragma fragment frag 21 #pragma multi_compile _ _DYNAMIC_ON 22 #include "UnityCG.cginc" 23 24 struct appdata 25 { 26 float4 vertex : POSITION; 27 float2 uv : TEXCOORD0; 28 }; 29 30 struct v2f 31 { 32 float2 uv : TEXCOORD0; 33 float4 vertex : SV_POSITION; 34 }; 35 36 sampler2D _MainTex; 37 float4 _MainTex_ST; 38 float4 _MainTex_TexelSize; 39 sampler2D _DataTex; 40 float4 _DataTex_TexelSize; 41 int _Width; 42 int _Height; 43 int _Magnification; // 拡大率...たとえば8なら、マップ上の8x8タイルをテクスチャ反復の1周期とする 44 45 v2f vert(appdata v) 46 { 47 v2f o; 48 o.vertex = UnityObjectToClipPos(v.vertex); 49 o.uv = TRANSFORM_TEX(v.uv, _MainTex); 50 return o; 51 } 52 53 // 固定拡大...テクスチャ反復数を縮尺によらず一定にする 54 fixed4 fixedMagnification(v2f i) 55 { 56 float2 worldSize = float2(_Width, _Height); 57 float2 worldUv = i.uv * worldSize; 58 float2 tileCoord = floor(worldUv); 59 float2 dataUv = (tileCoord + 0.5) * _DataTex_TexelSize.xy; 60 float4 texCorners = tex2D(_DataTex, dataUv); 61 62 // worldUvを拡大率で割ることでtileUvの周期を長くする 63 worldUv /= _Magnification; 64 float2 tileUv = frac(worldUv); 65 66 // 画面上で1ピクセルずれるとUV座標がどれだけ飛ぶかを求めておく 67 float2 gradScale = texCorners.zw - texCorners.xy; 68 float2 dUvdx = ddx(worldUv) * gradScale; 69 float2 dUvdy = ddy(worldUv) * gradScale; 70 71 // UV座標の飛び幅だけUV矩形を小さくして隣接テクスチャの色漏れを防止する 72 // テクスチャの外周が少し削ぎ落とされる欠点はありますが、テクスチャに幅広い余白を設けなくとも 73 // 縮尺によらず安定して色漏れを防止できるんじゃないかと思います 74 float2 texCornerOffset = min(gradScale, max(_MainTex_TexelSize.xy, dUvdx + dUvdy)); 75 76 // ミップマップを使う場合、tex2Dだと引数に与えたUV座標の変化率を基にミップレベルが選択されますが 77 // 今回のように特殊なUV座標を使ってサンプリングすると、正しいレベルが選択されないことがあります 78 // そんな時はtex2Dgradを使うと、レベル選択に使われるUV変化率を独自に与えてやることができます 79 float2 uv = lerp(texCorners.xy + texCornerOffset, texCorners.zw - texCornerOffset, tileUv); 80 fixed4 col = tex2Dgrad(_MainTex, uv, dUvdx, dUvdy); 81 return col; 82 } 83 84 // 可変拡大...遠くから見たときほどテクスチャ反復数を減らす 85 fixed4 dynamicMagnification(v2f i) 86 { 87 // 基本拡大量は固定拡大版と同じ 88 float2 worldSize = float2(_Width, _Height); 89 float2 worldUv = i.uv * worldSize; 90 float2 tileCoord = floor(worldUv); 91 float2 dataUv = (tileCoord + 0.5) * _DataTex_TexelSize.xy; 92 float4 texCorners = tex2D(_DataTex, dataUv); 93 worldUv /= _Magnification; 94 float2 gradScale = texCorners.zw - texCorners.xy; 95 float2 dUvdx = ddx(worldUv) * gradScale; 96 float2 dUvdy = ddy(worldUv) * gradScale; 97 98 // 縮尺の程度による追加の拡大量を算出する 99 float2 magRatio = (dUvdx + dUvdy) * _MainTex_TexelSize.zw; 100 float level = log2(max(1.0, min(magRatio.x, magRatio.y))); 101 float levelIndex = floor(level); 102 float levelRatio = frac(level); 103 float extraScale = pow(0.5, levelIndex); 104 105 // 追加拡大を施してテクスチャをサンプリング 106 worldUv *= extraScale; 107 dUvdx *= extraScale; 108 dUvdy *= extraScale; 109 float2 tileUv = frac(worldUv); 110 float2 texCornerOffset = min(gradScale, max(_MainTex_TexelSize.xy, dUvdx + dUvdy)); 111 float2 uv = lerp(texCorners.xy + texCornerOffset, texCorners.zw - texCornerOffset, tileUv); 112 float4 col0 = tex2Dgrad(_MainTex, uv, dUvdx, dUvdy); 113 114 // さらにもう一段階拡大してテクスチャをサンプリングし... 115 worldUv *= 0.5; 116 dUvdx *= 0.5; 117 dUvdy *= 0.5; 118 tileUv = frac(worldUv); 119 texCornerOffset = min(gradScale, max(_MainTex_TexelSize.xy, dUvdx + dUvdy)); 120 uv = lerp(texCorners.xy + texCornerOffset, texCorners.zw - texCornerOffset, tileUv); 121 float4 col1 = tex2Dgrad(_MainTex, uv, dUvdx, dUvdy); 122 123 // 2つを混ぜることでレベル間のつなぎ目をなめらかにする 124 fixed4 col = lerp(col0, col1, levelRatio); 125 return col; 126 } 127 128 fixed4 frag(v2f i) : SV_Target 129 { 130 #ifdef _DYNAMIC_ON 131 return dynamicMagnification(i); 132 #else 133 return fixedMagnification(i); 134 #endif 135 } 136 ENDCG 137 } 138 } 139}

Generate Mip Mapsオン、Filter ModeはTrilinearとし、マテリアルのMagnificationは32、Dynamicはオフだと下図のような見え方になりました。タイルの数は250×250ですが、テクスチャは32×32タイルで1周期になるようにしましたので、ある程度離れた位置からでも砂紋の形が見えます。ですがマップ全域が映るほどの距離になるとディテールがわかりにくくなりますね。

図1

Magnificationを4、Dynamicオンだと下図のような見え方になりました。遠距離であるほどテクスチャ反復数が小さくなるので、マップ全域でも砂紋(このスケールだと砂丘でしょうか)が見えています。一部分を拡大していくと全体と同じ形が再帰的に現れるような動作で面白そうだと思ったのですが、その分ちょっとDynamicオフよりも計算量は多くなってしまいます。

図2

投稿2019/07/06 22:20

Bongo

総合スコア10811

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

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

退会済みユーザー

退会済みユーザー

2019/07/07 10:11 編集

いつも参考になる回答ありがとうございます。質問の内容とは直接関係ないのですが、BongoさんはどのようにしてUnityのスクリプトやシェーダーの勉強をしたのでしょうか?自分もBongoさんのようにスクリプトやシェーダーを書けるようになりたいのですが、独学しようにもインターネットの情報くらいしかないような気がしていて、上手くいきません。市販の本は入門ばかりで、あまり役に立たないような感じがしています。もしよかったら教えていただきたいです。
Bongo

2019/07/07 21:28

そうですね...私も時々本屋をのぞきに行ったりしますが、やはり需要的な理由からか入門書がほとんどで物足りないかもしれませんね。 特に多少発展的な内容だったりシェーダープログラミングのことになったりすると、Unityについての本に絞ってしまうと大型書店でもまず見つからないと思います。ですが、Unityに限らなければいろいろ役立ちそうなものが見つかるんじゃないでしょうか。 範囲が広がった分、逆にこれだという一冊を例示するのが難しいですが、たとえばシェーダー周りなら「リアルタイム レンダリング」( http://www.realtimerendering.com/ )とか「GPU Gems」( https://developer.nvidia.com/gpugems/GPUGems/ )とかでしょうか...?たとえ数年~十数年前の情報でも、グラフィックス描画の基本的な理屈は今でも変わりませんので役立つはずです。 興味のおもむくまま使えそうなネタをつまみ食いしていってもいいでしょう。ご質問者さんは優れた学習意欲をお持ちのようですので、それらを起点に周辺情報を検索してみますとじきに習熟するかと思います。応援しております!
退会済みユーザー

退会済みユーザー

2019/07/08 08:58 編集

お忙しい中、ご返信ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問