- Home /
Spec only Shader, Again.
I already asked that question and I got a good awnser using GrabPass and it lead to a great looking water shader but, the big problem is that I am using Unity Free and it seems that GrabPass is not working in executables created by Unity Free.
What I am looking for is a shader that uses 2 bumps and a specular, without any diffuse. The problem is when I put the alpha of the diffuse to 0, it removes the specular as well, thats what I don't want. So I was asking myself, is there any way to use the specular output as an alpha or some other trick like this that will not require Unity Pro? I don't really care about the refraction in the water since I know that I will need Unity Pro for that.
And also, if there is no way of getting a spec only map, is there a way to blur the edges between the ground and the water, in Unity Free once again?
As far as blurring the edges goes, you can use the camera's depth/normals texture. $$anonymous$$ake sure your camera is set to generate a depth/normals texture and add a new variable to your shader called sampler2D _CameraDepthNormalsTexture;
. Also make sure that your shader is has the "Queue"="Transparent"
tag so it gets drawn after opaque objects. Inside the surface function, get the depth at the pixel you are rendering with this code (which, since the object is not drawn yet, is the depth of the object right behind the water mesh):
half4 d = tex2D (_CameraDepthNormalsTexture, IN.screenPos.xy/IN.screenPos.w);
float depth=DecodeFloatRG(d.zw);
Then get the depth of the water mesh
float od=(IN.screenPos.w*_ProjectionParams.w);
Both depth values are in the 0-1 range, so you can just set the alpha to
pow(depth-od,12/*or some other value you like*/);
As far as i know, Unity Free does allow you to use the depth/normals texture. PS: Effects based on the depth/normals texture won't be visible in the scene view; only in play mode.
Nvm that, right now it seems that the value that I change in the alpha just affects the whole shader. Putting it at 1 to 12 makes it invisible, while puting it at like 0.1, 0.5, makes it more visible but everywhere..
Answer by tanoshimi · Nov 25, 2013 at 06:00 PM
Unfortunately, simply setting c.a = spec (or similar) in the lighting model of a surface shader won't work (in fact, making any change to alpha in the lighting function has no effect, as noted here and here) because the surface shader output always seems to override whatever alpha was set in the lighting function with an additional c.a = o.Alpha;
placed at the end of the fragment function.
Instead, you can still write a surface shader that handles only the specular component together with the alpha, something like this:
half4 LightingSpecularOnly (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
half3 h = normalize (lightDir + viewDir);
half diff = max (0, dot (s.Normal, lightDir));
float nh = max (0, dot (s.Normal, h));
float spec = pow (nh, s.Specular*128.0);
half4 c;
c.rgb = (_LightColor0.rgb * spec) * (atten * 2);
c.a = spec;
return c;
}
But then also add #pragma debug
to generate the underlying vertex/fragment shaders from your code. Then simply copy and paste the generated code and remove the offending final c.a = o.Alpha;
and you should be good to go. Here's a quick test:
EDIT as suggested by @Professor Snake below, you can override the c.a = o.Alpha; by using a finalcolor function. Like this:
Shader "Custom/SpecOnly" {
Properties {
}
SubShader {
Tags { "RenderType"="Transparent" "Queue" = "Transparent"}
LOD 200
CGPROGRAM
#pragma surface surf SpecularOnly finalcolor:alphaFix alpha
struct Input {
half Specular;
};
half4 LightingSpecularOnly (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
half3 h = normalize (lightDir + viewDir);
half diff = max (0, dot (s.Normal, lightDir));
float nh = max (0, dot (s.Normal, h));
float spec = pow (nh, s.Specular*128.0);
half4 c;
c.rgb = (_LightColor0.rgb * spec) * (atten * 2);
c.a = spec;
return c;
}
void alphaFix (Input IN, SurfaceOutput o, inout fixed4 color) {
color.a = color.rgb;
}
void surf (Input IN, inout SurfaceOutput o) {
o.Specular = 1;
}
ENDCG
}
}
Quite a neat solution. Would a finalcolor function override the additional c.a = o.Alpha ? Also, is it possible to write to o.Alpha in a lighting function ins$$anonymous$$d?
Good thinking with the finalcolor function! I've amended code.
Ok. The shader works I only see the Spec which is really nice. Is there a way to apply a normal map on it?
Edit : Never$$anonymous$$d, added it on the surf at the end, works like a charm, thanks a lot!
this is really helpful, is it possible to change the color and shininess too somehow?
Your answer
Follow this Question
Related Questions
About shader! 0 Answers
Shader for overlaying textures 1 Answer
Transparent & reflective shader 1 Answer
Transparency shader that also writes to Camera Depth Texture 0 Answers