Pertanyaan CG: Tentukan sebuah variabel yang tidak akan diinterpolasi antara vertex dan fragment shader


saya menggunakan GC untuk menulis shader di dalam Unity3D.

Saya menggunakan atribut warna titik untuk mengirimkan beberapa parameter ke shader. Mereka tidak akan digunakan untuk menentukan warna, dan harus diteruskan dari vertex shader ke pixel shader tanpa memodifikasinya.

Ini adalah struktur yang saya ambil sebagai masukan dari Unity3D ke vertex shader:

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
};

Ini adalah struktur yang dikembalikan oleh vertex shader sebagai masukan ke fragmen:

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

Jika saya hanya meneruskan parameter ke shader fragmen, tentu saja akan diinterpolasi:

v2f vert (appdata_full v)
{

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

Saya ingin lulus v.color parameter tidak diinterpolasi ke shader fragmen. Apakah ini mungkin? Jika ya bagaimana?


EDIT

seperti yang Tim tunjukkan, ini adalah perilaku yang diharapkan, karena shader tidak dapat melakukan apa pun selain interpolasi warna jika mereka dilewatkan keluar dari vertex shader ke fragmen. Saya akan mencoba menjelaskan dengan lebih baik apa yang saya coba capai. Saya menggunakan per titik warna untuk menyimpan informasi jenis lain selain warna. Tanpa menceritakan semua rincian tentang apa yang saya lakukan dengan itu, katakanlah Anda dapat mempertimbangkan setiap simpul warna sebagai id (setiap titik dari segitiga yang sama, akan memiliki warna yang sama. Sebenarnya setiap titik dari jala yang sama).

Jadi saya menggunakan trik warna untuk menutupi beberapa parameter karena saya tidak punya cara lain untuk melakukan ini. Sekarang informasi ini harus tersedia di shader fragmen dalam beberapa cara. Jika sebuah pass sebagai parameter keluar dari vertex shader, informasi ini dikodekan menjadi warna akan tiba diinterpolasi pada fragmen, yang tidak bisa lagi menggunakannya.

Saya mencari cara menyebarkan informasi ini tidak berubah sampai shader fragmen (mungkin adalah mungkin untuk menggunakan variabel global atau sesuatu seperti itu? Jika ya bagaimana?).


5
2017-12-14 10:23


asal


Jawaban:


Saya tidak yakin ini penting untuk jawaban, tetapi sedikit banyak untuk komentar. Seperti yang ditunjukkan Bjorke, fragmen shader akan selalu menerima nilai interpolasi. Jika / ketika Unity mendukung Opengl 4.0 Anda mungkin memiliki akses ke Kualifikasi interpolasi, yaitu 'flat' yang menonaktifkan interpolasi, menurunkan semua nilai dari a memprovokasi verteks.

Yang mengatakan, masalah dengan mencoba untuk menetapkan nilai "warna" yang sama untuk semua simpul dari segitiga adalah bahwa vertex shader iterates atas simpul sekali, bukan per segitiga. Akan selalu ada daerah "batas" di mana beberapa vertex berbagi beberapa sisi dengan simpul lain dari "warna" atau "id" yang berbeda, lihat contoh bodoh saya di bawah ini. Ketika diterapkan ke kotak di (0,0,0), bagian atas akan menjadi merah, bagian bawah hijau, dan biru tengah.

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
}
} 
}

Dalam catatan tambahan Anda, Anda mengatakan, "Sebenarnya setiap titik dari jala yang sama." Jika itu masalahnya, mengapa tidak menggunakan properti yang dapat dimodifikasi, seperti yang saya sertakan di atas. Setiap mesh hanya membutuhkan skrip kemudian mengubah 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 );
}
}

10
2017-12-18 22:07



Ini adalah thread yang cukup tua, tetapi saya baru-baru ini memiliki masalah serupa dan saya menemukan jawaban yang sangat sederhana. OSX Mavericks sekarang mendukung OpenGL 4.1 sehingga tidak akan menjadi masalah sama sekali, tetapi masih perlu waktu beberapa saat sebelum Unity3d mengambilnya. Bagaimanapun, ada cara yang rapi untuk mengaktifkan shading datar di Unity bahkan pada OSX sebelumnya (mis. Mountain Lion)!

Shader di bawah ini akan melakukan pekerjaan (bagian yang penting adalah garis dengan #extension, jika tidak, Anda akan mendapatkan kesalahan kompilasi untuk menggunakan kata kunci datar "

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
  }
  }
}

Itu dengan menggabungkan hal-hal dari: http://poniesandlight.co.uk/notes/flat_shading_on_osx/ http://en.wikibooks.org/wiki/GLSL_Programming/Unity/Debugging_of_Shaders


3
2018-02-14 09:54



GPU akan selalu diinterpolasi antar nilai. Jika Anda menginginkan nilai konstan untuk segitiga, Anda perlu menetapkan nilai yang sama untuk semua simpul dari segitiga itu. Ini kadang-kadang bisa tidak efisien, tetapi bagaimana OpenGL (dan DirectX) bekerja. Tidak ada gagasan yang melekat pada nilai "wajah".


2
2017-12-18 06:19



Anda mungkin melakukan ini: glShadeModel (GL_FLAT). Ini mematikan interpolasi untuk semua input shader fragmen, dan tersedia di OpenGL lama juga (pre 4.0).

Jika Anda memiliki beberapa masukan yang ingin Anda interpolasi dan beberapa yang tidak Anda lakukan, render sekali dengan GL_FLAT ke tekstur resolusi yang sama dengan output Anda, dan kemudian render lagi dengan GL_SMOOTH dan cicipi tekstur untuk membaca nilai datar untuk setiap piksel ( sementara juga mendapatkan nilai interpolasi dengan cara biasa).

Jika Anda bisa menggunakan DirectX9, Anda bisa menggunakan tidak ada interpolasi modifier pada input shader fragmen individu (shader model 4 atau yang lebih baru).


1
2017-12-20 19:47