0 votes

Alright I've been at this for a bit and the doc didn't help me :(

Just for context, my goal is to make a RayMarching shader through a 3D volumetric dataset from microscopy recording. I've done it in Unity in the past and I want to continue this project. But I want to switch to Godot, out of principles, and because the Node system is just amazing.

So here I am trying to create a simple RayMarching shader through a cube, and I need to pass my 3D texture so that I can sample from the volume in the fragment shader.

So, as per the documentation, I need to use the inherited function set_layer_data which takes an Image instance, and an layer Int. Ok all good !

Well no ... the layer never gets set and pixels stay at [0.0, 0.0, 0.0, 1.0]

Here is my code sample so that one of you wizard might see what I am doing wrong ...

extends MeshInstance

var mat = get_surface_material(0)

func _ready():
    # Instanciate a Texture3D
    var tex3D = Texture3D.new()
    # Create the texture with a 64 cube with RGB8 format, we won't need Alpha
    tex3D.create(64, 64, 64, Image.FORMAT_RGB8)
    # Instanciate an image this will serve as our layer for now
    var img = Image.new()
    # Let's give it the right dimension 64x64 and the right format
    img.create(64, 64, false, Image.FORMAT_RGB8)
    # Gotta Lock it to set a pixel (this is confusing ... Like, Lock? Why not "Unlock" it ??? Anyhow)
    img.lock()
    # Define out color
    var c1 = Color("#ffb2d90a")
    # And set the pixel
    img.set_pixel(31, 31, c1)
    # Let's check that it worked ?
    print(img.get_pixel(31, 31))
    # This gives me a beautiful: 0.698039,0.85098,0.039216,1
    # Amazing let's set the layer then !
    tex3D.set_layer_data(img, 0)
    # Great so then let's see if it worked ? 
    print(tex3D.get_layer_data(0).get_pixel(31, 31))
    # 0,0,0,1
    # What ? O.o 
    print(tex3D.data['layers'][0].get_pixel(31, 31))
    # 0,0,0,1
    # Yup nothing !

    # Let's feed the texture to the shader
    mat.set_shader_param("My3DTexture", tex3D)

Edit: I also checked that I wasn't crazy by trying this on a 2D texture on a Sprite, and this worked just fine, so the pixel setting on an img works along with the texture shader pipeline.

extends Sprite

func _ready():
    var texture = ImageTexture.new()
    var img = Image.new()
    # Let's give it the right dimension 64x64 and the right format
    img.create(64, 64, false, Image.FORMAT_RGB8)
    # Gotta Lock it to set a pixel (this is confusing ... Like, Lock? Why not "Unlock" it ??? Anyhow)
    img.lock()
    # Define out color
    var c1 = Color("#ffb2d90a")
    # And set the pixel
    img.set_pixel(0, 0, c1)
    img.set_pixel(1, 1, c1)
    img.set_pixel(2, 2, c1)
    img.set_pixel(3, 3, c1)

    texture.create_from_image(img)
    material.set_shader_param("tex", texture)
in Engine by (14 points)

1 Answer

0 votes

You are right, print doesn't work, I could reproduce the problem.
However, if I render the material with a shader, it shows the exact data you set!

shader_type canvas_item;
render_mode unshaded;

uniform sampler3D tex;

void fragment() {
    COLOR = texture(tex, vec3(UV,1));
}
ago by (14 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.