- Home /
The question is answered, right answer was accepted
What order are a mesh's triangles rendered in?
I'm trying to draw the triangles of a mesh in back-to-front order, where back is the lowest Y position among all triangles, and front is the highest. Every single triangle has some transparent area.
I'm getting inconsistent behaviour - many 'high' triangles are rendered on top, but some - not all, and not consistently - low triangles are rendered on top of the high ones.
Am I correct in my understanding that the only influence on draw order is the order of the triangles in the mesh.triangles variable? If so, I must have some logical issue in my code, but I can't spot it:
function get sortedAUVs() : ArrayList { sortableAUVs.Sort(orderComparer); return sortableAUVs; }
private var sortableAUVs : ArrayList; // unordered list of all AUVs
function SortDrawOrder() {
var auv : AnimatedUV;
var list : ArrayList = sortedAUVs;
var tix : int; // triangle index
var vix : int; // vertex index
var ix : int; // index (into list)
for ( ix = 0; ix < list.Count; ix++ ) {
auv = list[ix] as AnimatedUV;
vix = auv.auvmSlot * 4; // this is the index of the first vertex of this AUV
tix = ix * 6; // we want the zeroth element of the sorted list to be drawn first (= is lowest triangle)
mesht[tix] = vix;
mesht[tix+1]=vix+1;
mesht[tix+2]=vix+2;
mesht[tix+3]=vix+1;
mesht[tix+4]=vix+3;
mesht[tix+5]=vix+2;
}
mf.mesh.triangles = mesh.triangles = mesht;
}
The sorter is this:
class DrawOrderComparer implements IComparer {
static var auv1 : AnimatedUV;
static var auv2 : AnimatedUV;
function Compare( a : Object, b : Object ) : int {
auv1 = a as AnimatedUV;
auv2 = b as AnimatedUV;
if ( auv1.tx.position.y > auv2.tx.position.y ) return 1;
if ( auv1.tx.position.y < auv2.tx.position.y ) return -1;
return 0;
}
}
I've taken to calling Sort every frame, and still no change.
I'm using the Particles/Alpha Blended shader for the mesh. Is that perhaps what's causing the issue?
Well given that the GPU is parallel there's pretty much no guarantee what it will do! I guess it's down to the hardware, the lighting path and the shader. What effect are you after? Sounds like you might need a transparent shader that does some depth buffer writing (which is not usual and still might not fix it). Not sure I get why it matters which goes first - is it that the non-transparent parts further back might need to be overlaid by the transparent parts?
Perhaps a 2 pass shader that renders only fully opaque parts in the first pass and writes to the ZBuffer followed by a second pass for only semi transparent pixels that doesn't...
The specific problem I'm having is that missiles at Y=0 are being rendered on top of the character dialogue at Y=1 (sometimes :|).
This shader renders everything in the right order, but transparent quads in this mesh fully occlude other quads in this mesh (still transparent to other meshes, which is neat, but not quite what I'm going for)
Shader "Transparent/Z-sorted" {
Properties {
_TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
_$$anonymous$$ainTex ("Particle Texture", 2D) = "white" {}
_InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
}
Category {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
Blend SrcAlpha One$$anonymous$$inusSrcAlpha
AlphaTest Greater .01
Color$$anonymous$$ask RGB
Cull Off Lighting Off ZWrite Off
BindChannels {
Bind "Color", color
Bind "Vertex", vertex
Bind "TexCoord", texcoord
}
// ---- Fragment program cards
SubShader {
Pass {
ZWrite On
Color$$anonymous$$ask 0
}
Pass {
ZWrite Off
Color$$anonymous$$ask RGB
CGPROGRA$$anonymous$$
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#pragma multi_compile_particles
#include "UnityCG.cginc"
sampler2D _$$anonymous$$ainTex;
fixed4 _TintColor;
struct appdata_t {
float4 vertex : POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f {
float4 vertex : POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
#ifdef SOFTPARTICLES_ON
float4 projPos : TEXCOORD1;
#endif
};
float4 _$$anonymous$$ainTex_ST;
v2f vert (appdata_t v)
{
v2f o;
o.vertex = mul(UNITY_$$anonymous$$ATRIX_$$anonymous$$VP, v.vertex);
#ifdef SOFTPARTICLES_ON
o.projPos = ComputeScreenPos (o.vertex);
CO$$anonymous$$PUTE_EYEDEPTH(o.projPos.z);
#endif
o.color = v.color;
o.texcoord = TRANSFOR$$anonymous$$_TEX(v.texcoord,_$$anonymous$$ainTex);
return o;
}
sampler2D _CameraDepthTexture;
float _InvFade;
fixed4 frag (v2f i) : COLOR
{
#ifdef SOFTPARTICLES_ON
float sceneZ = LinearEyeDepth (UNITY_SA$$anonymous$$PLE_DEPTH(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos))));
float partZ = i.projPos.z;
float fade = saturate (_InvFade * (sceneZ-partZ));
i.color.a *= fade;
#endif
return 2.0f * i.color * _TintColor * tex2D(_$$anonymous$$ainTex, i.texcoord);
}
ENDCG
}
}
// ---- Dual texture cards
SubShader {
Pass {
ZWrite On
Color$$anonymous$$ask 0
}
Pass {
ZWrite Off
Color$$anonymous$$ask RGB
SetTexture [_$$anonymous$$ainTex] {
constantColor [_TintColor]
combine constant * primary
}
SetTexture [_$$anonymous$$ainTex] {
combine texture * previous DOUBLE
}
}
}
// ---- Single texture cards (does not do color tint)
SubShader {
Pass {
ZWrite On
Color$$anonymous$$ask 0
}
Pass {
ZWrite Off
Color$$anonymous$$ask RGB
SetTexture [_$$anonymous$$ainTex] {
combine texture * primary
}
}
}
}
}
Well you've got a ZWrite pass there - which is going to mean the second pass might not write some of the pixels. To prove a point - just make those two ZWrite On statements Off for a moment and check whether the model then looks right - if it does we can probably figure something out with the second pass.
With both of them as ZWrite Off, it works just like the normal shader (random stuff on top). It does display transparency correctly, though.
If there's some way to "ZWrite only opaque pixels" that would be what I need for the first pass.
I'll be the first to admit I have no idea about shaders. I basically Frankenstein them together and hope for the best x)
I didn't know much until a few weeks ago - been writing this Noobs Guide To Shaders on Unity Gems and learned a lot :)
You can turn off ZWriting for individual pixels by using discard, but it's expensive.
You could try removing that first pass and allow ZWriting on the second.