GL.Lines

Trying to get some line drawing going tonight using GL in Unity. No luck. I can get my script to draw an array of lines using LineRenderer, Debug.DrawLine, etc… but GL just won’t do anything. Can someone please post a simple script that just draws a line using GL calls?

My script so far that samples an animation and draws a line between each position at every frame…

var i = 0.0;
var lastLinePoint = new Vector3(0,0,0);

function Start () 
{
	var animLength = (animation["Take 001"].length * 30.0) + 1.0;
	theLine = gameObject.AddComponent ("LineRenderer");
	locator = transform.Find("locator1");
	theLine.SetVertexCount (animLength);
	theLine.SetWidth (0.1, 0.1);
	
	GL.Color(Color(0, 0, 0, 1));
	GL.Begin(GL.LINES); 
	
	while (i < animLength)
	{
		i++;
		gameObject.SampleAnimation(animation["Take 001"].clip, i/30.0);
		theLine.SetPosition (i, locator.position);
		
		GL.Vertex3(lastLinePoint.x, lastLinePoint.y, lastLinePoint.z);
		GL.Vertex3(locator.position.x, locator.position.y, locator.position.z); 
		
		Debug.DrawLine (lastLinePoint, locator.position, Color(1, 1, 1, 1));
        
      lastLinePoint = locator.position;	
	}	
	
	GL.End();
}

Works great with both the LineRenderer and Debug.DrawLine, but GL is a no go :roll:

I hope I’m missing something really simple,
Ethan

There are two things:

  1. GL immediate drawing functions use whatever is the “current material” set up right now. The material controls how the rendering is done (blending, textures, etc.) So unless you explicitly set it to something before using GL draw functions, the material can happen to be anything. Also, if you call any other drawing commands from inside GL drawing code, they can set material to something else, so it’s not good to mix them.

  2. GL drawing commands execute immediately. That means if you call them in Start(), they will be executed just once. If you call them in Update(), they will be executed before camera is rendered (and the camera will most likely clear the screen, making the GL drawing not visible). So the usual place to call GL drawing is most often in OnPostRender from a script that is attached to a camera.

Here’s a small example, attach it to a camera:

static var lineMaterial : Material;

static function CreateLineMaterial()
{
    if( !lineMaterial ) {
        lineMaterial = new Material( "Shader \"Lines/Colored Blended\" {" +
            "SubShader { Pass { " +
            "    Blend SrcAlpha OneMinusSrcAlpha " +
            "    ZWrite Off Cull Off Fog { Mode Off } " +
            "    BindChannels {" +
            "      Bind \"vertex\", vertex Bind \"color\", color }" +
            "} } }" );
        lineMaterial.hideFlags = HideFlags.HideAndDontSave;
        lineMaterial.shader.hideFlags = HideFlags.HideAndDontSave;
    }
}

function OnPostRender()
{
    CreateLineMaterial();
    lineMaterial.SetPass( 0 );
    GL.Begin( GL.LINES );
    GL.Color( Color(1,1,1,0.5) );
    GL.Vertex3( 0, 0, 0 );
    GL.Vertex3( 1, 0, 0 );
    GL.Vertex3( 0, 1, 0 );
    GL.Vertex3( 1, 1, 0 );
    GL.Color( Color(0,0,0,0.5) );
    GL.Vertex3( 0, 0, 0 );
    GL.Vertex3( 0, 1, 0 );
    GL.Vertex3( 1, 0, 0 );
    GL.Vertex3( 1, 1, 0 );
    GL.End();
}

Thanks a bunch Aras, it works great now.

Ok, instead of starting a new thread to ask my dumbass scripting questions I’ll just keep this one going. I have a GL Line drawing from sampling the animation of a Maya file. Awesome, works perfectly! My next step is to draw multiple lines from mutiple animation clips inside one Maya file. So I split my Maya animations into multiple clips and named them “1” to “10” or whatever. I use this to sample the transformation at a given frame of the animation:

gameobject.SampleAnimation (animation["1"].clip, i/30.0);

My question is how do I make the string that defines the animation clip a variable… So “1” can be a variable that counts up to the number of animation clips I have in this Maya file. It has to just be some syntax right? I want to loop through each animation clip and draw a line at the transform positions in each frame. This works great when there is only one animation clip, but I need to cycle through an arbitrary amount.

Thanks for any help and sorry if I haven’t explained my problem properly. And thanks again Aras for your help just getting GL Lines to even draw properly.

Ethan

If your animations are named “1”, “2”, and so on, you can access them in a for loop.

for (a=1;a<100;a++)
gameObject.SampleAnimation (animation[a.ToString()].clip, i/30.0);
}
//alternately, this code will count up until it stops finding animations instead of a set number; this is probably a better way to do it since you don't have to change the code to change the number of animations it runs
var index : int=1;
while (true) {
if (!animation[index.ToString()]) break;
gameObject.SampleAnimation (animation[index.ToString()].clip, i/30.0);
index++;
}

Thanks a bunch Ray for introducing me to ToString ()… that does the trick.

I’ve used this code and it works fine on Mac, but under Windows all lines (and quads too for that matter) are rendered black.

I’ve filed it as a bug under Case 19588, however, today I got the reply:

I’ve looked up BindChannels in the docs, but I have no experience with shaders and don’t really know how to apply it. If anybody could make an updated version of the shader posted by Aras that correctly binds the color channel (or whatever the terminology is) and thus show the right colors on both Mac and Windows, I’d appreciate it a lot!

Rune

static function CreateLineMaterial() 
{ 
    if( !lineMaterial ) { 
        lineMaterial = new Material( "Shader \"Lines/Colored Blended\" {" +
            "SubShader { Pass { " + 
            "    BindChannels { Bind \"Color\",color } " +
            "    Blend SrcAlpha OneMinusSrcAlpha " + 
            "    ZWrite Off Cull Off Fog { Mode Off } " + 
            "} } }" ); 
        lineMaterial.hideFlags = HideFlags.HideAndDontSave; 
        lineMaterial.shader.hideFlags = HideFlags.HideAndDontSave; 
    } 
}

Rune - this worked with the little example above. I confirmed that the original code worked on Mac and made only a black square on Windows. I added ‘BindChannels { Bind “Color”, color }’ and tested in Windows – the results look like on Mac now.

Unity is usually good about getting bindings figured out for us, but shaders that take vertex colors into account sometimes need some help mapping sources to targets.

Thanks Charles, it works nicely on both Mac and Windows now!

Rune

is there a way to get simple white color for the lines?
without using this material?