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

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

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

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

Q&A

解決済

1回答

936閲覧

shaderの色変更

c_c_mk2

総合スコア11

Unity

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

0グッド

0クリップ

投稿2021/10/23 13:40

前提・実現したいこと

お絵描きのコードを拾ったのですが色変更の仕方がわかりません
どこを変更したら背景とペイントの色を変更できるのでしょうか

イメージ説明

該当のソースコード

public class Suibokuga : MonoBehaviour { [SerializeField] Shader shader; Material mat; [SerializeField] Texture2D paper; [SerializeField, Range(0f, 1f)] float alpha = 1.0f; [SerializeField, Range(0f, 0.005f)] float evaporation = 0.0001f; [SerializeField, Range(0, 10)] int iterations = 4; [SerializeField] int size = 1024; FboPingPong fpp; [SerializeField]float thickness =0.015f; bool dragging = false; Vector2 previous; void Start () { fpp = new FboPingPong(size, size); mat = new Material(shader); mat.SetTexture("_PaperTex", paper); Init(); } void Update () { Vector3 mousePos = Input.mousePosition; Vector2 current = new Vector2(mousePos.x / Screen.width, mousePos.y / Screen.height); mat.SetVector("_Prev", previous); if(dragging) { mat.SetVector("_Brush", new Vector3(current.x, current.y, thickness)); } else { mat.SetVector("_Brush", new Vector3(0, 0, 0)); } if(Input.GetMouseButtonDown(0)) { dragging = true; } else if(Input.GetMouseButtonUp(0)) { dragging = false; } previous = current; mat.SetFloat("_Alpha", alpha); mat.SetFloat("_Evaporation", evaporation); for(int i = 0; i < iterations; i++) { Graphics.Blit(fpp.GetReadTex(), fpp.GetWriteTex(), mat, 1); // update fpp.Swap(); } if(Input.GetMouseButtonDown(2)) { Init(); } } void Init () { Graphics.Blit(fpp.GetReadTex(), fpp.GetWriteTex(), mat, 0); // init fpp.Swap(); } void OnRenderImage (RenderTexture src, RenderTexture dst) { Graphics.Blit(fpp.GetReadTex(), dst, mat, 2); } }
namespace Utils { public class FboPingPong { private int _readTex = 0; private int _writeTex = 1; private RenderTexture[] _buffer; /// <summary> /// Init the specified width_ and height_. /// </summary> /// <param name="width_">Width_.</param> /// <param name="height_">Height_.</param> public FboPingPong (int width_, int height_, FilterMode filterMode = FilterMode.Point, TextureWrapMode wrapMode = TextureWrapMode.Repeat){ _readTex = 0; _writeTex = 1; _buffer = new RenderTexture [2]; for (int i = 0; i < 2; i++){ _buffer [i] = new RenderTexture (width_, height_, 0, RenderTextureFormat.ARGBFloat); _buffer [i].hideFlags = HideFlags.DontSave; _buffer [i].filterMode = filterMode; _buffer [i].wrapMode = wrapMode; _buffer [i].Create (); } Clear (); } /// <summary> /// Swap buffers. /// </summary> public void Swap (){ //RenderTexture temp = _buffer[0]; //_buffer [0] = _buffer [1]; //_buffer [1] = temp; int t = _readTex; _readTex = _writeTex; _writeTex = t; } /// <summary> /// Clear buffers. /// </summary> public void Clear (){ for (int i = 0; i < _buffer.Length; i++){ RenderTexture.active = _buffer [i]; //GL.Clear (false, true, Color.black); GL.Clear (false, true, Color.yellow); RenderTexture.active = null; } } /// <summary> /// Delete buffers. /// </summary> public void Delete (){ if (_buffer != null) { for (int i = 0; i < _buffer.Length; i++){ _buffer[i].Release (); _buffer[i].DiscardContents (); _buffer[i] = null; } } } /// <summary> /// Gets the read tex. /// </summary> /// <returns>The read tex.</returns> public RenderTexture GetReadTex (){ return _buffer [_readTex]; } /// <summary> /// Gets the write tex. /// </summary> /// <returns>The write tex.</returns> public RenderTexture GetWriteTex (){ return _buffer [_writeTex]; } } }
Shader "Suibokuga/Suibokuga" { Properties { _MainTex ("Water Texture", 2D) = "white" {} _Alpha ("Transfer/Diffusion coefficient for water particles", Range(0.01, 1.5)) = 1.0 _Evaporation ("a unit quantity of water for evaporation", Range(0.0001, 0.005)) = 0.00015 _PaperTex ("Paper Texture", 2D) = "white" {} _Brush ("brush", Vector) = (-1, -1, -1, -1) _Prev ("previous brush position", Vector) = (-1, -1, -1, -1) } CGINCLUDE #include "UnityCG.cginc" #pragma target 3.0 /* * r : water particles * b : capacities of water * a : the heights of the bottoms */ sampler2D _MainTex; float4 _MainTex_TexelSize; float _Alpha; float _Evaporation; sampler2D _PaperTex; float2 _Prev; float3 _Brush; // x,y : position, z : size struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; v2f vert (appdata IN) { v2f OUT; OUT.vertex = UnityObjectToClipPos(IN.vertex); OUT.uv = IN.uv; return OUT; } void sample (float2 uv, out float4 o, out float4 l, out float4 t, out float4 r, out float4 b) { float2 texel = _MainTex_TexelSize.xy; o = tex2D(_MainTex, uv); l = tex2D(_MainTex, uv + float2(-texel.x, 0)); t = tex2D(_MainTex, uv + float2( 0, -texel.y)); r = tex2D(_MainTex, uv + float2( texel.x, 0)); b = tex2D(_MainTex, uv + float2( 0, texel.y)); } float waterDelta (float4 k, float4 o) { float ld = (k.w + k.x) - (o.w + o.x); // level difference float transfer = (k.w + k.x) - max(o.w, k.w + k.z); // transferable water particles return max( 0.0, 0.25 * _Alpha * min(ld, transfer) ); } float waterFlow (float2 uv) { float4 o, l, t, r, b; sample(uv, o, l, t, r, b); float nw = o.r; nw += (waterDelta(l, o) - waterDelta(o, l)); nw += (waterDelta(t, o) - waterDelta(o, t)); nw += (waterDelta(r, o) - waterDelta(o, r)); nw += (waterDelta(b, o) - waterDelta(o, b)); return max(nw, 0); } float evaporation (float wo) { return max(wo - _Evaporation, 0.0); } float brush (float2 uv) { const int count = 10; float2 dir = _Brush.xy - _Prev.xy; float l = length(dir); if(l <= 0) { float d = length(uv - _Brush.xy); return smoothstep(0.0, _Brush.z, _Brush.z - d); } float ld = l / count; float2 norm = normalize(dir); float md = 100; for(int i = 0; i < count; i++) { float2 p = _Prev.xy + norm * ld * i; float d = length(uv - p); if(d < md) { md = d; } } return smoothstep(0.0, _Brush.z, _Brush.z - md); // float d = length(uv - _Brush.xy); // return smoothstep(0.0, _Brush.z, _Brush.z - d); } ENDCG SubShader { Cull Off ZWrite Off ZTest Always Pass { CGPROGRAM #pragma vertex vert #pragma fragment init float4 init (v2f IN) : SV_Target { float4 paper = tex2D(_PaperTex, IN.uv); return float4( 0, 0, paper.r, paper.r ); } ENDCG } Pass { CGPROGRAM #pragma vertex vert #pragma fragment waterUpdate float4 waterUpdate (v2f IN) : SV_Target { float4 col = tex2D(_MainTex, IN.uv); col.x = evaporation(waterFlow(IN.uv)); float dw = brush(IN.uv); // if(dw > 0) { col.x = min(col.x + brush(IN.uv), 1.0); // } return col; } } Pass { CGPROGRAM #pragma vertex vert #pragma fragment visualize float4 visualize (v2f IN) : SV_Target { float4 col = tex2D(_MainTex, IN.uv); return float4(1.0 - col.xxx, 1.0); } ENDCG } } }

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

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

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

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

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

guest

回答1

0

ベストアンサー

ご参考になさったのは「unity-cellular-automaton-based-ink-simulation」でしょうかね?墨がじわっとにじんでおしゃれな感じですね。

色の変更についてですが、ペイント色が単色でもかまわなければ(つまり水彩画のようにさまざまな絵の具を使い分けていくのではなく、背景色やペイント色を変更すると既存の絵の色も一斉に変わってしまう状態)、比較的簡単に改修できそうです。

まず、Suibokugaシェーダーには下記のような変更を加えました。前景色と背景色をセット可能にするとともに、2番パス(シェーダーコードの一番末尾に記述されている、墨拡散シミュレーションの結果を画面にレンダリングするためのパス)でそれらの色を使うように変更しています。

ShaderLab

1Shader "Suibokuga/Suibokuga" { 2 3 Properties { 4 _MainTex ("Water Texture", 2D) = "white" {} 5 _Alpha ("Transfer/Diffusion coefficient for water particles", Range(0.01, 1.5)) = 1.0 6 _Evaporation ("a unit quantity of water for evaporation", Range(0.0001, 0.005)) = 0.00015 7 8 _PaperTex ("Paper Texture", 2D) = "white" {} 9 10 _Brush ("brush", Vector) = (-1, -1, -1, -1) 11 _Prev ("previous brush position", Vector) = (-1, -1, -1, -1) 12 13 // 前景色・背景色プロパティを追加する 14 _Color ("Foreground Color", Color) = (0.0, 0.0, 0.0, 1.0) 15 _BackgroundColor ("Background Color", Color) = (1.0, 1.0, 1.0, 1.0) 16 } 17 18 CGINCLUDE 19 20 #include "UnityCG.cginc" 21 #pragma target 3.0 22 23 /* 24 * r : water particles 25 * b : capacities of water 26 * a : the heights of the bottoms 27 */ 28 sampler2D _MainTex; 29 float4 _MainTex_TexelSize; 30 31 float _Alpha; 32 float _Evaporation; 33 34 sampler2D _PaperTex; 35 36 float2 _Prev; 37 float3 _Brush; // x,y : position, z : size 38 39 struct appdata { 40 float4 vertex : POSITION; 41 float2 uv : TEXCOORD0; 42 }; 43 44 struct v2f { 45 float4 vertex : POSITION; 46 float2 uv : TEXCOORD0; 47 }; 48 49 v2f vert (appdata IN) { 50 v2f OUT; 51 OUT.vertex = UnityObjectToClipPos(IN.vertex); 52 OUT.uv = IN.uv; 53 return OUT; 54 } 55 56 void sample (float2 uv, out float4 o, out float4 l, out float4 t, out float4 r, out float4 b) { 57 float2 texel = _MainTex_TexelSize.xy; 58 o = tex2D(_MainTex, uv); 59 l = tex2D(_MainTex, uv + float2(-texel.x, 0)); 60 t = tex2D(_MainTex, uv + float2( 0, -texel.y)); 61 r = tex2D(_MainTex, uv + float2( texel.x, 0)); 62 b = tex2D(_MainTex, uv + float2( 0, texel.y)); 63 } 64 65 float waterDelta (float4 k, float4 o) { 66 float ld = (k.w + k.x) - (o.w + o.x); // level difference 67 float transfer = (k.w + k.x) - max(o.w, k.w + k.z); // transferable water particles 68 return max( 69 0.0, 70 0.25 * _Alpha * min(ld, transfer) 71 ); 72 } 73 74 float waterFlow (float2 uv) { 75 float4 o, l, t, r, b; 76 sample(uv, o, l, t, r, b); 77 78 float nw = o.r; 79 nw += (waterDelta(l, o) - waterDelta(o, l)); 80 nw += (waterDelta(t, o) - waterDelta(o, t)); 81 nw += (waterDelta(r, o) - waterDelta(o, r)); 82 nw += (waterDelta(b, o) - waterDelta(o, b)); 83 return max(nw, 0); 84 } 85 86 float evaporation (float wo) { 87 return max(wo - _Evaporation, 0.0); 88 } 89 90 float brush (float2 uv) { 91 const int count = 10; 92 93 float2 dir = _Brush.xy - _Prev.xy; 94 float l = length(dir); 95 if(l <= 0) { 96 float d = length(uv - _Brush.xy); 97 return smoothstep(0.0, _Brush.z, _Brush.z - d); 98 } 99 100 float ld = l / count; 101 float2 norm = normalize(dir); 102 float md = 100; 103 for(int i = 0; i < count; i++) { 104 float2 p = _Prev.xy + norm * ld * i; 105 float d = length(uv - p); 106 if(d < md) { 107 md = d; 108 } 109 } 110 return smoothstep(0.0, _Brush.z, _Brush.z - md); 111 112 // float d = length(uv - _Brush.xy); 113 // return smoothstep(0.0, _Brush.z, _Brush.z - d); 114 } 115 116 ENDCG 117 118 SubShader { 119 Cull Off ZWrite Off ZTest Always 120 121 Pass { 122 CGPROGRAM 123 #pragma vertex vert 124 #pragma fragment init 125 126 float4 init (v2f IN) : SV_Target { 127 float4 paper = tex2D(_PaperTex, IN.uv); 128 return float4( 129 0, 130 0, 131 paper.r, 132 paper.r 133 ); 134 } 135 136 ENDCG 137 } 138 139 Pass { 140 CGPROGRAM 141 #pragma vertex vert 142 #pragma fragment waterUpdate 143 144 float4 waterUpdate (v2f IN) : SV_Target { 145 float4 col = tex2D(_MainTex, IN.uv); 146 col.x = evaporation(waterFlow(IN.uv)); 147 148 float dw = brush(IN.uv); 149 // if(dw > 0) { 150 col.x = min(col.x + brush(IN.uv), 1.0); 151 // } 152 153 return col; 154 } 155 156 ENDCG 157 } 158 159 Pass { 160 CGPROGRAM 161 #pragma vertex vert 162 #pragma fragment visualize 163 164 // 前景色・背景色プロパティの値を受け取るユニフォーム変数を宣言する 165 fixed4 _Color; 166 fixed4 _BackgroundColor; 167 168 float4 visualize (v2f IN) : SV_Target { 169 float4 col = tex2D(_MainTex, IN.uv); 170 171 // 墨模様をもとに前景色・背景色を混合する 172 return lerp(_BackgroundColor, _Color, col.x); 173 } 174 175 ENDCG 176 } 177 178 } 179 180}

そしてSuibokugaスクリプト側は下記のようにしました。前景色と背景色の設定項目を追加し、それをマテリアルにセットするようにしています。こんな感じでいかがでしょうか?

lang

1using UnityEngine; 2using System.Collections; 3 4using Utils; 5 6[RequireComponent (typeof (Camera) ) ] 7public class Suibokuga : MonoBehaviour { 8 9 [SerializeField] Shader shader; 10 Material mat; 11 12 [SerializeField] Texture2D paper; 13 [SerializeField, Range(0f, 1f)] float alpha = 1.0f; 14 [SerializeField, Range(0f, 0.005f)] float evaporation = 0.0001f; 15 16 [SerializeField, Range(0, 10)] int iterations = 4; 17 [SerializeField] int size = 1024; 18 19 FboPingPong fpp; 20 21 [SerializeField] float thickness = 0.015f; 22 23 // 前景色・背景色を表すフィールドを追加する 24 [SerializeField] Color foregroundColor = Color.black; 25 [SerializeField] Color backgroundColor = Color.white; 26 27 bool dragging = false; 28 Vector2 previous; 29 30 void Start () { 31 fpp = new FboPingPong(size, size); 32 mat = new Material(shader); 33 34 mat.SetTexture("_PaperTex", paper); 35 36 Init(); 37 } 38 39 void Update () { 40 41 Vector3 mousePos = Input.mousePosition; 42 Vector2 current = new Vector2(mousePos.x / Screen.width, mousePos.y / Screen.height); 43 mat.SetVector("_Prev", previous); 44 45 if(dragging) { 46 mat.SetVector("_Brush", new Vector3(current.x, current.y, thickness)); 47 } else { 48 mat.SetVector("_Brush", new Vector3(0, 0, 0)); 49 } 50 51 if(Input.GetMouseButtonDown(0)) { 52 dragging = true; 53 } else if(Input.GetMouseButtonUp(0)) { 54 dragging = false; 55 } 56 57 previous = current; 58 59 mat.SetFloat("_Alpha", alpha); 60 mat.SetFloat("_Evaporation", evaporation); 61 62 // マテリアルに前景色・背景色をセットする 63 mat.SetColor("_Color", foregroundColor); 64 mat.SetColor("_BackgroundColor", backgroundColor); 65 66 for(int i = 0; i < iterations; i++) { 67 Graphics.Blit(fpp.GetReadTex(), fpp.GetWriteTex(), mat, 1); // update 68 fpp.Swap(); 69 } 70 71 72 if(Input.GetMouseButtonDown(2)) 73 { 74 Init(); 75 } 76 } 77 78 void Init () { 79 Graphics.Blit(fpp.GetReadTex(), fpp.GetWriteTex(), mat, 0); // init 80 fpp.Swap(); 81 } 82 83 void OnRenderImage (RenderTexture src, RenderTexture dst) { 84 Graphics.Blit(fpp.GetReadTex(), dst, mat, 2); 85 } 86}

図

投稿2021/10/23 22:21

Bongo

総合スコア10807

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問