I'm writing a shader in CG language for Unity3d.
If you make a shader for transparent object you need to create two similar passes in SubShader
. The first one to render only back faces (with Cull Front
) and the second one to render only front faces (with Cull Back
). But the code for vertex and fragment function is the same for two passes.
Is it possible not to double a code and declare some functions, that would be shared between passes?
I want to have something like in my code example:
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: Found out how to do it using includes.
But is it possible to do inside one file?
You can do it in one file using CGINCLUDE
. If you look at the shader for MobileBlur ("Hidden/FastBlur") by Unity it has shared code at the top and passes below.
Here are just the key parts - note CGINCLUDE
/ENDCG
outside of the 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
}
}
}
Answering my own question. Wierdo!
Hope it will help somebody else.
You can write all that betwee CGPROGRAM
and ENDCG
in separate *.cginc file and include it inside each pass.
Important! But you need to write
#pragma vertex vert
and #pragma fragment frag
inside your main shader file, otherwise it will compile but won't work. I suppose that the reason is that pragma'ss are processed before include's.
Here is my code sample.
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 file shared.cginc:
#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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With