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

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

ただいまの
回答率

90.47%

  • Unity

    5653questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

  • HLSL

    19questions

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

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

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,505

segur

score 58

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

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

Shader "Custom/Test"
{
    Properties
    {
        _MainTex ("Main Texture", 2D) = "white" {}
        _CopyTex ("Copy Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            sampler2D _MainTex;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;

                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);

                //Tex2D(_CopyTex, i.uv) = col;

                return col;
            }
            ENDCG
        }
    }
}

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

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

tex2D(_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
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/06 08:33

    ご回答ありがとうございます。ComputeShader(computeファイル)ではテクスチャの書き換えができるのですね。勉強になります。

    ただ、ComputeShaderの場合、レンダリングパイプラインの外なので、UnityCG.cgincのUnityObjectToClipPos等の便利な関数が利用できない印象があります。(間違っていたらすみません。)

    できれば、レンダリングパイプラインの中にあるFragmentShader(shaderファイル)でテクスチャの書き換えをしたいのですが、可能でしょうか?

    キャンセル

  • 2018/02/06 09:25

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

    キャンセル

  • 2018/02/06 09:34

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

    キャンセル

  • 2018/02/06 11: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];
    }
    ```
    ※シェーダーとして意味のあることはしていません。

    ご回答ありがとうございました。

    キャンセル

  • 2018/02/06 11:30 編集

    今後、この質問を読む方がいるかもしれないので、念のため、補足します。

    フラグメントシェーダーでRWTexture2Dを利用するためには、Shaderファイル内に `#pragma target 5.0` を書く必要がありました。これによって、実行環境の幅が狭まります。

    DirectX 12(Windows)では動作しましたが、DirectX 11(Windows)とMetal(Mac,iOS)では動作しませんでした。

    [PlayerSettings]→[Graphics APIs for Windows]で[Direct3D12]を先頭にすれば、DirectX 12が利用できます。

    キャンセル

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

  • ただいまの回答率 90.47%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Unity

    5653questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

  • HLSL

    19questions

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