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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Unity

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

Q&A

解決済

1回答

6317閲覧

unityのマテリアルのサイズが一定にならない

pin03

総合スコア23

Unity

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

0グッド

0クリップ

投稿2018/11/14 02:55

編集2018/11/14 06:22

サイズの違う二つのキューブに同じマテリアルをつけているのですが。サイズの大きいキューブに貼ったマテリアルが伸びてしまって全然違うマテリアルに見えてしまいます。オブジェクトのサイズ関係なくマテリアルの画像の大きさが一定になる設定をしたいのですが、どうのようにしたらよいのでしょうか?

(現在のマテリアルは模様の入った石の画像を読み込んでおり、インスペクターのTilingから数値を)

---------追記-------------------

·マテリアルをオブジェクトの数だけ作成し、そのオブジェクトごとにTiling値を調整する
·UVマッピングで対応する

という回答をいただいたのですが、
実は取り扱っているオブジェクトが大量にあり、それぞれ大きさちが違います。
そのすべてに同じマテリアルを充てたいです。(質問分のとおり、テクスチャが伸びないように)

上記の二つの方法でも対応できそうですが、かなり手間と時間がかかってしまいそうです。

エディター拡張などでテクスチャの大きさがオブジェクトの大きさに比例されないような
設定を作成できるのでしょうか?

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2018/11/14 05:59 編集

似た様な質問を受付中のまま繰り返すのは回答者に失礼なので改めて投稿するなら以前のは取り合えず解決済みにするなどしてはどうでしょう。個人的にはhttps://teratail.com/questions/154950の質問に対する回答のUV作成で対応可能な問題かと思いますがUnityだけで行いたいなど拘りがあるのでしょうか?
pin03

2018/11/14 06:13

対応は可能なのでしょうが、UVマッピングに関しての知識がなく、また時間がなかったためunityの機能で、そのような設定があるはずだと思い込んで質問をいたしましたが、ないのかもしれませんね。。ご指摘いただきましたように前回の質問は解決済にいたします。
guest

回答1

0

ベストアンサー

あるモデルに対してそれ専用のテクスチャを貼り付ける場合にはUVマッピングが適していますが(たいていの場合はUVマッピングでまかなえると思います)、今回のような様々なオブジェクトに同一のスケールで質感を与えたいケースは不得意でしょうね。

ここはモデルのUV座標を無視したマッピング技法の方が有利かもしれません。三平面マッピングは試してみる価値があるかと思います。アセットストアで「Triplanar」で検索しますと、有用そうなアセットが出てきました。
他にも、Unity - Unity-テクスチャを1マスごとに敷きつめる|teratailのKapustinさんの案や、GitHub - keijiro/StandardTriplanar: Unity's standard shader with triplanar mappingがご参考になるかと思います。

keijiroさんのマテリアルを試してみましたが、こちらは法線テクスチャ・オクルージョンテクスチャもセット可能で、岩肌などの表現にはほとんど問題ないかと思います。コードも比較的シンプルで読解しやすく、実行時の負荷も低めだろうと予想されます。

ですが、条件によっては粗が見えてしまうかもしれません。Standardマテリアル(Unityで標準的に使われる、モデルのUV座標に基づいたマッピング)の場合下図のように見えるシーンを...
Standard
keijiroさんのマテリアルに変更すると下図のようになります。
keijiro
これはわざと粗が目立つように作ったシーンでして、地面のPlaneと左のCylinderはスケールが(1, 1, 1)ですので木のブロックの大きさがほぼ同じになっていますが、上のCubeはスケール(2, 2, 1)、右のCapsuleは(2, 2, 2)、下のSphereは(1.5, 1, 1)で、ブロック模様が大きくなったり、引き伸ばされてしまっています。これはマッピング座標の決定にメッシュのモデル座標をそのまま使用しているためで、Unity上でのスケール設定が考慮されていないことによります。
また、静止画ではわかりにくいかもしれませんが、Cubeの手前側の面の凹凸が反転し、溝の部分が出っ張ってしまっています。これは法線テクスチャからサンプリングした法線をそのまま使っており、接空間の向き合わせを行っていないことによります。この接空間問題についてはNormal Mapping for a Triplanar Shader – Ben Golus – Mediumに詳しく解説されておりました。サイトの図を引用させていただきますと...

接空間を考慮しない陰影期待される陰影
NaiveGround Truth

陰影が場所によってまちまちになってしまい、岩肌であれば目立たないものの、レンガのような人工物では気になりそうです。

上記スケール問題・接空間問題と、ついでにもう一つ、X方向に投影されたテクスチャが90°回転してしまう問題(キューブの側面が顕著です)の対策を検討してみました。コードの大部分が接空間の向き合わせで占拠されています...

ShaderLab

1Shader "Custom/ObjectTriplanar" 2{ 3 Properties 4 { 5 _PixelsPerUnit ("Pixels Per Unit", Float) = 128.0 6 _Color ("Color", Color) = (1, 1, 1, 1) 7 _MainTex ("Albedo", 2D) = "white" { } 8 _Glossiness ("Smoothness", Range(0.0, 1.0)) = 0.5 9 [Gamma] _Metallic ("Metallic", Range(0.0, 1.0)) = 0.0 10 _BumpScale ("Bump Scale", Float) = 1.0 11 [Normal][NoScaleOffset] _BumpMap ("Normal", 2D) = "bump" { } 12 [NoScaleOffset] _OcclusionMap ("Occlusion", 2D) = "white" { } 13 } 14 SubShader 15 { 16 Tags { "RenderType" = "Opaque" "DisableBatching" = "True" } 17 18 CGPROGRAM 19 20 // OpenGL ESには非対応...OpenGL ES対応にしたい場合、非正方行列を使用している箇所を書き換える必要がある 21 #pragma exclude_renderers gles 22 #pragma surface surf Standard vertex:vert fullforwardshadows addshadow 23 #pragma target 3.5 24 25 float _PixelsPerUnit; 26 fixed4 _Color; 27 sampler2D _MainTex; 28 float4 _MainTex_ST; 29 float4 _MainTex_TexelSize; 30 half _Glossiness; 31 half _Metallic; 32 half _BumpScale; 33 sampler2D _BumpMap; 34 sampler2D _OcclusionMap; 35 36 struct Input 37 { 38 float3 objectUV; 39 float3 objectNormal; 40 float4 objectTangent; 41 }; 42 43 // カットオフ方式の混合比算出 44 // カットオフが0.57くらいを上回ると、コーナー部分が欠落してしまうので注意 45 float3 cutoffBlending(float3 normalAbs, float cutoff) 46 { 47 float3 factor = max(normalAbs - cutoff, 0.0001); 48 return factor / dot(factor, (float3)1.0); 49 } 50 51 // 冪乗方式の混合比算出 52 float3 powerBlending(float3 normalAbs, float exponent) 53 { 54 float3 factor = pow(normalAbs, exponent); 55 return factor / dot(factor, (float3)1.0); 56 } 57 58 // Y-XZ非対称方式の混合比算出 59 // 人工物のテクスチャにはこれが効果的か? 60 float3 asymmetricBlending(float3 normalAbs, float exponent, float capCos, float borderHalfWidth) 61 { 62 float normalAbsXZMax = max(normalAbs.x, normalAbs.z); 63 float2 factorXZ = pow(normalAbsXZMax > 0.0 ? normalAbs.xz / normalAbsXZMax: (float2)1.0, exponent); 64 factorXZ /= dot(factorXZ, (float2)1.0); 65 float factorY = smoothstep(capCos - borderHalfWidth, capCos + borderHalfWidth, normalAbs.y); 66 float factorH = 1.0 - factorY; 67 float3 factor = float3(factorXZ.x * factorH, factorY, factorXZ.y * factorH); 68 return factor; 69 } 70 71 // 虚部xyz、実部wで表現される回転クォータニオンを行列形式にする 72 float3x3 rotationFromQuaternion(float4 q) 73 { 74 float3 nA = q.xyz * 2.0; 75 float3 nB = q.xyz * nA; 76 float3 nC = q.xxy * nA.yzz; 77 float3 nD = q.www * nA; 78 float3 nE = 1.0 - (nB.yzx + nB.zxy); 79 float3 nF = nC + nD.zyx; 80 float3 nG = nC - nD.zyx; 81 return float3x3( 82 nE.x, nG.x, nF.y, 83 nF.x, nE.y, nG.z, 84 nG.y, nF.z, nE.z); 85 } 86 87 // fromからtoへの最短回転行列を作成する 88 float3x3 fromToRotation(float3 from, float3 to) 89 { 90 float3 axisU = cross(from, to); 91 float axisULength = length(axisU); 92 float clampedAxisULength = max(axisULength, 0.001); 93 float angleIsValid = sign(axisULength); 94 float cosTheta = dot(from, to); 95 float3 axis = angleIsValid > 0.0 ? axisU / clampedAxisULength : float3(1.0, 0.0, 0.0); 96 float2 cosThetaHSinThetaH = sqrt(((float2)1.0 + float2(1.0, -1.0) * cosTheta) * 0.5); 97 return rotationFromQuaternion(float4(axis * cosThetaHSinThetaH.y, cosThetaHSinThetaH.x)); 98 } 99 100 void vert(inout appdata_full v, out Input IN) 101 { 102 UNITY_INITIALIZE_OUTPUT(Input, IN); 103 104 // 3面のUV座標 105 // オブジェクト座標をベースとし、それにワールドスケール推定値をかけて 106 // ワールド空間におけるテクスチャのスケールが一定になるようにする 107 IN.objectUV = v.vertex.xyz * float3( 108 length(unity_ObjectToWorld._m00_m10_m20), 109 length(unity_ObjectToWorld._m01_m11_m21), 110 length(unity_ObjectToWorld._m02_m12_m22)); 111 112 // オブジェクト法線 113 IN.objectNormal = v.normal; 114 115 // オブジェクト接線 116 IN.objectTangent = v.tangent; 117 } 118 119 void surf(Input IN, inout SurfaceOutputStandard o) 120 { 121 // オブジェクト空間->Unity接空間への変換を作成 122 // 接線のwには従法線の反転の有無が格納されているので、それを従法線にかけている 123 float3 objectNormal = normalize(IN.objectNormal); 124 float3 objectTangent = normalize(IN.objectTangent.xyz); 125 float3 objectBinormal = cross(objectNormal, objectTangent) * IN.objectTangent.w; 126 float3x3 objectToTangent = float3x3(objectTangent, objectBinormal, objectNormal); 127 128 // オブジェクト法線の成分の絶対値を求める...3方向のブレンド比算出に使う 129 float3 objectNormalAbs = abs(objectNormal); 130 131 // オブジェクト法線の成分の符号を求める...UV・接空間補正に使う 132 float3 s = sign(objectNormal); 133 134 // 3方向のUV座標を作成 135 // サイコロを十字に切り開く展開をイメージしたため、keijiroさん方式と異なり3方向の式が非対称になっている 136 // 137 // +Y 138 // +Z -X -Z +X 139 // -Y 140 // 141 float2 uvMultiplier = _PixelsPerUnit * _MainTex_TexelSize.xy * _MainTex_ST.xy; 142 float2 objectUVX = _MainTex_ST.zw + uvMultiplier * IN.objectUV.zy * float2(s.x, 1.0); 143 float2 objectUVY = _MainTex_ST.zw + uvMultiplier * IN.objectUV.zx * float2(-1.0, s.y); 144 float2 objectUVZ = _MainTex_ST.zw + uvMultiplier * IN.objectUV.xy * float2(-s.z, 1.0); 145 146 // 3方向の平面接空間->オブジェクト空間への変換を作成 147 // こちらもやはり3方向の接空間が非対称になっている 148 // 接空間の基底は右手系になっている点に注意 149 // テクスチャ赤が左から右、緑が下から上、青が奥から手前を指す 150 float3 tPXNormal = float3(s.x, 0.0, 0.0); 151 float3 tPYNormal = float3(0.0, s.y, 0.0); 152 float3 tPZNormal = float3(0.0, 0.0, s.z); 153 float3 tPXTangent = float3(0.0, 0.0, s.x); 154 float3 tPYTangent = float3(0.0, 0.0, -1.0); 155 float3 tPZTangent = float3(-s.z, 0.0, 0.0); 156 float3 tPXBinormal = float3(0.0, 1.0, 0.0); 157 float3 tPYBinormal = float3(s.y, 0.0, 0.0); 158 float3 tPZBinormal = float3(0.0, 1.0, 0.0); 159 float3x3 tPXToObject = transpose(float3x3(tPXTangent, tPXBinormal, tPXNormal)); 160 float3x3 tPYToObject = transpose(float3x3(tPYTangent, tPYBinormal, tPYNormal)); 161 float3x3 tPZToObject = transpose(float3x3(tPZTangent, tPZBinormal, tPZNormal)); 162 163 // 3方向の法線->オブジェクト法線への回転を求め、平面接空間->Unity接空間への合成変換を作成 164 float3x3 tPXToTangent = mul(objectToTangent, mul(fromToRotation(tPXNormal, objectNormal), tPXToObject)); 165 float3x3 tPYToTangent = mul(objectToTangent, mul(fromToRotation(tPYNormal, objectNormal), tPYToObject)); 166 float3x3 tPZToTangent = mul(objectToTangent, mul(fromToRotation(tPZNormal, objectNormal), tPZToObject)); 167 168 // 3方向の法線をテクスチャから取得、ついでにUnity接空間上のベクトルに変換 169 float3x3 normals = transpose(float3x3( 170 mul(tPXToTangent, UnpackScaleNormal(tex2D(_BumpMap, objectUVX), _BumpScale)), 171 mul(tPYToTangent, UnpackScaleNormal(tex2D(_BumpMap, objectUVY), _BumpScale)), 172 mul(tPZToTangent, UnpackScaleNormal(tex2D(_BumpMap, objectUVZ), _BumpScale)))); 173 174 // 3方向のアルベド・遮蔽率をテクスチャから取得 175 float4x3 albedoOcclusions = transpose(float3x4( 176 tex2D(_MainTex, objectUVX).rgb, tex2D(_OcclusionMap, objectUVX).a, 177 tex2D(_MainTex, objectUVY).rgb, tex2D(_OcclusionMap, objectUVY).a, 178 tex2D(_MainTex, objectUVZ).rgb, tex2D(_OcclusionMap, objectUVZ).a)); 179 180 // 3方向の混合比を算出 181 // Ben Golusさんの方法を参考にした、Y-XZ非対称混合を採用 182 float3 factor = asymmetricBlending(objectNormalAbs, 64.0, 0.5, 1.0 / 64.0); 183 // 冪乗混合の場合は下記 184 //float3 factor = powerBlending(objectNormalAbs, 128.0); 185 186 // アルベド・遮蔽率を合成 187 float4 albedoOcclusion = mul(albedoOcclusions, factor) * float4(_Color.rgb, 1.0); 188 189 // 法線を合成 190 float3 normal = normalize(mul(normals, factor)); 191 192 //#define DEBUG_TANGENT_NORMAL 193 //#define DEBUG_OBJECT_NORMAL 194 //#define DEBUG_WORLD_NORMAL 195 //#define DEBUG_ALBEDO 196 //#define DEBUG_OCCLUSION 197 198 o.Albedo = albedoOcclusion.rgb; 199 o.Normal = float3(0.0, 0.0, 1.0); 200 o.Metallic = 0.0; 201 o.Smoothness = 0.0; 202 o.Occlusion = albedoOcclusion.a; 203 #if defined(DEBUG_TANGENT_NORMAL) 204 o.Albedo = normal * 0.5 + 0.5; 205 #elif defined(DEBUG_OBJECT_NORMAL) 206 o.Albedo = mul(transpose(objectToTangent), normal) * 0.5 + 0.5; 207 #elif defined(DEBUG_WORLD_NORMAL) 208 o.Albedo = UnityObjectToWorldNormal(mul(transpose(objectToTangent), normal)) * 0.5 + 0.5; 209 #elif defined(DEBUG_ALBEDO) 210 #elif defined(DEBUG_OCCLUSION) 211 o.Albedo = albedoOcclusion.a; 212 #else 213 o.Normal = normal; 214 o.Metallic = _Metallic; 215 o.Smoothness = _Glossiness; 216 #endif 217 } 218 ENDCG 219 } 220 FallBack Off 221}

これを使ったところ、下図のようにブロックの大きさが大体一定になりました。
ObjectTriplanar

投稿2018/11/14 12:28

編集2018/11/14 12:33
Bongo

総合スコア10811

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

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

pin03

2018/11/21 01:10

できました!ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問