I’ve been trying to get my shader working but just can’t get it right with Unity 3beta6. The shader worked fine on Unity iPhone 1.7.1 and still works okay on hardware older than 3GS (so 3GS, iPad and I assume iPhone 4 and new ipods don’t render correctly). Attached is an example project that demo’s the problem (of course works fine in editor, even with emulation on).
In short, the shader renders the mesh with lighting but uses alpha channel of per-vertex color data for transparency. This is used to have ‘cheap’ shadow blobs below objects. As soon as lighting is on in the shader, the transparent part is just rendered opaque.
The shader code:
Shader "Revolt/Self-Illumination-Shadow" {
Properties {
_MainTex ("Base (RGB) Self-Illumination (A)", 2D) = "white" {}
}
SubShader {
// has to be rendered after other geometry as it contains transparency in
// the shadow.
Tags { "Queue" = "Geometry+1" }
ZWrite On // write to Z buffer
ColorMask RGBA //
Fog { Mode Off }
// to make sure the shadow is placed over the floor
// (although in test scene have placed the object 0.1f up as well)
Offset -1, -1
// if alpha == 0 use data from framebuffer, if 1 use what we've calculated
Blend SrcAlpha OneMinusSrcAlpha
// if I explicitly set bindchannels, the object is rendered in pure black.
// BindChannels {
// Bind "Vertex", vertex
// Bind "TexCoord", texcoord
// Bind "Color", color
// }
Pass {
// VertexOrNone tag doesn't seem to be supported anymore, although
// it's supposed to be the default lightmode so we just comment it out
// Tags { "LightMode" = "VertexOrNone" }
// we need lighting of course
Lighting On
// this should make the shader to user per-vertex color instead
// of color in material (_Color)
ColorMaterial AmbientAndDiffuse
// color is the lighted per-vertex color
// alpha is as defined in per-vertex color
SetTexture [_MainTex] {
combine texture * primary, primary
}
// optional: use alpha channel for self lighting
// SetTexture [_MainTex] {
// combine texture lerp(texture) previous, primary
// }
}
}
}
Please, can anybody see if there’s something wrong in my shader or is it a bug in Unity and should I report it?!
It’s only a problem if you use Universal instead of armv6. Personally, I only use armv6, so I have no idea what bugs come with OpenGL ES 2.0, but this seems to be one of them. If you’re going to bother with armv7, though, might as well write in GLSL to get even better performance.
Thanks, that’s indeed the simplest solution, never gave it a thought you can force to OpenGL ES1.1 through the player settings. Hope we don’t lose too much performance on missing armv7 optimizations as our game is quite close to the CPU and GPU limits of the iPhone :-/. Maybe I have to dive into GLSL (I still suck at shaders so will be a challenge). I’ll have a look at your video’s, could be useful!
Again, thank you, And I guess I better file a bug as it seems to be a bug alright in the shader generated for OpenGL ES2.0.
Unfortunately, my videos are fixed-function only. I don’t know GLSL, so if you ever find any good resources for learning it with Unity, please let me know. I haven’t been able to find anything that matched the ShaderLab documentation, in any capacity, as learning material.
I think your video’s are quite useful, although luckily I know most of it I think. For fun I tinkered with CG (GLSL was described as buggy in Unity manual and indeed didn’t see much documentation). But while building something I suddenly realised that vertex lighting is not really possible with vertex programs (or is it?). Although the vertex/fragment programs add more flexibility I don’t think they will be faster for my simple shader. So hopefully Unity manages to fix the bug(s) so I can use OpenGL ES2.0 and arm7 as I assume it will speed up things a bit besides having option to use vertex and fragment programs.
For fun I include my CG shader attempt (first attempt for me to write CG) but as stated I don’t think it’s possible to use vertex lights in it so stopped coding (now it doesn’t handle any lights, and behaves as ambient (1,1,1) and no lights).
Maybe the code is useful to others trying to get a grasp on CG
Shader "Revolt/Self-Illumination-Shadow" {
Properties {
_MainTex ("Base (RGB) Self-Illumination (A)", 2D) = "white" {}
}
SubShader {
Tags { "Queue" = "Geometry+1" }
ZWrite On // write to Z buffer
ColorMask RGBA //
Fog { Mode Off }
// to make sure the shadow is placed over the floor
// (although in test scene have placed the object 0.1f up as well)
Offset -1, -1
// if alpha == 0 use data from framebuffer, if 1 use what we've calculated
Blend SrcAlpha OneMinusSrcAlpha
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// my old mac pro can't simulate OpenGL ES 2.0 so to see the
// shader I have to comment the next pragma
// #pragma only_renderers gles
#include "UnityCG.cginc"
struct appdata {
float4 vertex;
float4 texcoord;
float4 color;
};
struct v2f {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
float4 color : COLOR;
};
uniform sampler2D _MainTex;
v2f vert(appdata v) {
v2f o;
// as basic as it can get but we have per-vertex colors to copy in v2f
o.pos = mul(UNITY_MATRIX_MVP, v.vertex); // go to
o.uv = TRANSFORM_UV(0);
o.color = v.color; // copy the per-vertex color
return o;
}
half4 frag(v2f input) : COLOR {
half4 texcol = tex2D(_MainTex, input.uv); // texture
// we don't have real lighting, as apparently can only use pixellights when using vertex programs
// so we default to max brightness, the selflighting can double the brightness
texcol = texcol + texcol.a * texcol; // add selflighting (if a == 1 then color is twice as bright)
// the alpha is determined by the alpha of the per-vertex color
texcol.a = input.color.a;
return texcol;
}
ENDCG
}
}
// compatible with all iPhones/iPods
// but doesn't render correctly somehow with OpenGL ES2.0
SubShader {
// has to be rendered after other geometry as it contains transparency in
// the shadow.
Tags { "Queue" = "Geometry+1" }
ZWrite On // write to Z buffer
ColorMask RGBA //
Fog { Mode Off }
// to make sure the shadow is placed over the floor
// (although in test scene have placed the object 0.1f up as well)
Offset -1, -1
// if alpha == 0 use data from framebuffer, if 1 use what we've calculated
Blend SrcAlpha OneMinusSrcAlpha
BindChannels {
Bind "Vertex", vertex
Bind "TexCoord", texcoord
Bind "Color", color
}
Pass {
// VertexOrNone tag doesn't seem to be supported anymore, although
// it's supposed to be the default lightmode so we just comment it out
// Tags { "LightMode" = "VertexOrNone" }
// we need lighting of course
Lighting On
// this should make the shader to user per-vertex color instead
// of color in material (_Color)
ColorMaterial AmbientAndDiffuse
// color is the lighted per-vertex color
// alpha is as defined in per-vertex color
SetTexture [_MainTex] {
combine texture * primary, primary
}
// se alpha channel for self lighting
SetTexture [_MainTex] {
combine texture lerp(texture) previous, primary
}
}
}
}
Arrg… will the bugs never end?
For most stuff it now works on iPad (and presumably other OpenGL ES 2.0 devices) except for animated meshes, as here it seems that animated objects get their per-vertex colors mixed up in certain light conditions (parts get transparent that shouldn’t be and the transparent shadow isn’t anymore).