As I was looking for some new stuff for the Alternativa engine, intending to start a big new project, I came accross this very good blog by David E Jones.
There’s some really cool stuff there, so I thought I’d try them out – well, at least some of them – still in my demo sample. I quickly picked the pixel material that prevents texture smoothing and the addition of fog. But there are other that are worth beeing tried. I’d like to point out again that Alternativa is entirely open source and that’s why these cutomizations are made possible. I’m not going to give the details as David E Jones describes it perfectly. If you’re interested, here are the links to his posts :
Turning off texture smoothing alternativa3d 8
Try out the demo :
The other new thing about this demo is that I added an algorithm that assembles each type of cubes into one global object. In this case I have 2 kind of cubes, therefore only 2 objects.
There are several benefits to this :
- The hidden faces (the ones facing each other) are no longer present, so this relieves the engine
- The resulting objects have there faces sorted, meaning they have 6 surfaces, one with all the below faces, one with the top faces, etc… this would allow to easily put a different texture to all the top faces for example – which is something I forgot to show in the demo !
Of course, in this demo, there aren’t that many cubes, so the benefit isn’t noticeable, but consider a great amount of them – you know, like in a well known cube game for instance – it may count !
This piece of code achieves this. It was inspired by a mesh-combine method I found :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
public static function cubeCombine(meshes:Vector.<Mesh>,map:Array):Mesh { var res:Mesh; var indices:Vector.<uint> = new Vector.<uint>(); var vert:Vector.<Number> = new Vector.<Number>(); var norm:Vector.<Number> = new Vector.<Number>(); var tex:Vector.<Number> = new Vector.<Number>(); var globalindices:Array = new Array(); var globalvert:Array = new Array(); var globalnorm:Array = new Array(); var globaltex:Array = new Array(); var obj:Object = new Object(); var k:int, s:int, e:int; var i:int, vil:uint, vtil:uint, til:uint, vec:Vector3D,vecn:Vector3D,vt:Vector.<Number>,v:Vector.<Number>,vn:Vector.<Number>,tempind:Vector.<uint>; var opp:Boolean; var nbtriangles:Array = new Array(); var faceindices:Array = new Array(); var pos:Vector3D; var opf:Vector.<Vector3D> = new Vector.<Vector3D>; opf.push(new Vector3D(0,0,-1)); opf.push(new Vector3D(0,0,1)); opf.push(new Vector3D(0,-1,0)); opf.push(new Vector3D(0,1,0)); opf.push(new Vector3D(-1,0,0)); opf.push(new Vector3D(1,0,0)); for (k = 0; k < 6; k++) { globalnorm[k] = new Vector.<Number>(); globalvert[k]= new Vector.<Number>(); globaltex[k] = new Vector.<Number>(); globalindices[k] = new Vector.<uint>(); } for each (res in meshes) { v = res.geometry.getAttributeValues(VertexAttributes.POSITION); vn = res.geometry.getAttributeValues(VertexAttributes.NORMAL); vil = v.length; vt = res.geometry.getAttributeValues(VertexAttributes.TEXCOORDS[0]); vtil = vt.length; tempind = res.geometry.indices; til = tempind.length; for (k = 0; k < 6; k++) { opp = false; pos = new Vector3D(res.userData.x + opf[k].x, res.userData.y + opf[k].y, res.userData.z + opf[k].z); //this test needs to be adapted if ((pos.x >= 0) && (pos.x<map.length) && (pos.y >= 0) && (pos.y<map.length) && (pos.z >= 0) && (pos.z<=1)) { if (map[pos.x][pos.y][pos.z]>0) opp = true; } if (!opp) { //no opposite face, so use the geometry s = vil * k / 6; e = s + vil / 6; for (i = s; i < e; i += 3) { vec = new Vector3D(v[i], v[i + 1], v[i + 2]); vecn = new Vector3D(vn[i], vn[i + 1], vn[i + 2]); vecn.incrementBy(vec); vec = res.localToGlobal(vec); vecn = res.localToGlobal(vecn); globalvert[k].push(vec.x, vec.y, vec.z); vecn.decrementBy(vec); vecn.normalize(); globalnorm[k].push(vecn.x, vecn.y, vecn.z); } s = vtil * k / 6; e = s + vtil / 6; for (i = s; i < e; i += 2) { globaltex[k].push(vt[i], vt[i + 1]); } s = til * k / 6; e = s + til / 6; for (i = s; i < e; i++) { globalindices[k].push(tempind[i] - k*4); } } } } var p:int = 0; var q:int = 0; for (k = 0; k < 6; k++) { faceindices[k] = new Vector.<uint>(); for (i = 0; i < globaltex[k].length; i++) { tex.push(globaltex[k][i]); } for (i = 0; i < globalnorm[k].length; i++) { norm.push(globalnorm[k][i]); } for (i = 0; i < globalvert[k].length; i++) { vert.push(globalvert[k][i]); } for (i = 0; i < globalindices[k].length; i++) { faceindices[k].push(globalindices[k][i] + p * 4); q++; if (q >= 6) { q = 0; p++; } } nbtriangles[k] = faceindices[k].length / 3; for (i = 0; i < faceindices[k].length; i++) { indices.push(faceindices[k][i]); } } res = new Mesh(); var geometry:Geometry = new Geometry(vert.length / 3); geometry._indices = indices; var attributes:Array = []; attributes[0] = VertexAttributes.POSITION; attributes[1] = VertexAttributes.POSITION; attributes[2] = VertexAttributes.POSITION; attributes[3] = VertexAttributes.TEXCOORDS[0]; attributes[4] = VertexAttributes.TEXCOORDS[0]; attributes[5] = VertexAttributes.NORMAL; attributes[6] = VertexAttributes.NORMAL; attributes[7] = VertexAttributes.NORMAL; attributes[8] = VertexAttributes.TANGENT4; attributes[9] = VertexAttributes.TANGENT4; attributes[10] = VertexAttributes.TANGENT4; attributes[11] = VertexAttributes.TANGENT4; geometry.addVertexStream(attributes); geometry.setAttributeValues(VertexAttributes.POSITION, vert); geometry.setAttributeValues(VertexAttributes.NORMAL, norm); geometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], tex); geometry.calculateTangents(0); res.geometry = geometry; res.calculateBoundBox(); return res; } |
This is only usable in my demo as it is. It requires a vector of meshes to combine and a map of the cubes as parameters. The map is a 3 dimensional array where 0 is the absence of a cube, other numbers being a cube type, presumably. Checking the map for cubes means it has to be entirely defined. I know it’s restrictive, someday I might give it extra thought to make it as general as possible.
Other restrictions would be that the cubes must be of the same size of course, and must have the geometry of a primitive box created with only 1 subdivision on the 3 axis (widthSegments=1
, lengthSegments=1
, heightSegments=1
). I’m not really sure how to adapt in other cases…
I’m very sure this can be optimized, and I wouldn’t be surprised if somebody did !
In the demo, you can hit the [X] key to toggle from customized controller to regular simple controller, so that you can cancel the collision detection and go check inside the cubes that there are no extra faces !