Closed ghost closed 8 years ago
Yeah, I'm using Babylon.js which is a wrapper around webgl The grid itself is currently a series of semi-transparent hexagons, its most obvious if you look at the sun. You can see a bit of it below the grid through the hexagons.
https://github.com/chad-autry/hex-grid-map-3D/blob/master/src/contexts/InverseGridContext.js Is where the grid action happens.
Apologies for how messy that code is, I need to do a cleanup pass over it.
The strategy of "draw transparent hexagons to represent the grid" really depends on a 3D library I think. If you have any more questions, or want to be pointed at some actual grid line drawing resources, don't hesitate to ask.
Hi, thanks for the reply! As i understand you create the scene in HexBoard.js, then the InverseGridContext calculates the grid. What i dont get is where you put the grid into the scene and say somethig like render() to show the result. I also saw a pane or something.
What you mean with actual grid line drawing resources?
InverseGridContext calculates the grid and adds the shapes to Babylonjs, the grid is made up of a SolidParticleSystem
https://github.com/chad-autry/hex-grid-map-3D/blob/master/src/contexts/InverseGridContext.js#L8 var babylon = require('babylonjs');
https://github.com/chad-autry/hex-grid-map-3D/blob/master/src/contexts/InverseGridContext.js#L62 var SPS = new babylon.SolidParticleSystem('SPS', scene, {updatable: false, pickable: false});
Starting at line 36 of the HexBoard is where Babylon.js is passed the canvas, and its render loop is set up. https://github.com/chad-autry/hex-grid-map-3D/blob/master/src/HexBoard.js#L36
this.engine = new babylon.Engine(canvas, true);
//Run the engines render loop
this.engine.runRenderLoop(function () {
if (!!board.scene) {
board.scene.render();
}
});
require gives access to the same babylon.js object to each module.
By an actual grid drawing resource, I mean I'm drawing a hexagon for each cell of the grid. It gives a bit of a short cut, since I just need to calculate the center point of each hex. If you wanted to draw the grid lines themselves, you'd need to concern yourself even more with the geometry of the hexagon. If you haven't seen it, http://www.redblobgames.com/grids/hexagons/ is pretty much the Authority =P
Well, I only understand half of what you are doing, but i got a basic example running: http://labs.setanodus.net/babylon-hex-grid/
Next is to throw out everything “weird” and see what happens and understand what you made me do here and the mousemove so i can load new tiles with ajax.
Yes, that reblobgames was were i started :)
Tried some other solutions, for example there is a complete css solution (http://labs.setanodus.net/csshexamap/ and here with svg: http://labs.setanodus.net/csshexamap/svgtest.php) but the css 3d transition always scales the whole thing to fit the screen so i cant drag and load fresh tiles) and when the game improves i would need webgl anyway in the future so why not start with it at all :)
Thank you very much for your explanations and for sharing that code at all.
So a bit of history might possibly help you next,
The various contexts are basically 'layers' inherited from my original https://github.com/chad-autry/hex-grid-map (It simplified a bit when going to 3D actually, but I kept the context concept). The contexts provide mouse event handlers for the layers, or if none of the contexts claimed the mouse action, handled updating the position (The HexBoard has the canvas mouse event handlers, and it calls into the context's handlers). In 2D, every layer had to draw itself offset for position, but now in 3D the Babylon.js camera moves. However, the hexagonal grid is really finite, it works the same in 2D or 3D, as the view is dragged, the context's updatePostion method recenters the finite grid on the hexagon/cell in the middle of the view.
Note: Even though the grid is finite, you should be able to individually size, texture, and rotate them based on the position they occupy when drawn..
Similarly the finite invisible 'pickerPlane' gets re-centered.
The main complexity in the mouse drag, is in finding the drag translation on our plane, vs on the canvas itself (movement at the top of the canvas moves further on our plane since it is further away than movement at the bottom where the plan is nearer)
Finally, the co-ordinates I chose back when I was in 2D don't match well with babylon.js's default co-ordinates. You might hit some confusion as you try and add shapes in to your scene.
ok, can drag now: http://labs.setanodus.net/babylon-hex-grid/test2.php
You say its finite, and in my example it actualy is, but in your demo you can drag it endlessly. When i am always dragging the plane, how do you find out when a tile is clicked?
scene.pick is used to convert canvas X, Y to babylon.js/planar X/Y https://github.com/chad-autry/hex-grid-map-3D/blob/master/src/HexBoard.js#L88
https://github.com/chad-autry/hex-grid-map-3D/blob/master/src/HexBoard.js#L192 passes that to a global mouse clicked function (if we didn't drag, and another context didn't claim the mouse event)
The demo uses hexDimensions.getReferencePoint to convert a planar X/Y into U, V. Then it broadcasts its alert. https://github.com/chad-autry/hex-grid-map-3D/blob/master/gh-pages/src/app/demo/demo.js#L105 Then
ya i just figured that out:
var hexagonalCoordinates = hexDimensions.getReferencePoint(pickResult.pickedPoint.x, pickResult.pickedPoint.y);
console.log('hexagonalCoordinates');
console.log(hexagonalCoordinates);
Cant find anywhere where you load new tiles, but your demo is infinite, pulled till -1000|-300. In the init you have positionArray until i<31.
What is that: var EmittingDataSource = require('data-chains/src/EmittingDataSource.js'); $scope.cellDataSource = new EmittingDataSource();
an external project to add the objects?
The grid is finite, but re-positioned so it appears infinte Positioning Method
If you can build and run the demo locally, changing 31 --> 5 at Finite Grid Loop should make it apparent.
Aaaaaah, got it: http://labs.setanodus.net/babylon-hex-grid/test3.php
So i can load the tiles with ajax line by line, during dragging, not complete areas on dragend.
very clever :D
Thats weird: i used code from this playground: http://babylonjs-playground.azurewebsites.net/#HSVQL, and the result is upside-down: http://labs.setanodus.net/babylon-hex-grid/test4.php Did you inverse the coordinate system or something? Or did I ?
Yeah, that's what I meant from the comment earlier.
Finally, the co-ordinates I chose back when I was in 2D don't match well with babylon.js's default co-ordinates. You might hit some confusion as you try and add shapes in to your scene.
Since I started over in 2D, I adopted canvas co-ordinates of x+ is to the right, y+ is down/out of the screen. Then I used z+ for height above the grid.
Babylon.js default is I believe x+ right, y+ up, z+ into the screen. So if we were looking at the grid edge on, we'd be rotated 90 degrees compared to Babylon.js, but then our top down view means we're rotated even further and yeah, looking at playground scene with Babylon.js defaults upside down.
I had to explicitly tell Babylon.js the camera is allowed to be upside down, or it would have auto-rotated the view Allow Upside Down
I hadn't considered the issue with billboards.
Luckily, I think rotating the texture, should give the desired effect outputplaneTexture.wAng = Math.PI;
Now I understand what you have done, but not why. You didnt wnat to change the coordinate system to fit the babylonjs Standard? Your tile enumeration is also different from http://www.redblobgames.com/grids/hexagons/ i think i have to change that to make the calculations (distance aso) work.
also weird is, that that text rotates when you drag around, since we never rotate the camera.
Yeah, I didn't want to change. The 3D hex grid map was initially just an experiment, I wanted to have it be as compatible as possible with the original 2D version. I literally started with the 2D version and started changing things to use Babylon.js. I also wanted to remain consistent with cartesian-hexagonal, which converts between U, V <--> X, Y and is shared with the 2D version.
My hexagonal-coordinates are the same as redblobgame's Axial Coordinates, with the minor caveat that pairs are swapped (I was looking at a ton of different hexagon sources and didn't write this soley from his site) More explicitlly, if you look at his demo my V is his green co-ordinate (it increases going up and to the right [+x, and -y]). He puts that axis first when writing a pair, it is simply second in my pair. My U is his blue axis (it increases going down [+y]). He puts that axis first when writing a pair. It is first for me.
I comprehend the "max" format for counting distance best myself,
max(abs(a.x - b.x), abs(a.y - b.y), abs(a.z - b.z))
Converting into my coords does give a formula he doesn't have directly, but I think it should be noticeable U and V are interchangeable. vs the cube distance formula he shows for axial.
max(abs(a.U - b.U), abs(a.V - b.V), abs(-a.U-a.V + b.U+b.V))
For the rotation, it is trying to orient the 'top' facing the camera. Which is really our bottom and is looking weird. You could constrain the rotation to the Z axis, though that won't 100% provide the same functionality. since it won't tilt up.
Just a note that I had another idea to try setting the camera's upVector. Unfortunately it does not appear to be used for billboards by the ArcRotate camera at least.
I tried to start from scratch with correct values but i do not get at all how that coordinate system works: http://labs.setanodus.net/babylon-hex-grid/babylon-hexagon-gameboard-v1.php they seem to be completly random.
Last thing i want to understand from your code is how exactly a placed object "claims" the mouseclick. You use another library for event handling that obfuscates how exactly shapes are created and placed.
I tried to start from scratch with correct values but i do not get at all how that coordinate system works: http://labs.setanodus.net/babylon-hex-grid/babylon-hexagon-gameboard-v1.php they seem to be completly random.
Converting co-ordinates is hard, which is why I didn't do it =P I notice your hexagons are flat up, don't know if that was intended or if you have a hidden 90 degree rotation (mine are point up).
Last thing i want to understand from your code is how exactly a placed object "claims" the mouseclick. Adding items and drawing is probably a bit over-complicated, in the pursuit of being extensible.
HexBoard has the direct mouse listener and delegates to each context to see if a context claims a click click delegation
Initially, each context was injected with a DrawnItemFactory, and listened to a listened to a DataSource(just a list with events). When a JavaScript object was added to the DataSource, the context would would create/draw the item. It was also responsible for delegating any mouse clicks to the item as applicable.
The Demo's pathContext (used to draw the orange line) is still that way. Path Context Initialization Orange Path Added to DataSource I notice now I have a bug with my drawn item context, clicking the orange path doesn't popup the an alert like it should.
The CellContext was a bit more complex, since it had to figure out stacking of items. And managed buckets and whatnot. Back in 2D land there was even the ability to drag the entire stack up and down to 'scroll' through it. Anyways, that DataSource (an evented list conceptually) could be chained together, and have logic place in it for filtering and transforming. So that is where I pushed the individual tasks of transforming a DTO --> Babylon.js object --> Translating the object to the correct cartesian coordinates for its axial --> Translating the object above the plain, given other items at the same axial. They each have their own DataSource/DataLink
So now the CellContext is only responsible for delegating mouse events, which it mostly does using Babylon's picking function, and a 'isCellItem' flag we decorated the mesh with. The CellContext doesn't even need to listen to the DataSource anymore, except that the way I started to show dragging was to introduce a drag target, which I want to swap control to (On second look, I could maybe even remove that by introducing a stationary drag source, and move/transform the clicked item itself)
i am not yet converting them, i'm just trying to paint some of them manually:
var hexagonWidth = 72;
var hexagonWidthHalf = Math.round(72/2);
var hexagonMargin = 0.5;
var hexagon = BABYLON.MeshBuilder.CreateDisc('t', {
radius: hexagonWidthHalf,
tessellation: 6,
sideOrientation: BABYLON.Mesh.DOUBLESIDE
}, scene);
var tilePositions = [{x:0,y:0},{x:54,y:54},{x:-54,y:-54},{x:-54,y:36}];
console.log(tilePositions);
var SPS = new BABYLON.SolidParticleSystem('SPS', scene, {updatable: false, pickable: false});
SPS.addShape(hexagon, tilePositions.length, {
positionFunction: function(particle, i, s) {
particle.position.x = tilePositions[i].x;//(Math.random() - 0.5) * fact;
particle.position.z = tilePositions[i].y;//(Math.random() - 0.5) * fact;
particle.position.y = 0;//Math.floor(Math.random() * (50-1));
//particle.rotation.x = Math.random() * 3.15;
//particle.rotation.y = Math.random() * 3.15;
particle.rotation.y = 0;
particle.color = new BABYLON.Color4(1, 1, 1, 0.125);
}
});
var grid = SPS.buildMesh();
i also did not rotate any tile, i just put the camera to a standard position: all zero and distance 500
var camera = new BABYLON.ArcRotateCamera('ArcRotateCamera', 0, 0, 0, BABYLON.Vector3.Zero(), scene);
camera.setPosition(new BABYLON.Vector3(0, 500, 500));
camera.setTarget(BABYLON.Vector3.Zero());
var cameraTargetX = 0;
var cameraTargetY = 0;
particle.position.z = tilePositions[i].y;//(Math.random() - 0.5) * fact;
particle.position.y = 0;//Math.floor(Math.random() * (50-1));
You're trying to flip the Y and Z co-ordinates, you also left out the particle rotation I had. That is what I meant by "converting." You're converting my cartesian orientation to Babylon.js's default. Its going to require some mental gymnastics to get that sorted, which I really didn't want to do, but now that I've thought of it a bit too late =P
The key you're missing, I think, is my Z <--> Babylon.js Y, but my Y <--> negative Babylon.js Z. So you need to invert the y/z co-ordinate of all your tile positions (assuming to mined them as my original Y positions).
Additionally your choice of camera position means that babylon.js spun the scene around and +X is to the left, probablly causing you additional confusion. (Because it has the constraint of +Y is up, but it has +Z as into the screen, so you're looking at the scene from behind as it keeps the camera oriented upwards.)
Sometimes I've found it helpful to insert colored spheres into a scene to visualize my orientation. Red in the + X, Green in the +Y, and Blue in the +Z directions.
nearly got it with the babylon coordinates, only adopting the pickerplane wont work. if i change here positioning from y to z, it is centered correctly, but it moves way to fast if i let it, it works but gets bigger/smaller on dragging an both variants give wronger coordinates the farer away you get from zero|zero: http://labs.setanodus.net/babylon-hex-grid/babylon-hexagon-gameboard-v2.php
i think i basically dont get something of how you place the plane.
We're well beyond the point of questions on hex-grid-map-3D, and into debugging your local changes.
I welcome further questions on how I've done things, but I'm not interested in debugging a re-write or co-ordinate transformation.
Of course, I should have been more specific: i made the plane smaller and gave it color so you can see it on one look and tell me if its still placed right - thats all.
Looks tilted
Hi!
I am currently trying to to get a hexagonal 3d grid like you have it here. i gues you are drawing it with webgl and i am very interested in that matter, but this project is way to complex for me to understand everything you joined here together or even get it running.
Can you give me a hint were to look for the actual drawing the grid code? Since your example is exactly what i am looking for, i hope you can get me in the right direction.