Search Unity

Expanding/Collapsing Grid?

Discussion in 'Scripting' started by Marble, Jun 14, 2007.

  1. Marble

    Marble

    Joined:
    Aug 29, 2005
    Posts:
    1,268
    I want to have an expanding/collapsing grid in my game like the one drawn in the editor window. As you zoom in, it proliferates. Problem is I can't think of a way to do it efficiently.

    I suppose I could create a bunch of line renderers to do it (one for each line of the grid, with a monobehaviour to keep track and control their visibility). But that seems excessive.

    Do you think a scaling grid like this is within the realm of possibility?
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Hmmm...draw lines on a texture with SetPixel?

    --Eric
     
  3. bronxbomber92

    bronxbomber92

    Joined:
    Nov 11, 2006
    Posts:
    888
    Well, if you have the Pro version, you could do something like this (this draws one big grid):
    Code (csharp):
    1. void DrawGrid()
    2. {
    3.         GL.Color(Color(0, 255, 0));
    4.  
    5.     // Draw a 1x1 grid along the X and Z axis'
    6.     for(float i = -50; i <= 50; i += 1)
    7.     {
    8.         // Start drawing some lines
    9.         GL.Begin(GL.LINES);
    10.  
    11.             // Do the horizontal lines (along the X)
    12.             GL.Vertex3(-50, 0, i);
    13.             GL.Vertex3(50, 0, i);
    14.  
    15.             // Do the vertical lines (along the Z)
    16.             GL.Vertex3(i, 0, -50);
    17.             GL.Vertex3(i, 0, 50);
    18.  
    19.         // Stop drawing lines
    20.         GL.End();
    21.     }
    22. }
    Note, this is untested, as I don't have Pro. But the regular C++/OpenGL equivalent does work.
     
  4. Marble

    Marble

    Joined:
    Aug 29, 2005
    Posts:
    1,268
    Good to know! Unfortunately, I don't have Pro. Maybe I'll look into SetPixel? Seems like it could be expensive to do every frame.
     
  5. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    You wouldn't draw every pixel in the texture every frame, just the lines, which should be very fast. Although the entire texture would have to be uploaded. Another possibility would be using the mesh scripting interface to make a grid out of thin polygons, although you'd have to make sure they still showed up at low resolutions without AA. But it would definitely be fast and it wouldn't need a large uncompressed texture.

    --Eric
     
  6. Marble

    Marble

    Joined:
    Aug 29, 2005
    Posts:
    1,268
    I'll see what I can do with a mesh. I've had problems in the past with thin lines disappearing and flickering (as you say). Hopefully I have the skill. :oops:

    Merci.
     
  7. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Out of curiosity, I checked out SetPixels, and in fact it does get a little slow for uploading a decent-sized texture every frame (SetPixels itself isn't a problem for drawing some lines). For smaller textures it's not a big deal, but then you'd end up with thick lines. Too bad Debug.DrawLine doesn't work outside the editor, eh?

    --Eric
     
  8. aaronsullivan

    aaronsullivan

    Joined:
    Nov 10, 2005
    Posts:
    986
    You can actually get pretty tricky stuff done with the mesh.

    I have a mesh that uses tiling so that you can have all sorts of nice smooth edged connections and such. It requires a set of 4 vertices for each "square" so there's lots of overlapping vertices, but it's necessary because, afaik, there's no way to set UVs per triangle corner, only per vertex.

    Anyway, you could make your grid up of square polygons that have either a straight line texture or a cross where they come together (by changing the uvs.) If you really wanted to be sure you could see the lines... dynamic sizing of the mesh would do it for you. You could even make the size of the polygons proportional to the display. Plus, you'll get anti-aliased lines that way.

    Even with all that calculating the mesh is darn fast. I do a bunch of perlin noise on mine and it works fine on 1ghz g4s.
     

    Attached Files:

  9. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Yeah, I was going to suggest using a line texture. Although I don't think I would bother with a cross for intersecting lines; I'd just use an alpha texture. It would be a lot simpler just to have 1 quad (2 triangles) for each line. With an alpha texture you'd get a darker spot where the lines intersect (if you're not using pure black), but it looks like that's what happens with the grid in the Unity editor too.

    --Eric
     
  10. aaronsullivan

    aaronsullivan

    Joined:
    Nov 10, 2005
    Posts:
    986
    Good point. It would be far, far, FAR, less geometry that way too. :)

    It also opens up the way for shnazzy looking lines, whatever that may mean to you.

    The big drawback to this method is the difficulty in keeping the size of the lines consistent. I was sort of thinking a 2D grid because that's what my brain is on, but if you want it like the Unity editor, it will be tricky-to-impossible to keep a consistent look with the line thickness. You'd probably have to settle for lines getting thicker as they get closer. :( Probably not what you want.
     
  11. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    I thought the point of this was to not zoom the lines, but create them with the mesh interface? That's what I'd do anyway...they'd stay the same thickness and you'd just move the vertices around. (And "shnazzy looking lines" are a good thing, right? ;) )

    --Eric
     
  12. aaronsullivan

    aaronsullivan

    Joined:
    Nov 10, 2005
    Posts:
    986
    Yes, the lines would be the same thickness, BUT as you get closer to them with perspective (as when you change the rotation for instance), they would look wider. This could be a good effect, but it's not what happens in 3D editors and their grids, they look about 1 pixel at any distance from the camera, and I thought that's the look that Marble was going for.

    If, on the other hand, we are talking about a 2D grid that we are always looking at "straight on", this can be handled pretty easily.

    Shnazzy is good. :D I'm thinking glowing lines, wavy lines, dotted lines... all sorts of fun stuff can be accomplished easily once you start using custom made meshes.

    [EDIT: Lots on my mind, not sure I'm being very coherent here today... sort of spilling my brain out onto the pages. Sorry if anything is unclear or for any brain matter stains.]
     
  13. Marble

    Marble

    Joined:
    Aug 29, 2005
    Posts:
    1,268
    Just to make things simpler, the grid is 2D, viewed by an orthogonal camera. A more finely tessellated grid needs to appear as one zooms in (and the opposite for out). Assuming I read you guys right, using the mesh interface to draw "lines" or quads for my grid seems to be the best way to get this done.

    So, I simply (ha) keep the width of my grid lines proportional to the growth in my camera's orthographic size so that it never seems to change.

    Am I on the right track here?
     
  14. aaronsullivan

    aaronsullivan

    Joined:
    Nov 10, 2005
    Posts:
    986
    Yes. That should work great... also if you are using an ortho camera you won't have to worry about resizing the lines because there will be no perspective and they won't look bigger as they get closer or anything. That makes it particularly easy... once you get used to the mesh interface.
     
  15. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Yep! But don't listen to Aaron ;), if you're changing the camera's orthogonal size, you're right that you'll need to change the size of the lines. Alternately, you could use two cameras and keep one of them stationary for the the grid in the background, in which case you'd move the lines around instead of changing the width. I'm not sure in which case the math would be easier, but either way it shouldn't be too hard. (Famous last words....)

    --Eric
     
  16. Marble

    Marble

    Joined:
    Aug 29, 2005
    Posts:
    1,268
    That's the catch. :wink:
     
  17. aaronsullivan

    aaronsullivan

    Joined:
    Nov 10, 2005
    Posts:
    986
    Um... yeah. Didn't catch the orthogonal size change thing. :)
     
  18. Marble

    Marble

    Joined:
    Aug 29, 2005
    Posts:
    1,268
    Thanks to Eric, I was able to create a couple of scripts that do what I needed. It creates one grid that will fade into a larger grid when the orthographic camera is "zoomed out."

    The system only works with two grids right now; been thinking about letting it support an arbitrary amount but that's for another day.

    On a couple empty Game Objects-

    GridManager.js
    Code (csharp):
    1. var gridExtents = 1000.0;
    2. var gridSpacing = 2.0;
    3. var gridZ = 100.0;
    4. var lineWidth = 0.5;
    5.  
    6. var gridMaterial : Material;
    7.  
    8. private var cameraManager : CameraControl;
    9.  
    10. private var XGrid : Vector3[];
    11. private var YGrid : Vector3[];
    12. private var grid : MeshFilter;
    13.  
    14. function Start() {
    15.     cameraManager = Camera.main.GetComponent(CameraControl);
    16.    
    17.     XGrid = new Vector3[(gridExtents / gridSpacing) * 2];
    18.     YGrid = new Vector3[(gridExtents / gridSpacing) * 2];
    19.    
    20.     var i = gridExtents;
    21.     for( var gridEnd : Vector3 in XGrid ) {
    22.         gridEnd = new Vector3( i * -1.0, gridExtents, gridZ );
    23.         i -= gridSpacing;
    24.     }
    25.    
    26.     i = gridExtents;
    27.     for( var gridEnd : Vector3 in YGrid ) {
    28.         gridEnd = new Vector3( gridExtents * -1.0, i * -1.0, gridZ );
    29.         i -= gridSpacing;
    30.     }
    31.    
    32.     grid = gameObject.AddComponent(MeshFilter);
    33.     grid.mesh = new Mesh();
    34.    
    35.     Redraw();
    36.    
    37.     gameObject.AddComponent(MeshRenderer);
    38.     renderer.material = gridMaterial;
    39.    
    40.     cameraManager.SetGridColor( renderer.material.color );
    41. }
    42.  
    43. function Redraw() {
    44.     grid.mesh.Clear();
    45.    
    46.     var modLineWidth = lineWidth * cameraManager.constanceFactor;
    47.     var vertices = new Vector3[ XGrid.length * 4.0 + YGrid.length * 4.0 ];
    48.     var triangles = new int[ vertices.length * 1.5 ];
    49.     var v = 0;
    50.     var t = 0;
    51.     for( var gridEnd : Vector3 in XGrid ) {
    52.         vertices[v] = gridEnd - Vector3(modLineWidth / 2.0, 0.0, 0.0); v++;
    53.         vertices[v] = gridEnd + Vector3(modLineWidth / 2.0, 0.0, 0.0); v++;
    54.         vertices[v] = gridEnd - Vector3(modLineWidth / 2.0, gridExtents * 2.0, 0.0); v++;
    55.         vertices[v] = gridEnd + Vector3(modLineWidth / 2.0, gridExtents * -2.0, 0.0); v++;
    56.        
    57.         triangles[t] = v - 4; t++; // 1
    58.         triangles[t] = v - 3; t++; // 2
    59.         triangles[t] = v - 2; t++; // 3
    60.        
    61.         triangles[t] = v - 1; t++; // 4
    62.         triangles[t] = v - 2; t++; // 3
    63.         triangles[t] = v - 3; t++; // 2    
    64.     }
    65.     for( var gridEnd : Vector3 in YGrid ) {
    66.         vertices[v] = gridEnd + Vector3(0.0, modLineWidth / 2.0, 0.0); v++;
    67.         vertices[v] = gridEnd - Vector3(0.0, modLineWidth / 2.0, 0.0); v++;
    68.         vertices[v] = gridEnd + Vector3(gridExtents * 2.0, modLineWidth / 2.0, 0.0); v++;
    69.         vertices[v] = gridEnd - Vector3(gridExtents * -2.0, modLineWidth / 2.0, 0.0); v++;
    70.        
    71.         triangles[t] = v - 2; t++;
    72.         triangles[t] = v - 3; t++;
    73.         triangles[t] = v - 4; t++;     
    74.        
    75.         triangles[t] = v - 3; t++;
    76.         triangles[t] = v - 2; t++;
    77.         triangles[t] = v - 1; t++;
    78.     }
    79.     var uvs = new Vector2[vertices.length];
    80.        
    81.     for (var i=0;i<uvs.Length;i++) {
    82.         uvs[i] = Vector2 (vertices[i].x, vertices[i].z);
    83.     }
    84.    
    85.     grid.mesh.vertices = vertices;
    86.     grid.mesh.triangles = triangles;
    87.     grid.mesh.uv = uvs;
    88.     grid.mesh.RecalculateNormals();
    89. }
    90.  
    91. function SetSpacing( spacing : float ) {
    92.     gridSpacing = spacing;
    93. }
    On the main camera-

    CameraControl.js
    Code (csharp):
    1. var zoomSpeed = 10;
    2. var minZoomDistance = -2.0;
    3.  
    4. var constanceFactor : float;
    5. var zoomChange = false;
    6.  
    7. var grid1 : GridManager;
    8. private var gridColor : Color;
    9. var grid2 : GridManager;
    10.  
    11. var switchToGridTwoAt = 1000.0;
    12.  
    13. private var originalSize : float;
    14.  
    15. function Awake() {
    16.     originalSize = camera.orthographicSize;
    17. }
    18.  
    19. function Update () {
    20.     if( zoomChange ) {
    21.         if( camera.orthographicSize < switchToGridTwoAt ) {
    22.             if( !grid1.gameObject.active ) grid1.gameObject.active = true;
    23.             grid1.renderer.material.color = gridColor - (gridColor * ( camera.orthographicSize / (switchToGridTwoAt - originalSize) ) );
    24.             grid2.renderer.material.color = gridColor - grid1.renderer.material.color; 
    25.  
    26.             grid1.Redraw();
    27.             grid2.Redraw();
    28.         }
    29.         else {
    30.             if( grid1.gameObject.active ) grid1.gameObject.active = false;
    31.             grid2.Redraw();
    32.         }
    33.         zoomChange = false;
    34.         constanceFactor = 1.0;
    35.     }
    36.    
    37.     if( Input.GetAxis("Zoom") ) {
    38.         camera.orthographicSize -= Input.GetAxis("Zoom") * Time.deltaTime * zoomSpeed;
    39.         constanceFactor = camera.orthographicSize / originalSize;
    40.         transform.position.z += Input.GetAxis("Zoom") * Time.deltaTime * zoomSpeed;
    41.         zoomChange = true;
    42.     }
    43.     if( Input.GetAxis("Mouse ScrollWheel") ) {
    44.         camera.orthographicSize -= Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * zoomSpeed * 100;
    45.         constanceFactor = camera.orthographicSize / originalSize;
    46.         transform.position.z += Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * zoomSpeed;
    47.         zoomChange = true;
    48.     }
    49.     if( transform.position.z > minZoomDistance ) transform.position.z = minZoomDistance;
    50.     if( camera.orthographicSize < 15.0 ) camera.orthographicSize = 15.0;
    51. }
    52.  
    53. function SetGridColor( color : Color ) {
    54.     gridColor = color;
    55. }
    Thanks to the Unity community!

    EDIT: Added UVs and normals so shaders won't complain. Thanks Eric for pointing that out (below).
     
  19. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Cool; that works well. :) I always get messages about the shader wanting texture coordinates (because of no UVs), but I don't know what you're using for a shader.

    --Eric