Share function between two passes inside CG Shader for unity3d
I am writing a CG shader for Unity3d.
If you are creating a shader for a transparent object, you need to create two similar passes in SubShader
. The first is to display only the front surfaces (c Cull Front
), and the second is to display only the front surfaces (c Cull Back
). But the code for the vertex and fragment function is the same for the two passes.
Is it possible not to double the code and declare some functions that will be shared between passes?
I want to have something like in my example code:
Shader "cool shader" {
Properties {
...
}
SubShader {
CGPROGRAM
// need to declare vertexOutput somewhow here
float4 sharedFragFoo(vertexOutput i) : COLOR // How to make smth like this?
{
....
return float4(...);
}
ENDCG
pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
vertexOutput vert(vertexInput v) {
vertexOutput o;
...
return o;
}
float4 frag(vertexOutput i) : COLOR
{
return sharedFragFoo(i); // call the shared between passes function
}
ENDCG
}
pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
vertexOutput vert(vertexInput v) {
vertexOutput o;
...
return o;
}
float4 frag(vertexOutput i) : COLOR
{
return sharedFragFoo(i); // call the shared between passes function
}
ENDCG
}
}
}
UPD: Find out how to do it using include. But is it possible to make one file inside ?
source to share
Answering my question. Wierdo!
Hope this helps someone else.
You can write everything betwee CGPROGRAM
and ENDCG
in a separate * .cginc file and include it in each pass.
Important! But you need to write
#pragma vertex vert
also #pragma fragment frag
inside the main shader file, otherwise it will compile but won't work. I believe the reason is because the pragma is being processed before inclusion.
Here is my sample code.
Main shader definition file:
Shader "cool shader" {
Properties {
// properties
}
SubShader {
...
pass {
Cull Front
ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "shared.cginc"
ENDCG
}
pass {
Cull Back
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "shared.cginc"
ENDCG
}
}
}
Shared shared.cginc file :
#ifndef SHARED_FOO
#define SHARED_FOO
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
uniform float4 _Color;
// other variables....
struct vertexInput {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct vertexOutput {
float4 pos : SV_POSITION;
float4 tex : TEXCOORD0;
float4 posWorld : TEXCOORD1;
float4 posInObjectCoords : TEXCOORD2;
float3 normalDir : TEXCOORD3;
};
vertexOutput vert(vertexInput v) {
vertexOutput o;
// do staff
return o;
}
float4 frag(vertexOutput i) : COLOR
{
// do staff
return float4(...);
}
#endif // SHARED_FOO
source to share
You can do it in one file using CGINCLUDE
. If you look at the shader for MobileBlur ("Hidden / FastBlur") from Unity, it has generic code at the top and goes below.
Here are just the key parts - note CGINCLUDE
/ ENDCG
outside SubShader / Pass
Shader "YourShader"
{
...
CGINCLUDE
#include "UnityCG.cginc"
struct shared_v2f
{
float4 pos : SV_POSITION;
}
shared_v2f myVert( appdate_img v )
{
shared_v2f o;
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
return o;
}
fixed4 myFrag( shared_v2f i ) : SV_Target
{
return fixed4( 1.0, 0.5, 0.0, 1.0 );
}
ENDCG
SubShader
{
...
Pass
{
CGPROGRAM
#pragma vertex myVert
#pragma fragment myFrag
ENDCG
}
}
}
source to share
If you don't want to have multiple files, you can add generic declarations or generic functions at the beginning of your shader using the keyword CGINCLUDE
:
Shader "Custom/YourShader"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
CGINCLUDE
//This code is available to all passes in your shader below
sampler2D _MainTex;
float4 _MainTex_TexelSize;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
float4 aSamplingFunction(sampler2D tex, float2 uv, float4 size)
{
return SOMETHING;
}
ENDCG
SubShader
{
Cull On
ZWrite Off
ZTest LEqual
Pass// #0
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
float4 frag(v2f i) : SV_Target
{
float4 col = aSamplingFunction(_MainTex, i.uv, _MainTex_TexelSize);
return col;
}
ENDCG
}
Pass// #1
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
float4 frag(v2f i) : SV_Target
{
float4 col = aSamplingFunction(_MainTex, i.uv, _MainTex_TexelSize);
return col;
}
ENDCG
}
}
}
source to share