Okay, I have read through the custom mesh tutorial, and tried to make my own cube. Now what I am looking to do is to try to create another cube which is one unit further on the X axis. I am wanting to use the four vertices on one cube as the same vertices on the next, if that makes any sense. The thing is I want to do this programatically, and without having to create new vertices every time as this would waste memory (or so I believe).
My ultimate goal will be to have one giant cube, subdivided into eight more cubes, this is just a step in that direction.
I am far from an expert, and I have come up with a method of doing this but I need some clarification. It’s hard for me to explain just in words, so here is some code
[java] Vector3f [] vertices = new Vector3f[7];
vertices[0] = new Vector3f(0,0,0);
vertices[1] = new Vector3f(1,0,0);
vertices[2] = new Vector3f(0,1,0);
vertices[3] = new Vector3f(1,1,0);
vertices[4] = new Vector3f(0,0,1);
vertices[5] = new Vector3f(1,0,1);
vertices[6] = new Vector3f(0,1,1);
vertices[7] = new Vector3f(1,1,1);[/java]
Then I define the indexes, but I created three methods, one of which is:
[java] Vector3f[] shiftVerticesX(Vector3f[] vertices){
for(int i=0;i<=7;i++){
vertices = new Vector3f(vertices.getX() + 1,vertices.getY(),vertices.getZ());
}
return vertices;
}[/java]
the other two also do the same for Y and Z. If I then re-defined the same indexes after calling this method, would I waste memory or have a dodgy result? Thanks, I hope you understand as I have been told I am not clear in my communication in the past.
Erm, well there are several stylistic problems before we even touch the main implementation
Use:
[java] Vector3f [] vertices = new Vector3f[] {
new Vector3f(0,0,0),
new Vector3f(1,0,0),
…etc
};[/java]
Then when we look at your code:
[java] Vector3f[] shiftVerticesX(Vector3f[] vertices){
for(int i=0;i<=7;i++){
vertices = new Vector3f(vertices.getX() + 1,vertices.getY(),vertices.getZ());
}
return vertices;
}[/java]
You shouldn’t loop to a fixed number - loop to vertices.length.
You would also be better off using a defined constant GRID_SIZE = 1; or similar rather than all the 1s and -1s you have in both places.
Now onto what it actually does…You are creating a new vertice and then over-writing the original position in the incoming array with it. Is that what you really intended to do? You also need to think about how you are going to link these vertex positions to things like face indexes, colour/uv mapping, etc.
If you are creating a full cube each time you also want to shift by twice the width of the cube or you will end up with two identically placed vertices everywhere they join.
I’d make a static final VERTICES list and then do something like
[java] Vector3f[] buildMetaCube(int xNum, yNum, zNum){
Vector3f[] result = new Vector3f[xNumyNumzNumVERTICES.length];
int resIndex = 0;
for (x=0;x<xNum;x++) {
for (y=0;y<yNum;y++) {
for(z=0;z<zNum;z++) {
for(Vector3f v: VERTICES) {
result[resIndex++] = new Vector3f(v.x+xGRID_SIZE2, v.y+yGRID_SIZE2, v.z+zGRID_SIZE*2);
}
}
}
}
return result;
}
[/java]
I’d also create an int[] TRIANGLES static final array containing the list of triangles to build. That list I would make based from a 0 index (so when applied to the cube in vertices it creates all the triangles for that). You then need to add some logic to the above when creating the vertices to work out what triangles are needed.
I’d have negative fields in the TRIANGLES array that contains the link to the previous cube. When building the faces then ignore triangles where any index ends up negative (as the first cube has nothing to link to).
Hope that helps.
Edit to fix typo of vertex->Vector3f in the for loop.
Ok, thanks @zarch, I just have a couple of questions:
Why is it better to define the vertices array like that instead of my way?
Why do I want to shift twice the width of the cube each time, wont this leave a cube-sized gap between each cube?
I’m not really sure that I fully understand the bit about triangles…
Also, I don’t mind about how to cubes will come out, they just need a basic wireframe material with backface culling turned off. All I am trying to do is be realistic, I am looking at the marching cubes algorithm and I thought this 3d grid would help me visualize what is happening.
Thanks for the quick reply though, it would take me a while to work all of that out…
EDIT
Also what are you doing with that Vector3f in the last for loop?..
The vertice array being defined like that and using .length instead of the number are both for one main reason: Robustness (although you also gain on conciseness with the array declaration).
If you made a mistake in one of the array indices, or you moved an entry, or whatever then you end up with a lot of manual fiddling to correct vertices and work all that out yourself and make sure you’ve allocated the right size array etc. Or you can let the compiler do all that work for you
All you have defined here is 6 points. Those points need to be joined together with triangles to form a visible shape. Get a bit of paper and draw out a square 1cm in a side. Move one cm to the left and draw another cube 1cm in a side. Notice anything about 2 of the dots you just drew? Now repeat but move 2cm instead, see the difference? You were duplicating vertices at identical positions previously.
To be honest if all you are generating is cubes I wouldn’t use the vertices array at all, I’d just generate them all from step size and iteration. For more complex shapes though you do need something like the vertices list so it’s a worthwhile exercise.
And I don’t wish to seem harsh but an implementation of marching cubes seems like a bit of a stretch given your level of math & java knowledge at the moment. You might be better off sticking to something simpler.
@javagame said:
Also what are you doing with that Vector3f in the last for loop?...
I'm creating a list of Vector3f which then form the vertexes of the generated geometry... (There was a mistake in my post that I've now fixed).
Thanks, perhaps one day in my lifetime I will gather enough knowledge to use marching cubes, right now I need to go and find out what a list of Vector3f is… I’ve heard of ArrayLists, but i’m confident that they don’t look like that
@pspeed said:
http://mathbits.com/mathbits/Java/arrays/Initialize.htm
I meant this
for(Vector3f v: VERTICES) {
Thats not an arraylist, that statement (a for-each loop) checks/counts all elements of Vector3f inside an arraylist named VERTICES. The current element indexed in the loop represented by ‘v’.
to make an array list…
[java]
import java.util.ArrayList;
…
ArrayList<Vector3f> vectorArray = new ArrayList<Vector3f>(); //declare the list, the type of objects it will hold, and initialise it
…
vectorArray.add(vectorObject); //adds a new element to the list
…
Vector3f vectorObject = vectorArray.get(index); //retrieves an element from the list at index
…
Vector3f[] newVectorArray = vectorArray.toArray(new Vector3f[vectorArray.size()]); //converts the ArrayList into a regular Vector3f array
…
for(Vector3f v: vectorArray){ //a loop which cycles through all Vector3f elements added to the ArrayList, and stops when it reaches the end
}
[/java]
ArrayLists are virtually a must for situations where you are generating a huge amount of vectors, and have no idea what the exact maximum limit is, since you dont have to define the array size on initialisation.
Once you have filled the list though, its important to convert it to a regular array, so it can be passed to your meshes buffer
[java]
yourMesh.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(newVectorArray));
[/java]
If you want to recycle your arrays, you can. Once you have passed your ArrayList into a regular array, you can empty it and start fresh
[java]
vectorArray.clear();
[/java]
Very much worth getting aquainted with this class. The JavaDocs are easy enough to read and use if you need to know more.
Bottom line is, you use ArrayLists when it is impractical to use a regular array with a fixed array size.
Sorry, I was being a little sloppy in my phrasing as in this case VERTICES would be an array…which in English semantics is a list but it is not a List in Java terms.
[java]
private static final Vector3f [] VERTICES = new Vector3f[] {
new Vector3f(0,0,0),
new Vector3f(1,0,0),
…etc
};
[/java]
The two links pspeed gave should explain most of the rest though
haha, well now you know about ArrayLists too
Yep, java.collections is probably one of the most important Java packages for any developer to know.
If someone doesn’t know what at a minimum ArrayList, LinkedList, HashMap and HashSet are and why and when you would use each then they are missing out on a lot of the power of Java. (Some of the others like CopyOnWriteArrayList, TreeSet and LinkedHashMap also can be very useful but are much more specialised).
Everything makes sense now, thanks to everyone :d
I just wanted to add something to these two points:
@fatesauce said:
Thats not an arraylist, that statement (a for-each loop) checks/counts all elements of Vector3f inside an arraylist named VERTICES. The current element indexed in the loop represented by 'v'.
In fact for-each loops work on any Iterable which is a lot more than just lists. Arrays, Lists, Sets (in fact most collections) can all be iterated over using for-each loops. Even with maps you can iterate over the keys, values, or entries.
@fatesauce said:
Bottom line is, you use ArrayLists when it is impractical to use a regular array with a fixed array size.
There are a number of other advantages to using Collections rather than Arrays as well. (Don't get fixated on ArrayList, it's probably the most useful but it's not always the best choice). These include things like concurrent modification detection, access to the Collections utilities (sort etc), access to Singleton and Empty version (Collections.singletonList(), Collections.emptyList()), the list goes on.
For example:
[java]
void doStuffToStuff(Collection<Stuff> stuffs) {
for(Stuff s: stuffs)
s.doStuff()
}
[/java]
Now you can call it with:
[java]
List<Stuff> stuffAList = new ArrayList...
List<Stuff> stuffsLList = new LinkedList...
Set<Stuff> stuffsSet = new HashSet...
Map<Integer, Stuff> stuffsMap = new HashMap...
doStuffToStuffs(Collections.emptyList());
doStuffToStuffs(Collections.singletonList(myStuff));
doStufftoStuffs(stuffAList);
doStufftoStuffs(stuffLList);
doStufftoStuffs(stuffsSet);
doStufftoStuffs(stuffsMap.values());
[/java]
See how flexible and powerful this can become?
Another example might be getters.
[java]
List<Stuff> getStuffList() {
if (stuffList == null || stuffList.isEmpty())
return Collections.emptyList();
else
return Collections.unmodifiableList(stuffList);
}
[/java]
(Although depending on context using google's immutableList or a new ArrayList() might be a better option for getStuffList)
[java]
List<Stuff> getStuffList() {
if (stuffList == null || stuffList.isEmpty())
return Collections.emptyList();
else
return new ArrayList(stuffList);
}
[/java]
Now code using getStuffList doesn't have to worry about checking for null, you can just do things like
[java]
for (Stuff s: getStuffList())
s.doStuff();
[/java]
And you know if stuffList is null you will still work fine.
:)
With the for-each loop, before you were using V: as the operator, but in these examples you are using s:… Do these letters make a difference?
@javagame said:
With the for-each loop, before you were using V: as the operator, but in these examples you are using s:... Do these letters make a difference?
Yes.
@pspeed said:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
Read ;)
A little mnemonic for you about those.
[java]
for (Vector3f v : getVectors() {
System.out.println("Vector’s X axis value = " + v.x);
// do something else
}
[/java]
It goes like this:
For Each Vector3f named v in getVectors() (provided the method returns a “list” of Vector3f of course).
That kind of loop iterates through a list and each element is named v. That way you can easily reference each member of the list as v and do whatever you need to do.
Hopefully that helps.
Ah, so if you wanted to use whatever is currently in the loop you could just call it v?
Here’s an example.
[java]
ArrayList<Vector3f> testArray = new ArrayList<Vector3f>(10);
private void init() {
for (int i = 0 ; i < 10 ; i++) {
testArray.add(new Vector3f());
}
}
private ArrayList<Vector3f> getVectorArray() {
return testArray;
}
private void doSomething() {
for (Vector3f v : getVectorArray()) {
v.x = 1.5f;
}
}
[/java]