Panda3Dtoy (simple, extensible shadertoy alternative)

I just saw a cool video introduction to shaders (well, fragment shaders) that mentioned shadertoy. Cool, but if you’re hanging out around here, you probably want to dive right into doing that stuff with Panda3D. So, here’s your panda3dtoy.py:

from direct.showbase.ShowBase import ShowBase

from panda3d.core import CardMaker
from panda3d.core import Shader
from panda3d.core import Vec2
from panda3d.core import WindowProperties


vertex_shader_source = """#version 430

uniform mat4 p3d_ModelViewProjectionMatrix;
in vec4 vertex;
in vec2 texcoord;
out vec2 uv;

void main() {
  gl_Position = p3d_ModelViewProjectionMatrix * vertex;
  uv = texcoord;
}
"""
fragment_shader_source = """#version 430

uniform float dt;
uniform float time;
uniform vec2 aspect;
in vec2 uv;
out vec4 fragColor;

void main() {
  float d = length((uv*2-1) * aspect);
  fragColor = vec4(sin(d*2*3.141592 * 10 + time * 20), 0, 0, 1);
}
"""


ShowBase()
base.accept('escape', base.task_mgr.stop)
base.disableMouse()


card_maker = CardMaker('card')
card_maker.set_frame(-1, 1, -1, 1)
card = base.render2d.attach_new_node(card_maker.generate())
shader = Shader.make(
    Shader.SL_GLSL,
    vertex=vertex_shader_source,
    fragment=fragment_shader_source,
)
card.set_shader(shader)


def update_shader_inputs(task):
    card.set_shader_input('dt', globalClock.dt)
    card.set_shader_input('time', task.time)
    top_right = base.a2dTopRight.get_pos()
    card.set_shader_input('aspect', Vec2(top_right.x, top_right.z))
    return task.cont


fullscreen = [False]
def toggle_fullscreen():
    fullscreen[0] = not fullscreen[0]
    wp = WindowProperties()
    wp.fullscreen = fullscreen[0]
    wp.cursor_hidden = fullscreen[0]
    base.win.requestProperties(wp)


base.task_mgr.add(update_shader_inputs)
base.accept('f', toggle_fullscreen)
base.run()

Press escape to exit, and f to toggle fullscreen mode.

3 Likes

You just have a mistake in logic.

  1. You create a list and set the first element to True. After all, your value in the global list is already False.

fullscreen = [False] → False
fullscreen[0] = not fullscreen[0] → True

  1. Next, you invert the value again.

wp.cursor_hidden = not fullscreen[0] → False

facepalm Thanks, fixed.
Also exchanged the deprecated gl_FragColor with out vec4 fragColor.

I think the way to store the flag in an additional list is redundant, since there is a WindowProperties class for this.

def toggle_fullscreen():
    fullscreen = base.win.getProperties().fullscreen
    wp = WindowProperties()
    wp.fullscreen = not fullscreen
    wp.cursor_hidden = not fullscreen
    base.win.requestProperties(wp)
1 Like