5

GC内部にシェーダーを書き込むために使用していますUnity3D

いくつかのパラメーターをシェーダーに渡すために頂点カラー属性を使用しています。これらは色の定義には使用されず、変更せずに頂点シェーダーからピクセル シェーダーに転送する必要があります。

これは、Unity3D から頂点シェーダーへの入力として取っている構造です。

struct appdata_full {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
    float4 texcoord1 : TEXCOORD1;
    fixed4 color : COLOR;
#if defined(SHADER_API_XBOX360)
    half4 texcoord2 : TEXCOORD2;
    half4 texcoord3 : TEXCOORD3;
    half4 texcoord4 : TEXCOORD4;
    half4 texcoord5 : TEXCOORD5;
#endif
};

これは、フラグメントへの入力として頂点シェーダーによって返される構造です。

struct v2f {
  float4 pos : SV_POSITION;
  float2  uv : TEXCOORD0;
  fixed4 col: COLOR;           
};

パラメータを単にフラグメント シェーダに転送すると、もちろん補間されます。

v2f vert (appdata_full v)
{

  v2f output;
  //....
  output.col = v.color;
}

v.color補間されていないパラメータをフラグメントシェーダに渡したいです。これは可能ですか?はいの場合、どのように?


編集

ティムが指摘したように、頂点シェーダーからフラグメントに渡された場合、シェーダーは色を補間する以外に何もできないため、これは予想される動作です。私が達成しようとしていることをよりよく説明しようとします。色以外の種類の情報を保存するために、頂点ごとの色を使用しています。私がそれで何をしているのかについてのすべての詳細を言わずに、各色の頂点をidと見なすことができるとしましょう(同じ三角形の各頂点は同じ色になります。実際には同じメッシュの各頂点)。

そのため、他に方法がないため、カラー トリックを使用していくつかのパラメーターをマスクしました。この情報は、何らかの方法でフラグメント シェーダーで利用できる必要があります。頂点シェーダーの出力パラメーターとして渡す場合、色にエンコードされたこの情報はフラグメントに補間されて到着し、フラグメントは使用できなくなります。

この情報を変更せずにフラグメント シェーダーまで伝播する方法を探しています (グローバル変数などを使用することは可能でしょうか?そうであれば、どのようにすればよいでしょうか?)。

4

6 に答える 6

10

これが答えとして重要かどうかはわかりませんが、コメントには少し多すぎます。Bjorke が指摘しているように、フラグメント シェーダーは常に補間された値を受け取ります。Unity が Opengl 4.0 をサポートしている場合は、Interpolation qualifiers、つまり補間を無効にする 'flat' にアクセスして、誘発する頂点からすべての値を導出することができます。

つまり、三角形のすべての頂点に同じ「色」値を割り当てようとする際の問題は、頂点シェーダーが三角形ごとではなく頂点を 1 回反復することです。一部の頂点が複数のエッジを異なる「色」または「ID」の他の頂点と共有する「境界」領域が常に存在します。以下の私のばかげた例を参照してください。(0,0,0) のボックスに適用すると、上部が赤、下部が緑、中央が青になります。

Shader "custom/colorbyheight" {
Properties {
 _Unique_ID ("Unique Identifier", float) = 1.0
}
SubShader {
Pass {
  CGPROGRAM
  #pragma vertex vert
  #pragma fragment frag
  #include "UnityCG.cginc"
  struct v2f {
      float4 pos : SV_POSITION;
      fixed4 color : COLOR;
  };
  uniform float _Unique_ID;
  v2f vert (appdata_base v)
  {
      v2f o;
      o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
      float3 worldpos = mul(_Object2World, v.vertex).xyz;
      if(worldpos[1] >= 0.0)
        o.color.xyz = 0.35;  //unique_id = 0.35
      else
        o.color.xyz = 0.1;   //unique_id = 0.1
      o.color.w = 1.0;
      return o;
  }


  fixed4 frag (v2f i) : COLOR0 { 
    // local unique_id's set by the vertex shader and stored in the color
    if(i.color.x >= 0.349 && i.color.x <=0.351)
        return float4(1.0,0.0,0.0,1.0); //red
    else if(i.color.x >= 0.099 && i.color.x <=0.11)
        return float4(0.0,1.0,0.0,1.0); //green

    // global unique_id set by a Unity script
    if(_Unique_ID == 42.0)
        return float4(1.0,1.0,1.0,1.0); //white

    // Fallback color = blue
    return float4(0.0,0.0,1.0,1.0);
  }
  ENDCG
}
} 
}

補遺のメモには、「実際には同じメッシュの各頂点」と書かれています。その場合は、上で説明したように、変更可能なプロパティを使用しないでください。各メッシュには、unique_id を変更するためのスクリプトが必要です。

public class ModifyShader : MonoBehaviour {
public float unique_id = 1;
// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {
    renderer.material.SetFloat( "_Unique_ID", unique_id );
}
}
于 2012-12-18T22:07:38.667 に答える
5

これが古いスレッドであることは承知していますが、これは Google の上位の検索結果の 1 つであるため、回答する価値はあります。通常の CG シェーダーで変数に nointerpolation オプションを使用できるようになりました。すなわち

nointerpolation fixed3 diff : COLOR0;
于 2018-11-22T12:37:28.400 に答える
3

これはかなり古いスレッドですが、最近同様の問題が発生し、非常に簡単な答えが見つかりました。OSX Mavericks は OpenGL 4.1 をサポートするようになったので、すぐにはまったく問題にはなりませんが、Unity3d が対応するまでにはまだ時間がかかるかもしれません。とにかく、以前の OSX (Mountain Lion など) でも Unity でフラット シェーディングを有効にするきちんとした方法があります。

以下のシェーダーがその役割を果たします (重要な部分は #extension のある行です。そうしないと、キーワード flat を使用するとコンパイル エラーが発生します。"

Shader "GLSL flat shader" {
SubShader {
  Pass {
     GLSLPROGRAM

     #extension GL_EXT_gpu_shader4 : require
     flat varying vec4 color;

     #ifdef VERTEX
     void main()
     {
        color = gl_Color;
        gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
     }
     #endif

     #ifdef FRAGMENT
     void main()
     {
        gl_FragColor = color; // set the output fragment color
     }
     #endif

     ENDGLSL
  }
  }
}

http://poniesandlight.co.uk/notes/flat_shading_on_osx/ http://en.wikibooks.org/wiki/GLSL_Programming/Unity/Debugging_of_Shadersからのものを組み合わせて 取得しました

于 2014-02-14T09:54:52.143 に答える
2

GPU は常に値間を補間します。三角形に一定の値が必要な場合は、その三角形のすべての頂点に同じ値を設定する必要があります。これは非効率な場合もありますが、これが OpenGL (および DirectX) の仕組みです。「額面」の価値という固有の概念はありません。

于 2012-12-18T06:19:04.930 に答える
1

これを行うかもしれません: glShadeModel(GL_FLAT)。これにより、すべてのフラグメント シェーダー入力の補間がオフになり、古い OpenGL (4.0 より前) でも使用できます。

補間したい入力と補間しない入力がある場合は、一度 GL_FLAT を使用して出力と同じ解像度のテクスチャにレンダリングし、GL_SMOOTH を使用して再度レンダリングし、テクスチャをサンプリングして各ピクセルのフラット値を読み取ります (また、通常の方法で補間値を取得します)。

代わりに DirectX9 を使用できる場合は、個々のフラグメント シェーダー入力 (シェーダー モデル 4 以降)でnointerpolation修飾子を使用できます。

于 2012-12-20T19:47:48.443 に答える
1

次の手順は私にとってはうまくいきます。

残念ながら、DX は誘発頂点として頂点 0 を使用しますが、GL はデフォルトで 2 を使用します。

これは GL で変更できますが、glProvokingVertex は公開されていないようです。

フラットシェーディングを行っているため、頂点数が大幅に減少します。

特別な方法で三角形を並べ替え、法線を計算する必要があります (興味のある方はサンプル ソースを投稿できます)。

問題は、三角形が適切な誘発頂点を使用するために三角形のインデックスを回転させる必要があるため、GL と DX で異なるメッシュを持たなければならないことです。

プラグインを介して GL コマンドを実行する方法があるかもしれません。

于 2019-04-22T06:45:18.610 に答える