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

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

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

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

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

Q&A

解決済

1回答

26100閲覧

Unityでオブジェクトの一部のみの色を動的に変える

GeeChiki

総合スコア12

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

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

3グッド

9クリップ

投稿2018/01/28 10:15

編集2018/01/28 10:16

オブジェクトの一部のみをスクリプトから色を変える方法ありますでしょうか。
例えば、

void changeObjectColor(){ gameobject.GetComponent<Renderer>().material.color = new Color(0.3f, 0.4f, 0.9f, 0.3f); }

が実行されれば、このスクリプトがアタッチされているオブジェクトが指定の色になるかと思います。

しかし、例えば、球体が水没するシーンがあったとして、水中にある部分と、空中にある部分が同時に存在する時、同じオブジェクトでも色が違う部分が生まれます。
この場合、どのようにすれば、オブジェクトの一部のみの色を動的に変えることができますでしょうか。

調査してみたところ、知恵袋でヒットしましたが、
detail.chiebukuro.yahoo.co.jp/qa/question_detail/q14173810644
「ポリゴン単位で良ければ、頂点カラーをscriptで制御」「シェーダーにて色が変化する部分を示すマップテクスチャを用意し、その部分にだけ、色を線形補間」という部分がどうすれば良いかわかりません。

このあたりを勉強すればいい、という方向性だけでも頂けると非常に助かります。
何卒よろしくお願いいたします。

UNICO.SA, Bongo, suittizihou👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

知恵袋の回答者の方は最初に「1部だけ違う色のテクスチャを用意しましょう」とおっしゃっていますが、その方法や「頂点カラーをscriptで制御しましょう」、そしておそらく「色が変化する部分を示すマップテクスチャを用意し」といった案も、オブジェクトのモデル座標を基準に部分的に色を変えることを想定したもののように感じます。

今回ご質問者さんは、水面に浮かぶ物体のようなワールド座標を基準とした色分けを想定されているご様子です。それを知恵袋のご回答者さんの方針で進めた場合、いくらか複雑になりそうな気配がしました。

ちょっと違うアプローチですが、メニューの「Assets」→「Create」→「Shader」→「Standard Surface Shader」で新規サーフェスシェーダーを作り、そのデフォルトのコードを一部書き換えてやれば、比較的簡単にワールド座標基準の2色塗りができそうです。
方針としては...

  • 第2の色のプロパティを追加する。
  • 2つの色を分ける高さ(ご質問者さんの想定における水面の位置)を表すプロパティを追加する。
  • サーフェスシェーダーに供給される入力情報として、ピクセルのワールド座標を追加する。
  • デフォルトのコードでは、テクスチャから取得した色に一つの塗り色を掛けて最終的なアルベド色として返しているが、この掛ける塗り色をピクセルのワールド座標に応じて二つの色から選ぶようにする。

あとはこのシェーダーを使ったマテリアルを作り、スクリプトから色を変えたい場合はそれぞれの色をSetColorなどで設定してやればいいかと思います。

デフォルトのサーフェスシェーダーに、たとえば下記のように手を加えて...

Shader "Custom/MultiColored" { Properties { _Color ("Color", Color) = (1,1,1,1) _SecondaryColor ("Secondary Color", Color) = (1,1,1,1) // 追加...第2の色 _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 _SeparationHeight ("Separation Height", Float) = 0.0 // 追加...ワールドYがこれより上なら_Color、下なら_SecondaryColorで塗ることにする } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM // Physically based Standard lighting model, and enable shadows on all light types #pragma surface surf Standard fullforwardshadows // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 sampler2D _MainTex; struct Input { float2 uv_MainTex; float3 worldPos; // 追加...注目点のワールド空間内の座標が自動的に入れられる // その他追加できる変数の一覧は https://docs.unity3d.com/Manual/SL-SurfaceShaders.html の下の方にありました }; half _Glossiness; half _Metallic; fixed4 _Color; fixed4 _SecondaryColor; // 追加...追加したプロパティの値を受け取る変数 float _SeparationHeight; // 追加...追加したプロパティの値を受け取る変数 // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader. // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing. // #pragma instancing_options assumeuniformscaling UNITY_INSTANCING_BUFFER_START(Props) // put more per-instance properties here UNITY_INSTANCING_BUFFER_END(Props) void surf (Input IN, inout SurfaceOutputStandard o) { // Albedo comes from a texture tinted by color // 変更...surf内でworldPosを受け取れるようになったので、追加したプロパティ_SeparationHeightとY座標を比較し、_Colorと_SecondaryColorを切り替えてテクスチャ色に掛ける fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * lerp(_SecondaryColor, _Color, step(_SeparationHeight, IN.worldPos.y)); o.Albedo = c.rgb; // Metallic and smoothness come from slider variables o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }

スクリプトからの色の設定は下記のようにしてみました。

C#

1using UnityEngine; 2 3[RequireComponent(typeof(Renderer))] 4public class GlobeController : MonoBehaviour { 5 6 public float HueSpeed = 0.25f; 7 public float MotionSpeed = 0.25f; 8 public float MotionAmplitude = 0.25f; 9 10 private Material material; 11 12 private void Start () { 13 this.material = this.GetComponent<Renderer>().material; 14 } 15 16 private void Update () { 17 // 時間とともに色合いを変える 18 var hue1 = Mathf.Repeat(Time.time * this.HueSpeed, 1.0f); 19 var color1 = Color.HSVToRGB(hue1, 0.5f, 1.0f); 20 var hue2 = Mathf.Repeat(hue1 + 0.5f, 1.0f); 21 var color2 = Color.HSVToRGB(hue2, 0.5f, 1.0f); 22 23 // Set系メソッドでマテリアルに情報を渡す 24 material.SetColor("_Color", color1); 25 material.SetColor("_SecondaryColor", color2); 26 27 // 時間とともにY位置を上下させる 28 var angle = Mathf.Repeat(Time.time * this.MotionSpeed, 1.0f) * 2.0f * Mathf.PI; 29 var y = Mathf.Sin(angle) * this.MotionAmplitude; 30 31 transform.position = new Vector3(0.0f, y, 0.0f); 32 } 33}

すると、下図のようにワールド座標における特定の高さの上下で塗り分けられます。
プレビュー
サーフェスシェーダーについては本家マニュアルの他にも色々な方が解説記事を書いておられるようです。
たとえばサーフェイスシェーダー、頂点・フラグメントシェーダー入門 - Qiitaなどはイメージを掴むのによさそうに思いましたが、いかがでしょうか。

※補足を追記
うっかり第2の色プロパティに_SecondaryColorなんて名前を付けてしまいましたが、専門用語のSecondary color二次色)とかぶってしまいました。
_Color_SecondaryColor」より「_Color1_Color2」とか「_UpperColor_LowerColor」の方がよかったかもしれません。

投稿2018/01/28 14:01

編集2018/01/28 20:49
Bongo

総合スコア10807

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

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

GeeChiki

2018/01/29 14:31

素晴らしいです!!ここまで丁寧に解説して頂けるとは・・! シェーダーを触って見たことがなかったので、こちらを参考にやってみます!参考URLとGif(やりたいことそのものでした)も頂きありがとうございました。
GeeChiki

2018/01/30 11:02

シェーダーを触り始めて30分くらいで出来てしまいました・・!しかもおぼろけながら内容も分かった気に。前に公式からやってみようとした時は挫折してしまいましたが、こちらは導入としては最高ですね。本当にありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問