Some parts of the model goes into terrain (Collision problem)

Hi all, I’ve applied Terrain Generation from Heightmap and it worked like a charm. The problem is that sometimes my character’s parts go into the ground/terrain like in the gif above. I’ve set my character’s rigid body & collision properly (as you can see in the gif - sometimes it looks ok).

I suspect the terrain’s attributes ratio - height, width, and subdivisions. But I’ve changed a lot of these to find the right balance, it did not work out so far.

P.S: I’ve used both Sphere and Capsule for rigid body

Any ideas on this?
Screen_Recording_2022-11-09_at_14_53_27_AdobeExpress

It looks like the collision mesh is off from the GIF

@LeXXik Does your Ammo drawer handle rendering custom meshes?

@Ertugrul_Cetin for your reference: GitHub - LeXXik/ammo-debug-drawer: A helper class to debug draw Ammo physics world state in PlayCanvas.

1 Like

@yaustar yes, it does.

@Ertugrul_Cetin you can use the linked helper class to debug draw the state of the Ammo’s dynamics world to see if there is a difference between what Ammo sees and what you see.

Edit:
Please, grab the latest version here:
https://playcanvas.com/project/744419/overview/ammo-debug-draw
I need to update the github repo as well…

2 Likes

@LeXXik @yaustar here is the GIF with the ammo debug drawer. Looks like it happens on some big triangles, but could not understand the reason.

Screen_Recording_2022-11-09_at_15_50_20_AdobeExpress

Video link: Screen Recording 2022-11-09 at 15.50.20.mov - VEED

If you look carefully, you can notice that your visual mesh does not match the collision mesh. In some places the visual mesh goes below the collision mesh, in others it goes above it. When it goes above it, then it clips your capsule mesh.

Most probably the issue is in the precision loss. Somewhere along the way the data that was stored in 64 bit float typed array got saved into 32 bit float one, losing precision. Use 32 bit floats from the beginning, then you should be ok.

2 Likes

Sorry, I could not follow that part, this is something I should set in the Rigid Body or Collision component? Could you elaborate more on this to set 32-bit float value (did not do this before - also, fairly new to PlayCanvas)

How do you store/populate an array with heightfield vertex positions?

It is not PlayCanvas related. In JavaScript we use 64 bit floats for regular numbers/arrays.

const a = 5.4;
const b = [1, 2, 3];

If you save it to a 32 bit typed array, you will lose some bits, since a 64 bit cannot fit into 32 bit without losing some precision:

const b = [1, 2, 3];
const c = new Float32Array(b); // precision loss

Ammo expects a 32-bit typed array, so if you feed it a 64-bit one, you will lose some precision.

2 Likes

Ah I see, I thought there is some shader setting I had to set like precision mediump float; or some setting in the editor. Let me check that JS code then.

@LeXXik Here is my terrain.js (line populating vertex data): terrain.js · GitHub

When I make a change from this to this;

var positions = [];
var uvs = [];
var indices = [];

=====================>

var length = options.subdivisions * options.subdivisions;
var positions = new Uint32Array(length);
var uvs = new Uint32Array(length);
var indices = new Uint32Array(length * 6);

mesh.setIndices accepts Uint32Array so could not use that Float32Array

My terrain disappears and getting these kinds of errors ;

Looks like it’s related to collisionMesh creation ( this.createTerrainFromHeightMap(img, this.subdivisions / 2);).

@yaustar do you have any idea why we’re diving subdivisions to 2 when creating collisionMesh? (this is the tutorials version)

I just removed / 2 part from collisionMesh and made it the same with visualMesh, but this height map tutorial generates with subdivisions / 2 for collisionMesh.

var visualMesh = this.createTerrainFromHeightMap(img, this.subdivisions);
var collisionMesh = this.createTerrainFromHeightMap(img, this.subdivisions / 2);

===>

var visualMesh = this.createTerrainFromHeightMap(img, this.subdivisions);
var collisionMesh = this.createTerrainFromHeightMap(img, this.subdivisions);

Yes, indices are integers, so should be ok to use unsigned int 32 (uint32). Positions (vertices) should be a float array.
As for the error - it seems you have a size mismatch. Probably didn’t calculate the texture size correctly?
As for the subdivisions, if you divide a square by half horizontally, you get 1 subdivision. Then if you do it vertically - you get another one. Two in total. So, total subdivisions divide by 2, just means amount of subdivisions on one side of a square.

As for the error - it seems you have a size mismatch. Probably didn’t calculate the texture size correctly?

Could be, need to check it not sure atm.

About the subdivision thing, is it ok for me to have the same generation code createTerrainFromHeightMap(img, this.subdivisions) for both visualMesh and collisionMesh?

Like, in the previous code - dividing subdivisions of collisionMesh by 2 - provides some optimization/performance? (this version causes the problem tho - in my case)

Yes it will provide slightly better performance but in this case that you want maximum accuracy it’s better to use the exact same mesh for the collision shape.

1 Like

Right, the less subdivisions you have, the lower resolution your mesh will be, the less memory it will occupy, the faster it will load, the uglier it will look.

1 Like

@LeXXik thank you so much for all the help!

1 Like