Merging 1000 cubes ... then using the cubes individually

Software: Away3D 4.x

Babylon, Jr. Member
Posted: 07 September 2012 05:25 PM   Total Posts: 39

Greetings,

My goal in my program is to generate a world made of blocks (similar to minecraft). As of now, terrain is generated out of many blocks and merged into one mesh (saving me on a lot of framerate) but once I’ve merged these objects I don’t know how I can use them again in my code, if even possible.

After merging I’d need to be able to detect mouse-over of a cube, and on click change it’s texture/erase the cube completely. If this is not possible after merging then my question is how can I draw many cubes to the screen without losing the ability to interact with them in this way?

I’ve attached a screen shot of the game at the moment for visualizing the concept.

I’m pretty new and might need some hand holding on this one.

edit: Also in the picture you’ll notice the lighting is very high contrast. What types of lighting can I use to make it more.. realistic or less contrast?
Thanks,
WB

 

   

Avatar
Fabrice Closier, Administrator
Posted: 07 September 2012 06:31 PM   Total Posts: 1265   [ # 1 ]

If you would use different shapes it could be bits more complex. But as its a cube, that’s pretty easy. Here is one way: Just make a Vector.<MyCubeData>
The MyCubeData is a simple class dataObject.

You could calculate howmany vertices one cube has, its indice etc.. before even generate or merge them. But lets take the easy path for the sake of explaination: merge each cube that you make during a loop. using Merge.apply(receiver, cube)  Before each merge call, you push a new dataObject (MyCubeData) and fill it with the vertices count (of the receiver merge), extrapolate from that the indice and subgeometry index. Save the id or type if you want as well.

Now you know exactly which part of the mesh represent a given “cube” and you can access it representation right into the big buffer. Think that if you remove ‘one’, that you will need to update all the data indices in your dataObjects found behind these entries…

Hope that makes sens.

   

Babylon, Jr. Member
Posted: 07 September 2012 07:27 PM   Total Posts: 39   [ # 2 ]

Fabrice,

I think I understand what you’re saying a little bit.

I set things up

//declare the mesh vector, mesh and geometry
var cubeG:CubeGeometry = new CubeGeometry(boxLengthboxLengthboxLength111);
   var 
maxX:int 30;//20;
   
var maxY:int 1;//10;
   
var maxZ:int 30;//20;
   
   
var merge:Merge = new Merge(truefalse);
meshes = new Vector.<Mesh>();
mesh = new Mesh();

//generate cubes

 
for (0maxXx++){
    
for (0maxYy++){
     
for (0maxZz++){ mesh.positi
mesh
.geometry cubeG;
      
mesh.material material;
      
mesh.name "cube" "x" String(x) + "y" String(y) + "z" String(z)

      
meshes.push(mesh)
      
merge.apply(FinalMeshmesh); 

And then I tried to do things with the information

for (var index:String in meshes{
    meshes[index]
.visible false


You said:
“extrapolate from that[vertice count] the indice and subgeometry index”
I don’t undertsand how to get the indice or subgeometry.

Also:
“Now you know exactly which part of the mesh represent a given “cube” and you can access it representation right into the big buffer”
I don’t know how to take the vertice count, indice and subgeometry to change my merged mesh.

 

   

Avatar
Fabrice Closier, Administrator
Posted: 07 September 2012 09:02 PM   Total Posts: 1265   [ # 3 ]

ok, a basic triangle:

a face has 3 points defining its corners in space.
each point has 3 values: x,y,z
these coordinates are stored in vector<Number> that you can get via Subgeometry vertexData method.
so in the vector if we have a 1 face you have [x,y,z,x,y,z,x,y,z]

Now in order to pinpoint a given vertex in this vector, we have another buffer (Vector): the indices. Each entry represent the x value of a vertex into the vertices vector. So for a single face the entries will be [0,1,2]

indice[0] *3 give us 0—> the x of first vertex
indice[1] *3 give us 3—> the x of the second
indice[2] *3 give us of course the last one.

if you would want to trace the “v1.x” (the second vertex x value)
you would need to do this:  vertices[indices[1]]

by reading an indice[index] and multiplying by 3,  you can this way know where a vertex is stored.  You could be able as well to retreive its uv value by muliplying by 2 instead of 3 as uvs are stored per pair.

But in your case, you do not work at vertex level… Good news is, its exactly the same. Let take a cube or whatever mesh you have. Its definition is nothing else than long series of vertices, uvs, indices, normals etc… all perfectly ordered with each other.

Your original question was: I have now made a big long vector of all the cubes I’ve made. Now I want retrieve one of them and change some props on one of them.
k, lets change cube1 position on x.

so again, lets store the data has we build/merge

loop
make a cubeData object
cubedata.startIndex = receivermesh.geometry.subGeometries[0].verdataData.length;
Merge.apply(receivermesh, cube);
cubedata.endIndex = receivermesh.geometry.subGeometries[0].verdataData.length;
we save the cubedata.  cubesData.push(cubedata);

you have now a cubesdata[cubedata,cubedata,cubedata,cubedata etc]

now you want move the representation of the second one in your big merged mesh on x.

secondCube = cubesdata[1];
where does this baby starts to exists in the vertices buffer? at cubesdata[1].startIndex
so now if you do:
var vertices:Vector.<Number> - receivermesh.geometry.subGeometries[0].vertexData;
loop over vertices while its lower than cubedata.endIndex
you can alter each values of the cube…

but wait, how do you tell for sure its the x value that we want to update?
If your mesh has shared vertices (like the cubeGeometry), how do you make sure you are updating what you want?  simply by “extrapolating” the indice by the info that do have.

indice =  cubedata.startIndex/3;
the indice of the first vertice, the x value is indices[cubedata.startIndex/3]
the equivallent of
receivermesh.geometry.subGeometries[0].indices[cubedata.startIndex/3];
so if you loop over the receiver indices buffer from this pointer instead of the vertices. and iterate with a i+=3, you can for sure update the x value the exact cube that you want.

once done, you need to update the subgeometry:
receivermesh.geometry.subGeometries[0].updateVertexData;


It was a long answer… Hope it wil help you to undertand the principle. You could try to build a simple face using MeshHelper build method to see how it works…

k, now time to enjoy a beer…

 

   

Babylon, Jr. Member
Posted: 08 September 2012 12:18 AM   Total Posts: 39   [ # 4 ]

Edit 2::::
I’m really having trouble getting it to just move 1 cube.

private var cubeData:Object {startIndex0endIndex0};

for (
0maxXx++){
    
for (0maxYy++){
     
for (0maxZz++){
      
        mesh
.positi
      
      mesh
.geometry cubeG;
      
mesh.material material;
      
mesh.name "cube" "x" String(x) + "y" String(y) + "z" String(z)
       
      
      
     
      
cubeData.startIndex =  FinalMesh.geometry.subGeometries[0].vertexData.length
      
      merge
.apply(FinalMeshmesh);
      
cubeData.endIndex FinalMesh.geometry.subGeometries[0].vertexData.length
       
      
//cubeDatas.push(cubeData);
      
meshes.push(mesh)
      
      
      
      
      
//print the vertex data distance
                                                //why is it 0?
      
myInt myInt2 myInt
      debugtxt
.appendTextString((myInt )));
      
debugtxt.appendText"length\n");
      
debugtxt.scrollV++;
      
      
     
}
    }
   }

private function applyPosition(mesh:Meshdx:Numberdy:Numberdz:Number):void
  {
   
var geometry:Geometry mesh.geometry;
   var 
geometries:Vector.<SubGeometry> = geometry.subGeometries;
   var 
numSubGeoms:int geometries.length;
   var 
vertices:Vector.<Number>;
   var 
verticesLengthuint;
   var 
juint;
   var 
subGeom:SubGeometry;
   
   for (var 
:uint 0i<numSubGeoms; ++i){
    subGeom 
SubGeometry(geometries[i]);
    
vertices subGeom.vertexData;
    
verticesLength vertices.length;
   
    for (
cubeData.startIndexj<cubeData.endIndexj+=3){
     vertices[j] 
-= dx;
     
vertices[j+1] -= dy;
     
vertices[j+2] -= dz;
    
}
    
var tempMaterial ColorMaterial
    tempMaterial 
= new ColorMaterial(0x0000001);
    
    
tempMaterial.lightPicker _lightPickerMenu;
    
    
tempMaterial.color 0xFFFFFF
    mesh
.subMeshes[mesh.subMeshes.length 1].material tempMaterial
    subGeom
.updateVertexData(vertices);
   
}
   
   
   
   
  } 

IT seems the distance when I print it out between cubedata,start and cubedata.end is just 0, and when I try to change .geometries[0] to [1] it’s out of range so i’m guessing it is indeed on the [0] index of geometries.

So when the function apply position is called and I try to limit it to only changing the vertices from cubeData.start to cubeData.end it still ends up moving my entire mesh.

At the same time I’m trying to figure out ways to change specific meshes textures using the same method as moving just one cube.

I found this and it changes all of the meshes in my FinalMEsh

mesh.subMeshes[mesh.subMeshes.length 1].material tempMaterial 


You know when you create a cube and add MouseEvent3D so you can be like ‘On mouse over change the texture’ and ‘On mouse click change the texture and start a timer’. Then you can add a timer so that if your mouse is down for 3 seconds, the block disappears. This is what I want to accomplish, except to cubes that have been merged.

So,
1.) mouse events
2.) texture changes
3.) position changes / deletion

On cubes like you would when just creating a standard cube, except to ones that are merged together.

I can’t wrap my head around this.

Would it be too time consuming to perhaps create example code that generates two cubes, Cube1 and Cube2. And then you merge Cube2 into Cube1, then when you call moveCube function, it will move Cube2 and change it’s texture. Also a way to have mouse events on the cube still?

 

   

Avatar
80prozent, Sr. Member
Posted: 08 September 2012 09:08 AM   Total Posts: 430   [ # 5 ]

hi

i believe what you are trying to do is not possible without modifing the away3d classes.
you would need to extend the Mouseevent3d and the picking classes, to give you the index of the triangle your mouscursor hits when the mousedown event is fired.

when merging the cubes, you would have to do something like this:

var triangleIndicies:Vector.<int>=new Vector.<int>
var trianglePositions:Vector.<Matrix3D>=new Vector.<Matrix3D>
triangleIndicies[0]=0
triangleIndicies[1]=originalCube1.Geometry.subGeometries[0].indexData.length
triangleIndicies[2]=originalCube2.Geometry.subGeometries[0].indexData.length
trianglePositions[0]=originalCube1.transform
trianglePositions[1]=originalCube2.transform


now when recieving a mousedown event you can check wich of the original cubes has been hittet

for (var i:int=0;i>=triangleIndicies && recievedTriangleIndex

 Signature 

sorry…i hope my actionscript is better than my english…

   

Avatar
Fabrice Closier, Administrator
Posted: 08 September 2012 12:56 PM   Total Posts: 1265   [ # 6 ]

@babylon: yes a custom data object, but its purely illustratif, you could store anyway you like and want. a bytearray, a dictionary…  also if they all have same amount of vertices, you obviously don’t need the endindex…

I recommand, you start without different materials. as during merging the buffers are organized per subgeometries sharing same material. You could of course have a merged mesh per material if you do not have loads of variation…

also you say that you plan to change textures… you know that all “cubes” stored in same subgeometry sharing material would be affected… so I would look at textures atlasses options here. Where you would offsets the uvs instead of changing materials…

@80prozent yes that’s an option, tho would quickly become a memory monster if you have loads of cubes. I ‘d rather consider quadtree, octrees or simple grid to access data, after all, cubes are pretty good candidates for these… but thats another discussion.

   

Babylon, Jr. Member
Posted: 08 September 2012 10:57 PM   Total Posts: 39   [ # 7 ]

So I think I know an easy way to do what I’d like. I’ll have a 3D array that will generate my world and merge it into one mesh.

Also using that 3D Array I will have a character in my world.

And so I’ll generate blocks for every block ‘in range’ of my character on top of the world mesh to handle the mouse click events identical to the mesh (so I’ll have a character mesh, the world mesh, and about 20 other meshes to reuse as ‘blocks i can click on’.

So onclick, ill have it temporarily erase the new ‘in-range’ block until i use it again and the part of the world mesh too.

So even though Fabrice explained to me the process to do it

loop
make a cubeData object
cubedata.startIndex = receivermesh.geometry.subGeometries[0].verdataData.length;
Merge.apply(receivermesh, cube);
cubedata.endIndex = receivermesh.geometry.subGeometries[0].verdataData.length;
we save the cubedata.  cubesData.push(cubedata);

you have now a cubesdata[cubedata,cubedata,cubedata,cubedata etc]

now you want move the representation of the second one in your big merged mesh on x.

secondCube = cubesdata[1];
where does this baby starts to exists in the vertices buffer? at cubesdata[1].startIndex
so now if you do:
var vertices:Vector.<Number> - receivermesh.geometry.subGeometries[0].vertexData;
loop over vertices while its lower than cubedata.endIndex
you can alter each values of the cube…


I can’t figure out how to put it into code. Can you help me build an example snippet of code?

Create data object

private var cubeData:Object {startIndex0endIndex0}

Set values and merge

cubeData.startIndex =  FinalMesh.geometry.subGeometries[0].vertexData.length
      
      merge
.apply(FinalMeshmesh);
      
cubeData.endIndex FinalMesh.geometry.subGeometries[0].vertexData.length 

Save cube data (How would I declare cubesData [is it just a regular array]?

//what is cubesdata (not cubedata)??
 
cubesData.push(cubedata); 

So now we do secondCube = cubesdata[1];
What is secondCube? A new mesh object? So like this?

var secondCube Mesh = new Mesh();
secondCube cubesdata[1];
//So this is all I need to do? this doesn't make sense to me 

So now I do this:
var vertices:Vector.<Number> - receivermesh.geometry.subGeometries[0].vertexData;
loop over vertices while its lower than cubedata.endIndex
you can alter each values of the cube…

var vertices:Vector.<Number> = receivermesh.geometry.subGeometries[0].vertexData;

for 
each (var verts in vertices){
//"You can alter each values of the cube"
//I don't know how .....
// What goes here?

 

I appreciate your time guys, I just can’t figure this out without being spoon fed I guess.

 

I kind of understand the applyPosition function in meshHelper but I couldn’t figiure out a way to just take that and use it to only effect 1 cube in my 1000 cube mesh.

private function applyPosition(mesh:Meshdx:Numberdy:Numberdz:Number):void
  {
   
var geometry:Geometry mesh.geometry;
   var 
geometries:Vector.<SubGeometry> = geometry.subGeometries;
   var 
numSubGeoms:int geometries.length;
   var 
vertices:Vector.<Number>;
   var 
verticesLengthuint;
   var 
juint;
   var 
subGeom:SubGeometry;
   
   for (var 
:uint 0i<numSubGeoms; ++i){
    subGeom 
SubGeometry(geometries[1]);
    
vertices subGeom.vertexData;
    
verticesLength 1;
    
    for (
0j<3j+=3){
     vertices[j] 
+= dx;
     
vertices[j+1] += dy;
     
vertices[j+2] += dz;
    
}
    
    subGeom
.updateVertexData(vertices);
   
}
   
   mesh
.-= dx;
   
mesh.-= dy;
   
mesh.-= dz;
   
   
  
   

Avatar
80prozent, Sr. Member
Posted: 08 September 2012 11:58 PM   Total Posts: 430   [ # 8 ]

hi

this is not acctually tested, but thats how i would do it.

var cube1:Cube=new Cube();
var 
cube2:Cube=new Cube();

var 
finalmesh:Mesh=cube1;
Merge.apply(finalmeshcube2);

var 
cubeDatas:Vector.<Object> =new Vector.<Object>;

cubeDatas[0]={startIndex0endIndexcube1.Geometry.SubGeometries[0].vertexData.length/3};

cubeDatas[1]={startIndexcube1.Geometry.SubGeometries[0].vertexData.length/3endIndexcube2.Geometry.SubGeometries[0].vertexData.length/3};


private var function 
setMeshPartPosition(meshPartID:int):void
{
for (var i:int=cubeDatas[meshPartID].startIndex;i<cubeDatas[meshPartID].endIndex;i++){

var position:Vector3D=new Vector3D();
//calculate the position of the point here
finalmesh.Geometrie.SubGeometries[0].vertexData[i*3]=position.x;
finalmesh.Geometrie.SubGeometries[0].vertexData[(i*3)+1]=position.y;
finalmesh.Geometrie.SubGeometries[0].vertexData[(i*3)+2]=position.z;

}
//update the vertexBuffer of the finalmesh subgeometrie[0]

hope that helps

 Signature 

sorry…i hope my actionscript is better than my english…

   

Avatar
80prozent, Sr. Member
Posted: 09 September 2012 02:32 PM   Total Posts: 430   [ # 9 ]

@fabrice:

i keep trying to understand how a octree would help reducing memory, when listening for mousedown events on a mesh, created by merging several meshes, to get the correct range of indicies/verticles for one of the “original” meshes inside the big merged mesh.

lets say i have one complex mesh (1000 verticles) and a sphere.
i create a clone of the sphere on every verticle of my complex mesh and merge them toghether, and store a vector with all the startindicies.
now on mousedown on the merged mesh, i can decide via the mouseevent triangleIndex which of the sphere meshes was hit.


how would a octree help with that ?

 

 Signature 

sorry…i hope my actionscript is better than my english…

   

Babylon, Jr. Member
Posted: 10 September 2012 05:22 AM   Total Posts: 39   [ # 10 ]

80 and fabrice:
I was able to finally get it to move cubes that were already inside a mesh as I wanted to by peicing together the code from 80 and the logic from fabrices posts. So thanks guys!

Just incase you’re wondering.
Merge and keep track of the size difference

var mergeNum FinalMesh.geometry.subGeometries[1].vertexData.length/3;
      var 
mergeNum2 FinalMesh.geometry.subGeometries[1].vertexData.length/3;
      
      
mergeNum FinalMesh.geometry.subGeometries[1].vertexData.length/3;
      
      
merge.apply(FinalMeshmesh);
      
      
mergeNum2 FinalMesh.geometry.subGeometries[1].vertexData.length/3;
      
      
      
cubeDatas[counter]={startIndexmergeNumendIndexmergeNum2}

And the fucntion that did the dirty work (basically from mesh helper)

private function setMeshPartPosition(mesh:MeshmeshPartID:int):void{
 
 
var geometry:Geometry mesh.geometry;
 var 
geometries:Vector.<SubGeometry> = geometry.subGeometries;
 var 
numSubGeoms:int geometries.length;
 var 
vertices:Vector.<Number>;
 var 
verticesLengthuint;
 var 
juint;
 var 
subGeom:SubGeometry;
 
 
 
subGeom SubGeometry(geometries[1]);
 
vertices subGeom.vertexData;
 
 for (var 
i:int=cubeDatas[meshPartID].startIndex;i<cubeDatas[meshPartID].endIndex;i++){
  
  
var position:Vector3D=new Vector3D();
  
//calculate the position of the point here
  
FinalMesh.geometry.subGeometries[1].vertexData[i*3] 999;
  
  
FinalMesh.geometry.subGeometries[1].vertexData[(i*3)+1] += 1;
  
FinalMesh.geometry.subGeometries[1].vertexData[(i*3)+2] += 1;
  
 
}
 
//update the vertexBuffer of the finalmesh subgeometrie[0]
 
FinalMesh.geometry.subGeometries[1].updateVertexData(vertices);
 
//subGeom.updateVertexData(vertices);

Thanks again

   
   

X

Away3D Forum

Member Login

Username

Password

Remember_me



X