Jump to content

Cannon.js Heightfield from Imported Mesh ?


Raggar
 Share

Recommended Posts

I need some simple pointers on how to turn an imported model into a Cannon.js heightfield.

I would prefer this over actual heightmaps, as I feel that I'm more in control of the design of the ground.

I made a simple PG example so I can test it along the way. Just a very basic model made out of a 20x20 plane.

How would you pull the positions(Especially Y) on the individual vertices, so they can be used to create the heightfield shape and added to a Cannon.js body?

 

This is the relevant code from the heightfield demo:

  var matrix = [];
            var sizeX = 15,
                sizeY = 15;
            for (var i = 0; i < sizeX; i++) {
                matrix.push([]);
                for (var j = 0; j < sizeY; j++) {
                    var height = Math.cos(i/sizeX * Math.PI * 2)*Math.cos(j/sizeY * Math.PI * 2) + 2;
                    if(i===0 || i === sizeX-1 || j===0 || j === sizeY-1)
                        height = 3;
                    matrix[i].push(height);
                }
            }

https://github.com/schteppe/cannon.js/blob/master/demos/heightfield.html

 

 

Link to comment
Share on other sites

Well. I am not making any progress, that's for sure.

I'm trying to find out how the DiStraction demo does it: http://www.babylonjs.com/Demos/Distraction/

I'm using the very same mesh, with most of the stuff stripped off.

But for some reason, when I try in the playground, the verticies are all aligned flat, and the sphere just falls through where the heightfield is supposed to be:

http://www.babylonjs-playground.com/#PTXTK#7

If you comment out o.dispose() on line 133, you'll see the shope of the original imported mesh

 

 

Here is the original, unminified code, if that would help anyone make sence of this:

 

Ground.prototype._createGround = function() {
        this.msgCallback && this.msgCallback("create ground...");
      
        var e = this;
        BABYLON.SceneLoader.ImportMesh("", this.groundPath, this.groundMesh, this.scene, function(t) {
            
    
            var i, s;
            for (i = 0; i < t.length; i++) {
                var o = t[i];
                if (-1 !== o.name.indexOf("Water") && (o.receiveShadows = !0), -1 !== o.name.indexOf("Support") && (o.receiveShadows = !0), null !== o.getVerticesData(BABYLON.VertexBuffer.PositionKind))
                    if (o.name === e.groundMeshName) {
                        e.ground = new BABYLON.GroundMesh("", e.scene), e.ground._setReady(!1), e.ground._subdivisions = e.subdivision;
                        var a = BABYLON.VertexData.CreateGround(e.width, e.depth, e.subdivision);
                        if (null !== e.groundTexture) {
                            var n = new BABYLON.StandardMaterial("", e.scene);
                            n.alpha = 1;
                            n.diffuseTexture = new BABYLON.Texture(e.groundTexture, e.scene), n.backFaceCulling = !0, e.ground.material = n
                        }
                        var r = a.positions,
                            d = o.getVerticesData(BABYLON.VertexBuffer.PositionKind),
                            h = d.length / 3,
                            l = e.width / e.scaleFactor;
                        for (s = 0; h > s; s++) {
                            var c = d[3 * s] * o.scaling.x,
                                p = d[3 * s + 1] * o.scaling.y,
                                u = d[3 * s + 2] * o.scaling.z,
                                g = Math.round((c + l / 2) * e.subdivision / l),
                                f = Math.round((u + l / 2) * e.subdivision / l),
                                m = g,
                                w = e.subdivision - f,
                                B = m + (e.subdivision + 1) * w;
                            r[3 * B + 1] = p * e.scaleFactor + 50
                        }
                        var C = a.normals,
                            y = a.indices;
                        BABYLON.VertexData.ComputeNormals(r, y, C), a.applyToMesh(e.ground, !1), e.ground._setReady(!0), o.dispose(), e.ground.receiveShadows = !0, e._createCannonHeightfield()
                    } 
					
					
					
					
					else e._moveAndScaleMesh(o), o.convertToFlatShadedMesh();
                else e._testEmptyMesh(o)
            }
        })
        
        
       
        
       
    }
    
    
    
    Ground.prototype._createCannonHeightfield = function() {
        var t, a, n, s = this.ground.getVerticesData(BABYLON.VertexBuffer.PositionKind),
            o = [];
        for (a = 0; a <= this.subdivision; a++)
            for (o.push([]), n = 0; n <= this.subdivision; n++) {
                var r = a + (this.subdivision + 1) * (this.subdivision - n);
                t = s[3 * r + 1], o[a].push(t)
            }
        var d = new CANNON.Heightfield(o, {
            elementSize: this.width / this.subdivision
        });
        
        this.groundBody = new CANNON.Body({
            mass: 0,
            material: this.groundMaterial
        });
        
        this.groundBody.addShape(d);
        this.groundBody.position.set(-this.width / 2, -this.depth / 2, 0);
        this.groundBody.collisionFilterGroup = this.groundCollisionFilterGroup;
        this.groundBody.collisionFilterMask = this.groundCollisionFilterMask;
        this.world.add(this.groundBody);
       
      //  this._loadSolidBuildings();
        this._loadSolidBox();
        
        if (this.onLoadFinished) { 
            this.onLoadFinished(); 
        }
    };
    
    
    Ground.prototype._testEmptyMesh = function(e) {
        var t, i = !1;
        for (t = 0; t < this.scene.meshes.length; t++) {
            var s = this.scene.meshes[t];
            if (s.parent === e) {
                i = !0;
                break
            }
        }
        i ? e.setEnabled(true) : e.dispose()
   
    };

 

Link to comment
Share on other sites

Hey,

why work hard, when everything is already implemented? :)

http://www.babylonjs-playground.com/#1GQK6J

You just need to be conform with a babylon heightmap, and you are fine. This is whyt I removed the parent (which indicates compound physics bodies), and baked the transformation into the heightmap.

 

Link to comment
Share on other sites

Well, that would certainly work client-side. But when it comes to running the same simulations server-side, using only Cannon.js, and not Babylon.js, this simply won't work. :)

I'm planning on using the array of vertex positions to recreate the heightfield server-side, but as testing blindy isn't quite as easy as having some visuals, I'll see if I can make it work using Babylon.js first.

This is what I got so far:

http://www.babylonjs-playground.com/#1B5UCR#3

Using the VertexData tutorial from pixelcodr:

http://pixelcodr.com/tutos/trees/trees.html

 

As you can see, the randomization of the vertices is successful, but when I try to apply the vertex information from the imported mesh into the created ground mesh, it simply gets all messed up.

If you check the console, you see that the getVerticesData function ran against the created ground mesh results in an array of 288, where as the same function ran against the imported mesh results in 75.

Why is this? The ground consists of a 4x4 grid, and the model is made using a 4x4 grid aswell. Shouldn't they have the same number of vertices?

Now I think about it, the 3Ds Max model might have been made out of rectangles instead of triangles. Hmm.

Link to comment
Share on other sites

why does everyone want to do all their hit testing server side?  This is not the way to do it, yes you want to do secondary calculations on the server but the majority of the i/O's need to be calculated on the client then pushed to the sever to confirm that it was valid and if they are out of a normal range push them back in.

Link to comment
Share on other sites

I can't speak for anyone else, but this is the way I have chosen to approach it :)

 

Edit: Making a triangular mesh creates the same amount of vertices, so that's not where the problem lies.

Another thing, if I change lines 44 and 45 to:

var positions2 = ground.getVerticesData(BABYLON.VertexBuffer.PositionKind);
var positions = newMeshes[1].getVerticesData(BABYLON.VertexBuffer.PositionKind);

In order to get the positional data on the vertices of the imported model, I get a double: TypeError: i is undefined | babylon.js:6:14936.
 

 

Link to comment
Share on other sites

@hen suggested the same thing, but I haven't had much time lately. I'll see if I can make it work later tonight, as I did one quick test. This test was almost a success, as it worked with a mesh created with babylon, but not a model imported on my own. I might have missed something, though.

Link to comment
Share on other sites

I see that I forgot to reply.

@RaananW's suggestion worked like a charm, and copying the matrix to the server-side only took a matter of minutes with some organized logging.

As the server and the client run the same simulations, they seem to sync up pretty well, but player prediction in mind. But prediction, compensation and reconciliation aren't quite easy tasks.

It really puts multiplayer in a whole new perspective.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...