- Home /
How to apply gradient texture in WorldSpace in CG shader
What I want to achieve is multiplying my first Pass (cg) by a second Pass which applies a gradient texture to the object, but which gets projected onto the object in (TexGen WorldSpace), so that it doesn't use the object's UVs...I guess maybe like a Toon Ramp if I'm correct?
I tried doing it in a second Pass, which was cg as well, but the (TexGen "") option for the 2D texture is disabled in custom vertex shaders. So do I need to write the second Pass in ShaderLab Fix Function Pipeline? And does the Ramp texture need to be a normal 2D map or a cubemap?
I hope someone can help me out because I'm a little stuck on this one lol
=================================
EDIT: Posting shader source
I have my shader source code in a custom .cginc file (BraaapCG.cginc), but I would like to add the gradient in the actual shader file, and keep it out of the source code in the .cginc file:
#pragma fragmentoption ARB_precision_hint_fastest
#pragma exclude_renderers xbox360 ps3
#define UNITY_PASS_FORWARDBASE
#include "UnityCG.cginc"
#include "Lighting.cginc"
// ================================= Data structs for vertex and pixel shaders
// Object data coming in
struct appdata
{
float4 vertex : SV_POSITION;
fixed3 normal : NORMAL;
half2 texcoord : TEXCOORD0;
half2 texcoord1 : TEXCOORD1;
};
// Vertex 2 Fragment data
struct v2f
{
float4 pos : SV_POSITION;
fixed4 color : COLOR;
#ifdef DIFFUSEMAP_ON
half2 uvMT : TEXCOORD0;
#endif
#ifdef DETAILMAP_ON
half2 uvDT : TEXCOORD1;
#endif
#ifdef LIGHTMAP_OFF
#ifdef VERTEX_LIT
fixed3 normal : TEXCOORD2;
fixed3 vlight : TEXCOORD3;
#endif
#else
half2 uvLM : TEXCOORD2;
#endif
};
// ================================= Properties used
#ifdef COLOR_ON
fixed4 _Color;
#endif
#ifdef DIFFUSEMAP_ON
float4 _MainTex_ST;
sampler2D _MainTex;
#endif
#ifdef DETAILMAP_ON
float4 _DetailMap_ST;
sampler2D _DetailMap;
float _Blend;
#endif
#ifdef LIGHTMAP_ON
float4 unity_LightmapST;
sampler2D unity_Lightmap;
#endif
// ================================= Custom Functions
#ifdef VERTEX_LIT
// Half-Lambert Lighting (wrap-diffuse)
inline fixed3 HalfLightingLambert ( fixed3 normal, fixed3 lightDir )
{
fixed NdotL = max ( 0, dot ( normalize( normal ), normalize( lightDir ))) * 0.5 + 0.5;
return _LightColor0.rgb * ( NdotL * NdotL * NdotL ) + UNITY_LIGHTMODEL_AMBIENT;
}
#endif
// ================================= VERTEX SHADER
v2f vert ( appdata v )
{
v2f o;
o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
#ifdef DIFFUSEMAP_ON
o.uvMT = TRANSFORM_TEX( v.texcoord, _MainTex );
#endif
#ifdef DETAILMAP_ON
o.uvDT = TRANSFORM_TEX( v.texcoord1, _DetailMap );
#endif
#ifdef VERTEX_LIT
#ifdef LIGHTMAP_OFF
o.normal = v.normal;
fixed3 lightDir = ObjSpaceLightDir(v.vertex);
o.vlight = HalfLightingLambert( o.normal, lightDir );
#endif
#endif
#ifdef LIGHTMAP_ON
o.uvLM.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
#endif
#ifdef COLOR_ON
o.color = _Color;
#endif
return o;
}
// ================================= PIXEL SHADER
fixed4 frag( v2f i ) : COLOR
{
fixed4 diff = i.color;
#ifdef DIFFUSEMAP_ON
diff = tex2D( _MainTex, i.uvMT );
#ifdef COLOR_ON
diff *= i.color;
#endif
#endif
#ifdef DETAILMAP_ON
fixed4 detail = tex2D( _DetailMap, i.uvDT );
#ifndef DIFFUSEMAP_ON
diff = detail;
#ifdef COLOR_ON
diff *= i.color;
#endif
#endif
#endif
#ifdef DIFFUSEMAP_ON
#ifdef DETAILMAP_ON
diff *= detail * _Blend;
#endif
#endif
// Apply lighting
#ifdef VERTEX_LIT
#ifdef LIGHTMAP_OFF
diff.rgb *= i.vlight * 2;
#endif
#endif
// Or apply lightmap if turned on( with no lighting )
#ifdef LIGHTMAP_ON
diff.rgb *= DecodeLightmap( tex2D( unity_Lightmap, i.uvLM ) );
#endif
return diff;
}
Then here's the actual shader:
Shader "SRShaders/ColorOnly/Single_Color_VertexLit" {
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
_Ramp( "Ramp (RGB)", 2D ) = "grey" {TexGen EyeLinear}???
}
// Single Color shader, vertex lit w/lightmap
SubShader {
Pass
{
Name "COLOR VERTEX LIT"
Tags { "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase LIGHTMAP_OFF LIGHTMAP_ON
#define COLOR_ON
#define VERTEX_LIT
#include "../BraaapCG.cginc"
ENDCG
}
Pass
{
// Here I would like to add(multiply) the Ramp texture to the
// previous pass, in WorldSpace (or any space that fits my purpose).
// I want to do it this way so that the UVs of the object don't matter
// for the _Ramp texture, that way it maps it vertically or horizontally
// across the whole object
//CG or Shaderlab code...
}
}
}
I have read that the {TexGen ""} tags don't work in custom vertex shaders, so I'm assuming I'd need to use ShaderLab and SetTexture[_Texture]{...}, but I'm not sure how to make it work.
EDIT END =========================
Thanks in advance!
Stephane
Posted the source code Scroodge$$anonymous$$ :) As you can see all my source code is in a custom .cginc file, and I'd like to add the gradient pass in the actual shader file if possible. Thanks!
Answer by ScroodgeM · Aug 20, 2012 at 10:23 PM
BraaapCG.cginc
// ================================= Data structs for vertex and pixel shaders struct v2f { #ifdef WORLD_RAMP float4 wPos : TEXCOORD1; // world-based position #endif };
// ================================= Properties used #ifdef WORLD_RAMP sampler2D _Ramp; #endif
// ================================= VERTEX SHADER v2f vert ( appdata v ) { #ifdef WORLD_RAMP o.wPos = mul(_Object2World, v.vertex); #endif }
// ================================= PIXEL SHADER fixed4 frag( v2f i ) : COLOR { #ifdef WORLD_RAMP diff += tex2D(_Ramp, frac(i.wPos).xy); #endif }
Blahblahblah.shader
#define WORLD_RAMP
Awesome, this looks like exactly what I was missing! I'll give it a try when I get home. Thanks a lot Scroodge :)
So I implemented your code above and I have one more question if you don't $$anonymous$$d! It's working as expected, although the ramp texture (which is just a black to white gradient atm) is being tiled across the object multiple times. What I want to achieve is have the ramp projected on the object with no tiling, so that the black area of the ramp starts at the bottom of my object, and the white area ends at the top. I tried to normalize the wPos but it's not doing what I need, and I'm not sure why the ramp texture is being tiled multiple times across my object.
Is this supposed to be the correct behavior, or is it possible I'm doing something wrong?
Thanks for your time Scroodge!
little tour to shaders.
vertex block once it executes don't know about other vertices except one it works with. that's why if you want to use some scaling in some space across set of vertices you should scale it externally.
normalizing vertice will just make vector length to 1, independent of what it was before - length 0.1 or 10. notice, that vertex block will normalize not all vertices to 1, but each vertice to 1.
all you need is set a scale
diff += tex2D(_Ramp, frac($$anonymous$$ * i.wPos).xy);
'$$anonymous$$' here is you multiplier to set scale of texture. you should set it to value where texture will be scaled from 0 to 1 once your world scaled from $$anonymous$$imum to maximum. basically $$anonymous$$ should be 1/[whole scene size in gradient direction]
Perfect, and thanks for the little lesson on vertex block, and on normalizing vertices. I have a lot to learn and that was very helpful.
About "$$anonymous$$ should be 1/[whole scene size in gradient direction]", I'm using this:
o.wPos = v.vertex * ( 1.0f / _ScreenParams.y );
Is this what you mean, or am I misunderstanding you? I'm almost there :)
Your answer
Follow this Question
Related Questions
The name 'Joystick' does not denote a valid type ('not found') 2 Answers
Can I blend Lightmap opacity? 1 Answer
Network restrictive rendering 1 Answer
Stencil buffer and transparency 0 Answers