I was working on other things today so the only thing I added to this project was the grid. It’s at a y-elevation of zero. More interestingly, it’s generation is automated, with the relevant code being shown below. Because floating-point numbers can be notoriously touchy after numerous operations I added in the smidge factor to ensure that end lines are always drawn and that the center lines can be found reliably. The center lines can be drawn in a different color if the number of divisions across the total width or length of the grid is even, meaning there will be an odd number of lines.
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 |
function define3DLine(x1,y1,x2,y2,lineColor) { var gridMaterial = new THREE.LineBasicMaterial({ color: lineColor }); var geometry = new THREE.Geometry(); geometry.vertices.push( new THREE.Vector3(x1, 0, y1), new THREE.Vector3(x2, 0, y2) ); var line = new THREE.Line(geometry, gridMaterial); scene.add(line); } function defineReferenceGrid() { var smidge = 0.00000001; var xMin = global3DMinX; var xMax = global3DMaxX; var xInc = (xMax - xMin) / 26; xMin -= xInc; xMax += xInc; var xMiddle = (xMin + xMax) / 2.0; var zMin = global3DMinY; var zMax = global3DMaxY; var zInc = (zMax - zMin) / 3i6; zMin -= zInc; zMax += zInc; var zMiddle = (zMin + zMax) / 2.0; xMax += smidge; zMax += smidge; var gridLineColor; for (var z=zMin; z<=zMax; z+=zInc) { if ((z < zMiddle-smidge) || (z > zMiddle+smidge)) { gridLineColor = "#000088"; } else { //center line gridLineColor = "#880000"; } define3DLine(xMin,z,xMax,z,gridLineColor); } for (var x=xMin; x<=xMax; x+=xInc) { if ((x < xMiddle-smidge) || (x > xMiddle+smidge)) { gridLineColor = "#000088"; } else { gridLineColor = "#880000"; } define3DLine(x,zMin,x,zMax,gridLineColor); } } //defineReferenceGrid |
The grid fits to the layout so well because I make use of the fact that I had the boundary locations available since they’d been calculated to identify the center about which the camera flies and at which it looks. I extended the grid exactly one block in each direction. I wanted the blocks to be (roughly) square so I created more of them in the z-direction than in the x-direction. Last but not least the function can and should be parameterized instead of hard-coded like I’ve done here, but that’s a trivial matter.
I put the following scene together as part of preparations for a presentation. The code for generating the grid is a bit more primitive but this exercise drove me to learn how to modify the endpoints of existing lines as well as their color. In define3DLine
we specify the endpoints as a pair of vector objects pushed into an array called vertices
. If we want to modify those endpoints we simply dereference them in the other direction. The trick in this case is knowing you need to set the flag which lets the framework know the change needs to be processed internally. Some operation are straightforward — you just change and value and it takes effect (the line’s color works this way as we’ve already seen). In other cases you have to set the flag because the framework has to do something extra in response to the changes that wouldn’t happen naturally.
Always be on the lookout for such gotchas if the first thing you try doesn’t work the way you think it should. As it happens I found the verticesNeedUpdate
property when I was using the Firefox debugger to inspect the line I was trying to change. A quick search in the documentation told me that my hunch was correct. You know what they say: RTFM.
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 |
//define a line in 3D function define3DLine(x1,y1,z1,x2,y2,z2,lineColor) { var gridMaterial = new THREE.LineBasicMaterial({ color: lineColor }); var geometry = new THREE.Geometry(); geometry.vertices.push( new THREE.Vector3(x1, y1, z1), new THREE.Vector3(x2, y2, z2) ); var line = new THREE.Line(geometry, gridMaterial); scene.add(line); return line; } function colorToHex(color) { //strip off hash character var c = color.slice(1,color.length); //if 3 convert to 6 if (c.length == 3) { c = c[0] + c[0] + c[1] + c[1] + c[2] + c[2]; } return "0x" + c; } //modify an existing line function update3DLine(segment, x1, y1, z1, x2, y2, z2, lineColor) { segment.geometry.vertices[0].x = x1; segment.geometry.vertices[0].y = y1; segment.geometry.vertices[0].z = z1; segment.geometry.vertices[1].x = x2; segment.geometry.vertices[1].y = y2; segment.geometry.vertices[1].z = z2; //set flag so new coordinates are used segment.geometry.verticesNeedUpdate = true; segment.material.color.setHex(colorToHex(lineColor)); } |
You can see the results here, in the lines showing where the camera is located as it orbits the scene. The camera does the same thing in the simulation code demos up to this point as well.