How to read pixels from SubViewport image?
- Edited
renight0 You need to manually update global position of Camera3D that's parented to SubViewport, every frame. Best to do it in _process()
in LightDetect.gd
. It won't automatically inherit any 3D transforms from ancestor nodes because 3D transformation chain is broken by inserting non-3D nodes (SubViewport and SubViewportContainer) inbetween.
Alternatively you can use RemoteTransform3D
node to drive camera's position.
- Edited
xyz I tried both ways. I'm not sure I did it correctly. First I tried the RemoteTransform3D node (didn't know this node before) (How do I highlight these names?). I set the Remote Path to the Light Detect (Node 3D parent) and it did not work.
Then I tried the following code on _process() in LightDetect.gd and also got the same result.
extends Node3D
var LightLevel : float
@onready var camera_3d: Camera3D = $SubViewportContainer/SubViewport/Camera3D
@onready var light_detect: Node3D = $"."
func _process(delta: float) -> void:
# The following code will take a screenshot of our camera and create an array of floats
# that will be used to average the float values so we can determine our general lightness
# values. Obs: An image is like an array of pixels
#var image : Image = get_node("SubViewportContainer/SubViewport").get_texture().get_image()
camera_3d.global_position = light_detect.global_position + Vector3(0,1.3,0)
var LightDetectSV : SubViewport = get_tree().get_nodes_in_group("LightDetectSubViewport")[0]
var image : Image = LightDetectSV.get_texture().get_image()
var floats : Array[float]
for y in range(0, image.get_height()):
for x in range (0, image.get_width()):
var pixel = image.get_pixel(x,y)
var lightValue = (pixel.r + pixel.g + pixel.b) / 3
floats.append(lightValue)
return average(floats)
pass
func average(numbers: Array[float]) :
var sum = 0.0
for n in numbers:
sum += n
return sum / numbers.size()
- Edited
xyz In what way it didn't work?
The lightValue is always zero and the floats array is always [0,0,0,...0]. There values should be in a 0 to 1 interval.
xyz Also why do you return something from _process() whose return value is declared void?
I should probably have made the floats array a "public" global variable instead of trying to return something. It needs to be read by other scripts.
xyz Now it worked!
I had been missing 2 thing:
I completely forgot to assign LightLevel = average(floats)
At some point I hid the LightDetect scene nodes i-i
Thanks for pointing out I needed to move the camera LightDetect scene camera by code. I had no idea. I just checked and you're completely right.