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

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

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

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

HLSL

HLSLは、米マイクロソフト社によって開発された Direct3D APIで使われるプロプライエタリなシェーディング言語です。

Q&A

解決済

1回答

7829閲覧

UnityのSubShader内でテクスチャの書き換えはできますか?

segur

総合スコア73

Unity

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

HLSL

HLSLは、米マイクロソフト社によって開発された Direct3D APIで使われるプロプライエタリなシェーディング言語です。

1グッド

1クリップ

投稿2018/02/05 12:47

何か解決したい問題があるわけではなくて、知識としての質問です。

例えば、以下のようなUnityのShaderファイルがあるとします。

HLSL

1Shader "Custom/Test" 2{ 3 Properties 4 { 5 _MainTex ("Main Texture", 2D) = "white" {} 6 _CopyTex ("Copy Texture", 2D) = "white" {} 7 } 8 SubShader 9 { 10 Tags { "RenderType"="Opaque" } 11 12 Pass 13 { 14 CGPROGRAM 15 #pragma vertex vert 16 #pragma fragment frag 17 18 #include "UnityCG.cginc" 19 20 struct appdata 21 { 22 float4 vertex : POSITION; 23 float2 uv : TEXCOORD0; 24 }; 25 26 struct v2f 27 { 28 float4 vertex : SV_POSITION; 29 float2 uv : TEXCOORD0; 30 }; 31 32 sampler2D _MainTex; 33 34 v2f vert (appdata v) 35 { 36 v2f o; 37 o.vertex = UnityObjectToClipPos(v.vertex); 38 o.uv = v.uv; 39 40 return o; 41 } 42 43 fixed4 frag (v2f i) : SV_Target 44 { 45 fixed4 col = tex2D(_MainTex, i.uv); 46 47 //Tex2D(_CopyTex, i.uv) = col; 48 49 return col; 50 } 51 ENDCG 52 } 53 } 54} 55

上記のように、フラグメントシェーダーでtex2Dを利用すれば、uv座標に対応する色情報を取得できます。

ふとした疑問なのですが、例えば、uv座標に対応する色情報を、書き換えるということはできないのでしょうか?
以下のように、値を代入するイメージです。

HLSL

1tex2D(_CopyTex, i.uv) = col;

ちなみに、このコードを試したところ、Unityで以下のようなエラーが表示されました。

Shader error in 'Custom/Test': undeclared identifier '_CopyTex' at line 47 (on d3d11) Compiling Vertex program Platform defines: UNITY_NO_DXT5nm UNITY_ENABLE_REFLECTION_BUFFERS UNITY_NO_CUBEMAP_ARRAY UNITY_USE_DITHER_MASK_FOR_ALPHABLENDED_SHADOWS UNITY_PBS_USE_BRDF1 UNITY_SPECCUBE_BOX_PROJECTION

恥ずかしながら、ShaderやGPUの仕組みがよくわかっていないので、質問いたしました。
「そんなことできないよ」ということであれば、できないとお答えいただけますと幸いです。

できるのだとすれば、フラグメントシェーダーから利用できる巨大なバッファのように扱えるかなと思いまして。

開発環境

  • Unity 2017.3.0f3
  • Windows 10
  • DirectX 11.0
Bongo👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

シェーダープログラムは多数が並列に実行されますが、通常は実行中のシェーダーコードが注目している1ピクセルにしか値を書き込まないので、不整合は起こらないでしょう。
しかし、あるテクスチャの任意の位置に値を書き込めるようにしたいとなると、複数のシェーダープログラムが同時に一つのピクセルへ値を書き込む可能性が出てきますので、調停のために処理が複雑化するはずです。

実行可能な環境の幅が狭まりますが、レンダーテクスチャのenableRandomWriteをオンにした上でSetRandomWriteTargetで書き込みターゲットに指定、シェーダー側では型名が「RWTexture...」で始まる変数で参照を受け取ることで、任意位置への書き込みも可能なようです(私はまだ使用経験がありませんが...)。

参考1: Unity の DX11 向け機能のサンプルを読んでみた - 凹みTips(「Random Write In Pixel Shader」の節)
参考2: Unity - Unity shader内でテクスチャの任意の座標に値を書き込む方法(51830)|teratail

投稿2018/02/05 22:19

Bongo

総合スコア10807

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

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

segur

2018/02/05 23:33

ご回答ありがとうございます。ComputeShader(computeファイル)ではテクスチャの書き換えができるのですね。勉強になります。 ただ、ComputeShaderの場合、レンダリングパイプラインの外なので、UnityCG.cgincのUnityObjectToClipPos等の便利な関数が利用できない印象があります。(間違っていたらすみません。) できれば、レンダリングパイプラインの中にあるFragmentShader(shaderファイル)でテクスチャの書き換えをしたいのですが、可能でしょうか?
Bongo

2018/02/06 00:25

shaderファイルでも可能ではないでしょうか。凹みTipsさんの「Random Write In Pixel Shader」の紹介記事を挙げさせていただきましたが、これはコンピュートシェーダーではなくグラフィックス用のshaderファイルを使っているかと思います。
segur

2018/02/06 00:34

迅速なご回答ありがとうございます。 紹介記事をしっかりと読み込めておりませんでした。大変申し訳ありません。 おっしゃる通り、RWTexture2Dをフラグメントシェーダで利用していますね。 動作確認してみます。
segur

2018/02/06 02:08

- _MainTexから取得した色情報を_CopyTexに格納できる。 - _CopyTexから色情報を取得できる。 上記の機能の動作確認のため、Custom/Testのフラグメントシェーダーを以下のように書き換えたところ、正常に動作しました。 ``` RWTexture2D<fixed4> _CopyTex; fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); int2 loc; loc.x = int(i.uv.x * 255.0); loc.y = int(i.uv.y * 255.0); _CopyTex[loc] = col; return _CopyTex[loc]; } ``` ※シェーダーとして意味のあることはしていません。 ご回答ありがとうございました。
segur

2018/02/06 02:31 編集

今後、この質問を読む方がいるかもしれないので、念のため、補足します。 フラグメントシェーダーでRWTexture2Dを利用するためには、Shaderファイル内に `#pragma target 5.0` を書く必要がありました。これによって、実行環境の幅が狭まります。 DirectX 12(Windows)では動作しましたが、DirectX 11(Windows)とMetal(Mac,iOS)では動作しませんでした。 [PlayerSettings]→[Graphics APIs for Windows]で[Direct3D12]を先頭にすれば、DirectX 12が利用できます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.44%

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

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

質問する

関連した質問