- Home /
Shaders: Using Property for Offset
I'm trying to define a property (allowing me to change the shader by script) and then use that property to define the offset ("Offset #, #") of the shader. I already define a _Color property and use that within the Pass without issues, and I can define the _Offset property without issue, but when I try to use it in the Pass I get the very helpful error
Shader error in 'TerraViz/Annotation': Parse error: syntax error at line 13
Since it's very short, here's a copy of the complete shader. The error happens on the line
Offset [_Offset], [_Offset]
// Unlit shader, color only, with definable offset
Shader "TerraViz/Annotation" {
Properties {
_Color ("Color", Color) = (1,1,1)
_Offset ("Offset", Float) = -1
}
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry+1"}
Pass {
//ZTest Always
Offset [_Offset], [_Offset]
Lighting Off
Color [_Color]
}
}
}
If you're wondering why I need to do this, here's the explanation:
The z-buffer used for rendering is not linear. When objects are rendered they're stuck into 'slots' in the z-buffer, and the slots get smaller and more numerous the closer to the camera you move. I have a world mesh and allow the user to draw on the globe (by creating linerenderers that follow the movement of their mouse). I also have a bunch of 3D data (like clouds, overlaid data, and satellites) so the height of the linerenderers is important. Because the linerenderers are so close to the surface of the earth, I was getting serious z-fighting issues. While an offset of, say, -1 may be fine when the camera is far from the earth, as it moves closer the offset has less effect and you start getting z-fighting. Likewise, if I just make the offset arbitrarily large to start with, that works great when the camera is close, but as it moves away the offset starts having a greater effect and the linerenderers on the far side of the planet start appearing in front of it. The only way I can see to go about this is to have an offset that's dynamically set based on the camera distance.
Texcoord doesn't do what I need, because it moves the texture relative to its normals (as I understand it), and what I need to do is move it in the z-buffer relative to the camera.
Answer by aldonaletto · Nov 01, 2011 at 12:47 PM
What exactly do you want to do with this Offset thing? What I understood from the docs is that the Offset parameter you're trying to use adds a depth offset for Z-test purposes. If you want to offset a texture, or a vertex position, you should do it in a different manner.
I don't know much about this shader stuff, but I once modified the Transparent/Specular shader (with a lot of pain and tears) to be two-sided, offset the y coordinate of all vertex by a Shift parameter, and offset the texture coordinates according to a sinusoidal function based on the Tempo parameter (it was used as a water shader). Take a look at my shader below - maybe one of these parameters is doing something similar to what you want to do:
Shader "Transparent/Specular2sided" {
Properties {
_Color ("Main Color", Color) = (1,1,1,1)
_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 0)
_Shininess ("Shininess", Range (0.01, 1)) = 0.078125
_MainTex ("Base (RGB) TransGloss (A)", 2D) = "white" {}
}
SubShader {
Tags {"Queue"="Transparent-150" "IgnoreProjector"="True" "RenderType"="Transparent"}
LOD 300
Cull Off
CGPROGRAM
#pragma surface surf BlinnPhong alpha vertex:vert
sampler2D _MainTex;
float4 _Color;
float _Shininess;
float _Shift;
float _Delta;
float _Tempo;
struct Input {
float2 uv_MainTex;
};
void vert (inout appdata_full v){
v.vertex.y += _Shift;
v.texcoord.x += _Delta*sin(_Tempo+v.vertex.x);
v.texcoord.y += _Delta*sin(0.6*_Tempo+v.vertex.z);
}
void surf (Input IN, inout SurfaceOutput o) {
half4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = tex.rgb * _Color.rgb;
o.Gloss = tex.a;
o.Alpha = tex.a * _Color.a;
o.Specular = _Shininess;
}
ENDCG
}
Fallback "Transparent/VertexLit"
}
What exactly do you want to do with this Offset thing?
An excellent question, and one I should have addressed. In short, the z-buffer used for rendering is not linear. When objects are rendered they're stuck into 'slots' in the z-buffer, and the slots get smaller and more numerous the closer to the camera you move. I have a world mesh and allow the user to draw on the globe (by creating linerenderers that follow the movement of their mouse. So, while an offset of, say, -1 may be fine when the camera is far from the earth, as it moves closer the offset has less effect and you start getting z-fighting. Likewise, if I just make the offset arbitrarily large to start with, that works great when the camera is close, but as it moves away the offset starts having a greater effect and the linerenderers on the far side of the planet start appearing in front of it. The only way I can see to go about this is to have an offset that's dynamically set based on the camera distance.
Texcoord doesn't do what I need, because it moves the texture relative to its normals (as I understand it), and what I need to do is move it in the z-buffer relative to the camera.
I've added this explanation to the question.
So, the Offset you need is really the Z-depth one, but the shader compiler is complaining about parsing errors. Well, it smells like a compiler bug to me, since the sintax seems ok. Have you tried some variations? Something like:
Offset -1, -1 <- no variables
Offset [_Offset], -1 <- one variable, one constant
Offset -1, [_Offset] <- one constant, one variable
Offset [_Offset] , [_Offset] <- one extra space between variables
Another possibility: use different names for the two parameters (illogical, but bugs are illogical too).
It certainly could be a compiler bug. Offset works fine with no variables (your top example), but gives the same compiler error for the other 3 examples. I've tried changing variable names, defining the variable as a range rather than a float, moving the offset definition outside the pass{}, etc - no dice.
Any other thoughts?
I tried several alternatives, but all of them resulted in the same error. It seems that the compiler can't handle variables in Offset, which doesn't make sense.
I googled around for alternatives, but the only thing I found is the OpenGL function glPolygonOffset, which takes the same parameters factor and units and seems to do the same thing - maybe this can be used in the GL class, if you have Pro.
Unfortunate that this seems to be a bug, but thanks much for trying. I'll look into glPolygonOffset, and hopefully that'll work (I do have Pro).
The only other alternative I can think of would be to create shaders on the fly with the updated offset value at runtime ( http://unity3d.com/support/documentation/ScriptReference/$$anonymous$$aterial.$$anonymous$$aterial.html ). Since those have to compile every time you change them, however, that's not an ideal solution on a per-frame basis.
Answer by danogles · Aug 22, 2013 at 10:31 PM
I was able to work around this by having multiple LOD levels in the shader, and then setting Shader.maximumLOD at runtime. Example:
Shader "DynamicZBias" {
Properties {
_MainTex ("Main Texture (RGB)", 2D) = "white" {}
}
SubShader {
Offset 0, -200
LOD 300
Pass { ... }
}
SubShader {
Offset 0, -50
LOD 200
Pass { ... }
}
SubShader {
Offset 0, -10
LOD 100
Pass { ... }
}
}
That's a very clever solution, alas I'd need far too many levels to try this.
Answer by davvilla · Aug 02, 2012 at 09:04 PM
I was attempting the exact same thing and came accross this question. After some research it seems that this is not allowed by design:
From: ShaderLab syntax: Pass
Offset OffsetFactor , OffsetUnits Set depth offset. Note that this command intentionally only accepts constants (i.e., not shader parameters) as of Unity 3.0.
Your answer
![](https://koobas.hobune.stream/wayback/20220613025603im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Is it possible to get back data for a specific vertex from a shader ? 0 Answers
How can I pass world position to a custom lighting function for a surface shader? 1 Answer
Accessing shader property breaks shader 0 Answers
Creating a fogless version of a built-in shader 1 Answer
Shader error: Shader program of type 'vp' already exists at line .... 1 Answer