Texture 3D update sub image

Hello ,

I’m currently working on a project that involves a tile-based 3D map with elevation and normal textures. To initialize the texture, I’m using gl.texImage3D, which has been working well. However, I’m facing a challenge when it comes to updating specific parts of the texture using texSubImage3D.
In the Babylon.js framework, I’m utilizing the RawTexture3D class, but it doesn’t provide direct access to texSubImage3D, which is necessary for updating only a portion of the texture at a time.

Before I reinvent the wheel and write my own code (which is basically not rocket science :-)), I wanted to reach out here for advice.

Has anyone worked on a similar use case and successfully implemented a solution for updating specific parts of a 3D texture in Babylon.js?

gl.bindTexture(gl.TEXTURE_3D, texture);
gl.texSubImage3D(gl.TEXTURE_3D, 0, xoffset, yoffset, zoffset, width, height, depth, ...);
gl.bindTexture(gl.TEXTURE_3D, null);

If you have any insights, suggestions, or code snippets, I would greatly appreciate your input.
G.

I don’t think we have functions that can update a portion of a texture, being 2D or 3D.

Contributions are always welcome if you want to tackle it!

1 Like

ok is something like this will be ok for you

import { RawTexture3D } from "@babylonjs/core/Materials/Textures/rawTexture3D";
declare module "@babylonjs/core/Materials/Textures/rawTexture3D" {
    export interface RawTexture3D {
        updatePartial(level: number, xoffset: number, yoffset: number, zoffset: number, width: number, height: number, depth: number, data: ArrayBufferView): void;
    }
}

RawTexture3D.prototype.updatePartial = function (
    level: number,
    xoffset: number,
    yoffset: number,
    zoffset: number,
    width: number,
    height: number,
    depth: number,
    data: ArrayBufferView
) {
    
};

with the support at engine level

import { InternalTexture, Nullable } from "@babylonjs/core";
import { Engine } from "@babylonjs/core/Engines/engine";

declare module "@babylonjs/core/Engines/engine" {
    export interface Engine {
        updatePartialRawTexture3D(
            texture: InternalTexture,
            level: number,
            xoffset: number,
            yoffset: number,
            zoffset: number,
            width: number,
            height: number,
            depth: number,
            data: Nullable<ArrayBufferView>,
            format: number,
            invertY: boolean,
            compression: Nullable<string>,
            textureType: number
        ): void;
    }
}

Engine.prototype.updatePartialRawTexture3D = function (
    texture: InternalTexture,
    level: number,
    xoffset: number,
    yoffset: number,
    zoffset: number,
    width: number,
    height: number,
    depth: number,
    data: Nullable<ArrayBufferView>,
    format: number,
    invertY: boolean,
    compression: Nullable<string>,
    textureType: number
): void {};

I will make some internal test and when ready I gona make a PR proposal.

Perhaps we could add parameters to the existing updateRawTexture function?

We should also add support for 2D textures and make sure to add the functionality to WebGPU as well.

cc @sebavan for feedback.

in regard to your mention of this fix , i have already being meaning to ask for a while… Whats up with the millions of attributes in functions. It seems so old school and honestly is a pain to use. Why not pass a single configuration object payload into the functions?
eg :

new RawTexture(data: Nullable, width: number, height: number, format: number, sceneOrEngine: Nullable<Scene | ThinEngine>, generateMipMaps?: boolean, invertY?: boolean, samplingMode?: number, type?: number, creationFlags?: number, useSRGBBuffer?: boolean): RawTexture

I mean for some functions , I dont need to change any of the default values for perhaps the first 5 attributes and then i only get to one I want to use… which then means I have to pass in the defaults or null etc to be able to get to the single attribute I actually want to use, thats what I mean by pain to use.

If it was a single payload , i could just create an inline object with the values I want. It also makes it easy for you to add a million more attributes to the function if you wanted without causing the situation I outlined to become worse and worse. ??

I agree, it’s mostly there for historical reasons…

I’m all for using an option object instead of countless parameters. We did it for the Texture constructor, for eg, but because we need to retain backward compatibility, the existing syntax must continue to work.

I agree. I incorporate options in my own code. However, in order to maintain code consistency, I often follow the implementation style of other objects or functions. This one also follow the gl syntax, which is more convenient to understand when dealing with the GPU.

Yes, it should be better… for the moment i just add it as extension in my own bundle, then after that i will introduce new parameters, and also give a first optional parameters as

declare module "@babylonjs/core/Materials/Textures/rawTexture3D" {
    export class UpdateRawTextureOptions {
        level: number;
        xoffset: number;
        yoffset: number;
        zoffset: number;
        width: number;
        height: number;
        depth: number;
    }

    export interface RawTexture3D {
        updatePartial(
            data: ArrayBufferView,
            level?: UpdateRawTextureOptions | number,
            xoffset?: number,
            yoffset?: number,
            zoffset?: number,
            width?: number,
            height?: number,
            depth?: number
        ): void;
    }
}