0 votes

I'm working with shaders, where I want to provide a Texture3D as input to the shader. To do so I need to define the data in the Texture3D. But I'm having troubles doing so.

First I create my image, and set the value of its only pixel to 0.7, 0,0,0:

var image = Image.new()
image.create(1, 1, false, Image.FORMAT_RGB8)
image.lock()
image.set_pixel( 0,0, Color(0.7, 0.0, 0.0, 0.0))

When I check the pixel value, it seems to have worked, as image.get_pixel(0,0) gives me 0.698039,0,0,1.

Then I try to use the image to define data in a Texture3D

var texture = Texture3D.new()
texture.create( 1, 1, 1, Image.FORMAT_RGB8 )
texture.set_layer_data(image, 1)

But when I check the pixel value, it has suddenly changed. texture.data['layers'][0].get_pixel(0,0)) gives 0,0,0,1 as output. And it doesn't seem to work to set the pixel value after it has been entered into the texture:

texture.data['layers'][0].lock()
texture.data['layers'][0].set_pixel(0,0, Color(0.7, 0.0, 0.0, 0.0))

does not work as it gives the error set_pixel: Image must be locked with 'lock()' before using set_pixel().

So, why isn't the above working? And a more open question is: how would one properly define the data in a Texture3D?

in Engine by (139 points)

Shouldn't it also be texture.set_layer_data(image, 0)?

You are correct! I came to the same conclusion independently =). Should have read your comment earlier xD.

2 Answers

0 votes
Best answer

As Tim Martin pointed out, the problem was that I tried to set partial data on the wrong layer

texture.set_layer_data(image, 1)  # incorrect, since index of layer is 0
texture.set_layer_data(image, 0)  # correct
by (139 points)
+1 vote

I never created a Texture3D from code before, but I'm not sure if data is meant to be used in this way.

texture.data['layers'][0].lock()
texture.data['layers'][0].set_pixel(0,0, Color(0.7, 0.0, 0.0, 0.0))

Sounds like data returned you a copy of the data (and not just one layer, the WHOLE data). So you locked the copy, but then set_pixel fails because it's another copy you are getting.

For comparison, the same happens if you do this with a regular texture, for example:

texture.get_data().lock() # Returns a COPY (which is immediately dropped)
texture.get_data().set_pixel(...) # Returns ANOTHER COPY (so wont work)

Besides, even if modifying the pixel in the image worked, it won't update the texture on your graphics card. Only the image the data property will have downloaded from it.

If you want to modify pixels of a Texture3D, you have to re-upload layers the same way as you did at the beginning. To update only a sub-region of it, maybe you can use set_data_partial: https://docs.godotengine.org/en/stable/classes/class_texturelayered.html#class-texturelayered-method-set-data-partial

by (27,766 points)

Besides, even if modifying the pixel in the image worked, it won't update the texture on your graphics card.

My plan was to provide the Texture3D as input to the shader through a uniform variable. So all of the above is an attempt to create the input to the shader before passing it to the GPU. I've asked whether or not that is a good idea in a comment to your reply here: https://godotengine.org/qa/81989/how-to-explicitly-run-shader-on-a-mesh

If you want to modify pixels of a Texture3D, you have to re-upload layers the same way as you did at the beginning

My major point is that this doesn't seem to work. I create the image, set the pixel values I want, but then after I use that image to define data in the texture, the data in the texture is not what I defined in the image.

Ok - I found the problem while typing the above. The problem was that I tried to set the data on the wrong layer:

texture.set_layer_data(image, 1)  # <-------- incorrect, since index of layer is 0
texture.set_layer_data(image, 0)  # <-------- correct
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.