I’m pulling my hair out trying to understand a weird behavior with one shot render to texture. In the example code below, I have a render to texture buffer which is set to one shot from a task. Another task is waiting for the texture to be ready and then applies it on a card.
Most of the time this works as expected, at frame number 1 the render buffer is created and activated in one shot mode in the first task. In frame 2, the second task checks that the texture has data and if so applies it on the card.
In that case I get the following log:
New buffer color_bits=24 red_bits=8 green_bits=8 blue_bits=8 1 Triggered 2 WAIT 2 APPLY 2d_texture 2-d, 256 x 256 pixels, each 3 bytes, rgb, compression off sampler wrap(u=repeat, v=repeat, w=repeat, border=0 0 0 1) filter(min=default, mag=default, aniso=0) lod(min=-1000, max=1000, bias=0) 196608 bytes in ram, compression off
However, from time to time, this does not work and the texture never gets any data :
New buffer color_bits=24 red_bits=8 green_bits=8 blue_bits=8 1 Triggered 2 WAIT 2 NO RAM 3 NO RAM 4 NO RAM 5 NO RAM 6 NO RAM 7 NO RAM 8 NO RAM 9 NO RAM ...
I’m probably doing something wrong but so far it keeps eluding me
Here is the demo code used:
from direct.showbase.ShowBase import ShowBase
from direct.task.Task import pause
from panda3d.core import Shader, AsyncFuture, FrameBufferProperties, WindowProperties, GraphicsPipe, GraphicsOutput, Texture
from panda3d.core import CardMaker, Camera, NodePath, OrthographicLens
def shader():
return Shader.make(Shader.SL_GLSL,
vertex="""
#version 140
in vec4 p3d_Vertex;
uniform mat4 p3d_ModelViewProjectionMatrix;
void main()
{
gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;
}
""",
fragment="""
#version 140
out vec4 color;
void main()
{
color = vec4(gl_FragCoord.x / 256, gl_FragCoord.y / 256, 0.0, 1.0);
}
""")
base = ShowBase()
###############################################################################
fbprops = FrameBufferProperties()
fbprops.set_rgba_bits(8,8,8,0)
winprops = WindowProperties()
winprops.set_size(256, 256)
buffer_options = GraphicsPipe.BF_refuse_window
t1 = base.graphics_engine.make_output(base.win.get_pipe(), "t1", -1,
fbprops, winprops, buffer_options, base.win.get_gsg(), base.win)
print("New buffer", t1.get_fb_properties())
t1.disable_clears()
t1.set_sort(base.win.get_sort() - 100)
t1.set_active(False)
texture = Texture()
t1.add_render_texture(texture, GraphicsOutput.RTM_copy_ram, GraphicsOutput.RTP_color)
###############################################################################
dr = t1.make_display_region((0, 1, 0, 1))
dr.disable_clears()
dr.set_scissor_enabled(False)
###############################################################################
cm = CardMaker("plane")
cm.set_frame_fullscreen_quad()
root = NodePath(cm.generate())
root.set_depth_test(False)
root.set_depth_write(False)
root.set_shader(shader())
###############################################################################
cam = Camera("buffer-cam")
lens = OrthographicLens()
lens.set_film_size(2, 2)
lens.set_near_far(-1000, 1000)
cam.set_lens(lens)
camera = root.attach_new_node(cam)
dr.set_camera(camera)
###############################################################################
maker = CardMaker('card')
maker.setFrame(0, 1, 0, 1)
np = render.attachNewNode(maker.generate())
np.setPos(-0.5, 3, -0.5)
###############################################################################
t1_done = AsyncFuture()
async def trigger_t1():
t1.set_active(True)
t1.set_one_shot(True)
print(globalClock.get_frame_count(), "Triggered")
t1_done.set_result(t1)
async def apply_t1():
# Force wait next frame
await pause(0)
print(globalClock.get_frame_count(), "WAIT")
await t1_done
while True:
if texture.has_ram_image():
break
print(globalClock.get_frame_count(), "NO RAM")
await pause(0)
print(globalClock.get_frame_count(), "APPLY")
print(texture)
np.set_texture(texture, 1)
taskMgr.add(apply_t1())
taskMgr.add(trigger_t1())
base.run()