GroundMesh - How to get mixTexture value at point?

Hi:

I would like to be able to retrieve the RGB value of the mixTexture for a GroundMesh at a given point. This would be used to drive logic such as object placement and movement speeds for objects on the map.

My current plan of attack is to write something similar to the HeightMap processing code in groundMesh.ts that processes the mixMap and maintains a set of RGB values similar to the _heightQuads array.

Before I implement that though, I’m wondering if there is a simpler way of doing this? It seems like this would be a common operation when working with GroundMeshes. Perhaps I am missing an API?

Thanks!

Eric

Welcome to the forum !!!

Nope, I am not aware of such feature. you might have to handle the process on the cpu fully as you described. depending of the usage frequency, you could render the requested position only into a 1*1 texture and read back the value :slight_smile: but this wont scale if it is used quite often.

1 Like

Thanks for the advice Sebavan. I have one follow-up question. I’m using es6 typescript and am receiving an error ‘property resizeImageBitmap’ does not exist on type ‘Engine’.

my devDependencies are:

“devDependencies”: {
@babylonjs/core”: “^4.2.0”,
@babylonjs/gui”: “^4.2.0”,
@babylonjs/inspector”: “^4.2.0”,
@babylonjs/loaders”: “^4.2.0”,
@babylonjs/materials”: “^4.2.0”,
@babylonjs/post-processes”: “^4.2.0”,
@babylonjs/procedural-textures”: “^4.2.0”,
@babylonjs/serializers”: “^4.2.0”,
“clean-webpack-plugin”: “^4.0.0-alpha.0”,
“html-webpack-plugin”: “^5.3.2”,
“ts-loader”: “^9.2.3”,
“typescript”: “^4.3.4”,
“webpack”: “^5.40.0”,
“webpack-cli”: “^4.7.2”,
“webpack-dev-server”: “^3.11.2”
},

I don’t see the symbol ‘resizeImageBitmap’ anywhere in the source under node_modules. Do I need an additional or more recent package?

This has been added recently I guess so you d need to be on 5.0 preview version ?

Hmm… that resolves the symbol, but it appears that the materials library doesn’t play nicely with 5.0.
I guess I’ll just have to stick with 4.2 and re-implement that function as a member of my utility class.

You need to have the same version for all the @babylonjs/… to make it work

For what it’s worth, here’s what I wound up implementing. Can’t swear it’s bug free, but it holds up to five minutes of clicking around at random on my ground mesh. Many thanks for the assist!

import { Scene } from “@babylonjs/core/scene”;
import { Color3, Vector3 } from “@babylonjs/core/Maths/math”;
import { Tools } from “@babylonjs/core/Misc”;

export class ColorMap {
private _cellColors = new Array();
private _subdivisionsX : number;
private _subdivisionsY : number;
private _width: number;
private _height: number;

constructor(scene: Scene, 
    url: string, 
    subdivisionsX: number, 
    subdivisionsY: number, 
    width: number,
    height: number) {
        this._subdivisionsX = Math.floor(subdivisionsX);
        this._subdivisionsY = Math.floor(subdivisionsY);
        this._width = width;
        this._height = height;
        this.buildColorMap(scene, url);
    }

public getColorAtPosition(position : Vector3) : Color3 {
    let idx = this._getIndexForPosition(position);
    return this._cellColors[idx];
}

private _getIndexForPosition(position: Vector3) : number {
    let idxX = (((position.x + this._width / 2) / this._width) * (this._subdivisionsX - 1));
    let idxY = ((1.0 - (position.z + this._height / 2) / this._height) * (this._subdivisionsY - 1));    

    return Math.floor(idxX) + Math.floor(idxY) * this._subdivisionsX;
}

private buildColorMap(scene: Scene, url: string) {
    var onload = (img: HTMLImageElement | ImageBitmap) => {
        let bufferWidth = img.width;
        let bufferHeight = img.height;

        if (scene!.isDisposed) {
            return;
        }

        let buffer = <Uint8Array>(ColorMap._resizeImageBitmap(scene, img, bufferWidth, bufferHeight));

        // save off color in upper left pixel of this subdivision
        // TODO:  consider averaging the pixels in this cell

        for (let row = 0; row < this._subdivisionsY; row++) {
            for (let col = 0; col < this._subdivisionsX; col++) {
                // calculate position relative to the center of the image.
                // This is what will be returned in the PickingInfo on a mouse notification.
                let position = new Vector3((col * this._width) / this._subdivisionsX - (this._width / 2.0), 
                                        0, 
                                        ((this._subdivisionsY - row) * this._height) / this._subdivisionsY - (this._height / 2.0));

                // Get the index of the RGB value for this position
                let idxX = (((position.x + this._width / 2) / this._width) * (bufferWidth - 1)) | 0;
                let idxY = ((1.0 - (position.z + this._height / 2) / this._height) * (bufferHeight - 1)) | 0;    

                let idx = (Math.floor(idxX) + Math.floor(idxY) * bufferWidth) * 4;
           
                let color = new Color3(buffer[idx] / 255.0,
                                       buffer[idx + 1] / 255.0,
                                       buffer[idx + 2] / 255.0);

                this._cellColors.push(color);
            }
        }
    };

    Tools.LoadImage(url, onload, () => { }, scene.offlineProvider);
}

// this is (mostly) cribbed from the 5.0 Engine object and should be removed in favor of 
// engine.resizeImageBitmap once 5.0 is released.

private static _resizeImageBitmap(scene : Scene,
    image: HTMLImageElement | ImageBitmap, 
    bufferWidth: number, 
    bufferHeight: number): Uint8Array {

    let canvas = document.createElement("canvas");
    canvas.width = bufferWidth;
    canvas.height = bufferHeight;

    let context = canvas.getContext("2d");

    context.drawImage(image, 0, 0);

    let buffer = <Uint8Array>(<any>context.getImageData(0,0,bufferWidth, bufferHeight).data);
    return buffer;
}

}