Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CG: Specify a variable not to be interpolated between vertex and fragment shader

I'm using GC for writing shaders inside Unity3D.

I'm using vertex colors attributes for passing some parameters to the shader. They won't be used so for defining colors, and should be forwarded from vertex shader to pixel shader without modifyng them.

This is the structure I'm taking as input from Unity3D to the 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
};

This is the structure returned by vertex shader as input to the fragment:

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

If I simply forward the parameter to the fragment shader, of course it will be interpolated:

v2f vert (appdata_full v)
{

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

I'd like to pass v.color parameter not interpolated to the fragment shader. Is this possible?if yes how?


EDIT

like Tim pointed out, this is the expected behavior, because of the shader can't do anything else than interpolating colors if those are passed out from vertex shader to fragment. I'll try to explain better what I'm trying to achieve. I'm using per vertex colors to store other kind of information than colors. Without telling all details on what I'm doing with that, let's say you can consider each color vertex as an id(each vertex of the same triangle, will have the same color. Actually each vertex of the same mesh).

So I used the color trick to mask some parameters because I have no other way to do this. Now this piece of information must be available at the fragment shader in some way. If a pass as an out parameter of the vertex shader, this information encoded into a color will arrive interpolated at the fragment, that can't no longer use it.

I'm looking for a way of propagating this information unchanged till the fragment shader (maybe is possible to use a global variable or something like that?if yes how?).

like image 992
Heisenbug Avatar asked Dec 14 '12 10:12

Heisenbug


People also ask

What type of vertex shader variable has the same value for each vertex?

There are three types of variables in shaders: uniforms, attributes, and varyings: Uniforms are variables that have the same value for all vertices - lighting, fog, and shadow maps are examples of data that would be stored in uniforms. Uniforms can be accessed by both the vertex shader and the fragment shader.

What is vertex shader and fragment shader?

There are several kinds of shaders, but two are commonly used to create graphics on the web: Vertex Shaders and Fragment (Pixel) Shaders. Vertex Shaders transform shape positions into 3D drawing coordinates. Fragment Shaders compute the renderings of a shape's colors and other attributes.

What is a varying variable GLSL?

varying variables contain data shared from a vertex shader to a fragment shader. The variable must be written in the vertex shader and the read-only value in the fragment shader is then interpolated from the vertices which make up the fragment.

What is vertex shader in Unity?

A Vertex Shader lets you create different effects by moving your objects' vertices in the scene, such as: waves, distortion around force fields (such as black holes), melting, flags movement, grass movement if the player steps on it and way more!


1 Answers

I'm not sure this counts for an answer but it's a little much for a comment. As Bjorke points out, the fragment shader will always receive an interpolated value. If/when Unity supports Opengl 4.0 you might have access to Interpolation qualifiers, namely 'flat' that disables interpolation, deriving all values from a provoking vertex.

That said, the problem with trying to assign the same "color" value to all vertices of a triangle is that the vertex shader iterates over the vertices once, not per triangle. There will always be a "boundary" region where some vertex shares multiple edges with other vertices of a different "color" or "id", see my dumb example below. When applied to a box at (0,0,0), the top will be red, the bottom green, and the middle blue.

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

In your addendum note you say "Actually each vertex of the same mesh." If that's the case, why not use a modifiable property, like I have included above. Each mesh just needs a script then to change the 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 );
}
}
like image 56
Jerdak Avatar answered Oct 12 '22 06:10

Jerdak