Search Unity

Question Creating shapes from a selected area.

Discussion in 'Scripting' started by uri576, May 31, 2023.

  1. uri576

    uri576

    Joined:
    Jun 14, 2021
    Posts:
    7
    Hi, I am doing a university work in which I have to make a tool to create blockouts in virtual reality. The problem is that when creating the primitives in the world I don't know how to make it represent the selected area (at the moment with square grid). That is to say, if I select an "L" shaped area, I don't know how to make a cube get to have that shape. I have thought of several ways, change the scale but then when the area rotates I will not be able to use it. And the other would be to change the vertices of the model but I don't know how to do it.
    Some help or advices pls.
    Thanks for your time.
     
  2. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    A cube cannot have an L shape by definition of a cube. You want an L shaped irregular prism at best.
    Anyway can you be more specific with how exactly are you picking an area, and what your end goal is? Because there are dozens of ways to do this, ranging from pretty easy to very difficult, and I don't feel like guessing which one would suit you the best, would count as a good advice.
     
    Bunny83 likes this.
  3. uri576

    uri576

    Joined:
    Jun 14, 2021
    Posts:
    7
    I'm still in an early stage but I wanted to go asking already to see if someone could help me giving advice and help, but my main idea is that when you choose the object creation mode, with a raycast you mark the block you want to use, you save it in a list and then I would like that with that list of cubes, the complete meshes are created. The thing is that I don't know if I'm approaching it right or I should think in another way.
     
  4. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    Ok, let's get this right. First, shapes are exclusively a 2D thing.
    So you're picking up square shapes that are presumably laid down on some 2D grid?
    And then you want a 3D object to be made, so that it inherits the same shape in the front (and back), but extruded into the 3rd dimension? Is that what you're trying to do?
     
    Bunny83 likes this.
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,744
    From your description it sounds like Minecraft would be a great starting point.

    Fortunately there are probably ten million "Make Minecraft in Unity!" tutorials already on Youtube.

    Start there.

    If you don't think Minecraft is the direction you're going, you'll need to do some serious wireframing to design whatever you contemplate.

    You may wish to fire up exemplar programs such as Blender3D that would allow you to do exactly the same thing, and use that as a guide for making your program.

    Tutorials and example code are great, but keep this in mind to maximize your success and minimize your frustration:

    How to do tutorials properly, two (2) simple steps to success:

    Step 1. Follow the tutorial and do every single step of the tutorial 100% precisely the way it is shown. Even the slightest deviation (even a single character!) generally ends in disaster. That's how software engineering works. Every step must be taken, every single letter must be spelled, capitalized, punctuated and spaced (or not spaced) properly, literally NOTHING can be omitted or skipped.

    Fortunately this is the easiest part to get right: Be a robot. Don't make any mistakes.
    BE PERFECT IN EVERYTHING YOU DO HERE!!


    If you get any errors, learn how to read the error code and fix your error. Google is your friend here. Do NOT continue until you fix your error. Your error will probably be somewhere near the parenthesis numbers (line and character position) in the file. It is almost CERTAINLY your typo causing the error, so look again and fix it.

    Step 2. Go back and work through every part of the tutorial again, and this time explain it to your doggie. See how I am doing that in my avatar picture? If you have no dog, explain it to your house plant. If you are unable to explain any part of it, STOP. DO NOT PROCEED. Now go learn how that part works. Read the documentation on the functions involved. Go back to the tutorial and try to figure out WHY they did that. This is the part that takes a LOT of time when you are new. It might take days or weeks to work through a single 5-minute tutorial. Stick with it. You will learn.

    Step 2 is the part everybody seems to miss. Without Step 2 you are simply a code-typing monkey and outside of the specific tutorial you did, you will be completely lost. If you want to learn, you MUST do Step 2.

    Of course, all this presupposes no errors in the tutorial. For certain tutorial makers (like Unity, Brackeys, Imphenzia, Sebastian Lague) this is usually the case. For some other less-well-known content creators, this is less true. Read the comments on the video: did anyone have issues like you did? If there's an error, you will NEVER be the first guy to find it.

    Beyond that, Step 3, 4, 5 and 6 become easy because you already understand!

    Finally, when you have errors, don't post here... just go fix your errors! Here's how:

    Remember: NOBODY here memorizes error codes. That's not a thing. The error code is absolutely the least useful part of the error. It serves no purpose at all. Forget the error code. Put it out of your mind.

    The complete error message contains everything you need to know to fix the error yourself.

    The important parts of the error message are:

    - the description of the error itself (google this; you are NEVER the first one!)
    - the file it occurred in (critical!)
    - the line number and character position (the two numbers in parentheses)
    - also possibly useful is the stack trace (all the lines of text in the lower console window)

    Always start with the FIRST error in the console window, as sometimes that error causes or compounds some or all of the subsequent errors. Often the error will be immediately prior to the indicated line, so make sure to check there as well.

    Look in the documentation. Every API you attempt to use is probably documented somewhere. Are you using it correctly? Are you spelling it correctly?

    All of that information is in the actual error message and you must pay attention to it. Learn how to identify it instantly so you don't have to stop your progress and fiddle around with the forum.
     
  6. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    Both in university as well as in software engineering it is a critical skill to be able to explain abstract concepts. Try to read you own description from the perspective of someone who does not know exactly what your task is and what you did already. It's pretty vague. I still dont know exactly what you desire to accomplish, and based on all the questions, neither do the others.

    Try explaining what the general idea is. Maybe post an image, or a quick drawing to deliver a concept. You cant expect quality answers if people are still guessing the majority of the context. They are bound to get it wrong, at least partially.
     
  7. uri576

    uri576

    Joined:
    Jun 14, 2021
    Posts:
    7
    Yes! I want some extrude function to create 3d models from a 2d shapes. Like the photos below (I don't know if they are sufficiently self-explanatory but it's the main idea):
     

    Attached Files:

    orionsyndrome and Yoreki like this.
  8. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    Ok, well the easiest way to make this would be to cast a ray to the ground.

    Contrary to what you might think (maybe you don't, I'm just assuming), you don't actually need any kind of objects or Unity colliders prior to that. I mean it's not forbidden either, you could do it for various cosmetic purposes like that, but essentially the ray is purely mathematical, hits the ground plane (at some Y altitude) and a coordinate is extracted from that.

    Now, because the grid is regular, you can tell exactly which square was hit from the XZ coordinates, and add it to some list. Effectively, you just store the rounded XZ coordinates as is.

    Finally, you instantiate the cubes (premade and stored as prefabs) directly to the coordinates in this list. Obviously you nudge them in such a way so that they appear at some height, depending on where the pivot is.

    You may now try this on your own or ask for further help, I can explain the code behind this fully, but I wouldn't want to make too long of a post. Maybe you've got better ideas, etc.
     
  9. uri576

    uri576

    Joined:
    Jun 14, 2021
    Posts:
    7
    The problem with this, if I understand correctly, is that if for example I keep using the "L" shape of the previous picture, I would end up having a cube for each grid square, right?
    The final goal I would like is to create a mesh with the selected shape.
     
  10. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    So you don't want the final mesh to have walls in between, is that why you want it like that?
     
  11. uri576

    uri576

    Joined:
    Jun 14, 2021
    Posts:
    7
    Yes!
     
  12. uri576

    uri576

    Joined:
    Jun 14, 2021
    Posts:
    7
    And I don't know if it is difficult or easy.
     
  13. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    Ok, well, in that case, you don't actually instantiate prefabs, but instead start adding cubes as data to some intermediate mesh model. Even better, because cubes can be represented with six quads, you can simply add quads.

    But before you do that, for each incoming quad, you introduce a guard condition -- there must not be an adjacent cube. In the end you'll add only the quads that satisfy this condition. And from this intermediate data you produce your final mesh.

    There are two additional pieces of info:

    First you want to introduce an intermediate model of your cubes, instead of doing just a list. This is because you want to test for adjacencies. A two-dimensional array would serve just fine.

    Second, the "intermediate mesh" as explained above is not really needed, you can use this two-dimensional array and work with that, and build your mesh on the fly, because quads are relatively simple geometry.

    Additionally, you don't even need the ground quad on your cubes, because they're likely already on the ground, so you can't see them anyway.
     
  14. uri576

    uri576

    Joined:
    Jun 14, 2021
    Posts:
    7
    I have never worked with quads but at least now I have something to start looking with. If you know of any videos or pages about this it would be welcome.
    Thanks for everything and if I have any more questions I will continue this thread :D
     
  15. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    What you really need when working with cubes like this, is a couple of functions that can resolve simple information, for example a face index, into other useful things, like the face normal vector, or the actual quad geometry.

    To make this properly, try drawing a cube on a piece of paper, draw its XYZ coordinate system, and label each face with 0, 1, 2, 3, 4, 5 (you can avoid the last one for reasons described above).
     
  16. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    A quad is just two triangles joined with their hypothenuse. It's called a quad because it resembles a "quadrilateral" but it doesn't have to be a quadrilateral, the two triangles are free to do whatever they want, as long as their hypothenuse vertices align perfectly.

    And in fact, in your final mesh, you want these two vertices to be shared (i.e. each triangle reuses the same vertex). Unlike the rest of them! This is very important because you probably want to texture this model as well, but we can get there at a later point.

    Basically, this is how you can introduce a regular quad on the spot, and then you can transform the vertices to produce all kinds of variations
    Code (csharp):
    1. public struct Quad {
    2.  
    3.   public Vector3 normal;
    4.   public float size;
    5.  
    6.   public Quad(Vector3 normal, float size) {
    7.     this.normal = normal;
    8.     this.size = size;
    9.   }
    10.  
    11.   public void Append(Vector3 p, List<Vector3> vertices, List<int> tris) {
    12.     var q = normal == Vector3.down? new Quaternion(1f, 0f, 0f, 0f)
    13.                                   : Quaternion.FromToRotation(Vector3.up, normal);
    14.  
    15.     var i = vertices.Count;
    16.  
    17.     vertices.Add(tr(-1f, -1f));
    18.     vertices.Add(tr(-1f, +1f));
    19.     vertices.Add(tr(+1f, +1f));
    20.     vertices.Add(tr(+1f, -1f));
    21.  
    22.     tris.Add(i);
    23.     tris.Add(i+1);
    24.     tris.Add(i+2);
    25.  
    26.     tris.Add(i+2);
    27.     tris.Add(i+3);
    28.     tris.Add(i);
    29.  
    30.     Vector3 tr(float x, float y) => p + q * (size * new Vector3(x, 0f, y));
    31.   }
    32.  
    33. }
    Haven't tested this, who knows, maybe it even works.

    I'm not sure atm, maybe Kurt got something for you above.
     
    Last edited: May 31, 2023
  17. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    Just added an example to the previous post.

    To use this in some mesh-building function, where you'd normally have ready-made lists for vertices and triangles:
    Code (csharp):
    1. var verts = new List<Vector3>();
    2. var tris = new List<int>();
    3. ...
    4. new Quad(Vector3.right, 2f).Append(new Vector3(1f, .5f, 0f), verts, tris);
    5. ...
    6. var mesh = new Mesh();
    7. mesh.SetVertices(verts);
    8. mesh.SetTriangles(tris, 0);
    9. mesh.RecalculateNormals();
    10. return mesh;
    Obv just a rough example. The quad would be centered at (1, 0.5, 0) and would face to the right (and would be 4 by 4 world units in size).
     
    Last edited: May 31, 2023
  18. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    Here's a version that includes a local rotation around the pivot, for the sake of completeness, because you don't actually need this for the cube.
    Code (csharp):
    1. public struct Quad {
    2.  
    3.   public Vector3 normal;
    4.   public float size;
    5.   public float rotation; // in degrees
    6.  
    7.   public Quad(Vector3 normal, float size, float rotation = 0f) {
    8.     this.normal = normal;
    9.     this.size = size;
    10.     this.rotation = rotation;
    11.   }
    12.  
    13.   public void Append(Vector3 p, List<Vector3> vertices, List<int> tris) {
    14.     var r = Quaternion.AngleAxis(rotation, Vector3.up);
    15.     var q = normal == Vector3.down? new Quaternion(1f, 0f, 0f, 0f)
    16.                                   : Quaternion.FromToRotation(Vector3.up, normal);
    17.  
    18.     var i = vertices.Count;
    19.  
    20.     vertices.Add(tr(-1f, -1f));
    21.     vertices.Add(tr(-1f, +1f));
    22.     vertices.Add(tr(+1f, +1f));
    23.     vertices.Add(tr(+1f, -1f));
    24.  
    25.     tris.Add(i);
    26.     tris.Add(i+1);
    27.     tris.Add(i+2);
    28.  
    29.     tris.Add(i+2);
    30.     tris.Add(i+3);
    31.     tris.Add(i);
    32.  
    33.     Vector3 tr(float x, float y) => p + q * (size * (r * new Vector3(x, 0f, y)));
    34.   }
    35.  
    36. }
    Edit: I think I got the normal rotation wrong; fixed in both examples
    Edit2: Rotation is in degrees, the comment was erroneous
     
    Last edited: Jun 1, 2023
  19. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    This is just to illustrate the above

    upload_2023-6-1_0-47-41.png

    On the left:
    Quad in the local space. Made up of 2 triangles, each made up of 3 vertices. Vertices 0 and 2 are shared among them. Vertices must be ordered in a clockwise order, this is how a front-face is determined. Triangle backfaces are usually not rendered.
    size
    simply scales the distances between the vertices, but because they're set to -1 and +1 coordinates, the pivot is in the center, and the outer edge is double that of
    size
    .

    On the right:
    Quad in the world space. Oriented arbitrarily thanks to the normal axis (red arrow), defined as a directional unit vector. For the axis-aligned cube you can use the predefined constants
    left
    ,
    right
    ,
    up
    ,
    down
    ,
    forward
    , and
    back
    . In the second example you can also rotate the quad around the normal axis at the pivot (blue arrow). The values shown in the parentheses are supposed to be local UV coordinates. This is not covered by the example above, but you can add UV coordinates on your own.
     
  20. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,744
    I have a 2D finger-to-polygon example... look up "finger" in my MakeGeo project.

    MakeGeo is presently hosted at these locations:

    https://bitbucket.org/kurtdekker/makegeo

    https://github.com/kurtdekker/makegeo

    https://gitlab.com/kurtdekker/makegeo

    https://sourceforge.net/p/makegeo

    Extrusion is fairly easy in that context because you already have the perimeter hull defined (because that's what your finger drew), so just clone it a little ways off, then produce triangles all the way around to close it up.