Trying to adapt GLSL shader to Panda3D

hey guys,

I’m trying to use this shader in P3D. I’ve made some minor modifications to use the proper panda3D inputs, but I end up just getting a single color the the whole frame. When I move the camera, the color changes. It almost feels like my shader is not properly taking the pixel position and instead outputing the same for all pixels.

I’m a total shader noob, so any help would be appreciated.

fisheye.vert

#version 120
varying vec4 Vertex_UV;
varying vec4 posDevSpace;
uniform mat4 p3d_ModelViewProjectionMatrix;
void main()
{
  gl_Position = p3d_ModelViewProjectionMatrix * gl_Vertex;
  Vertex_UV = gl_MultiTexCoord0;
  posDevSpace = gl_Position / gl_Position.z;
  posDevSpace = vec4(0.5, 0.5, 1.0, 1.0) + (posDevSpace + vec4(1.0, 1.0, 0.0, 0.0));
}

fisheye.frag

#version 120
uniform sampler2D p3d_Texture0;
varying vec4 Vertex_UV;
const float PI = 3.1415926535;

varying vec4 posDevSpace;
const float lensradius = 3.0;
const float signcurvature = 10.0;

#define EPSILON 0.000011

void main(void)
{
    float curvature = abs(signcurvature);
    float extent = lensradius;
    float optics = extent / log2(curvature * extent + 1.0) / 1.4427;
    vec4 PP = posDevSpace - vec4 (1.5, 1.5, 0.0, 1.0);
    float P0 = PP[0];
    float P1 = PP[1];
    float radius = sqrt(P0 * P0 + P1 * P1);

    float cosangle = P0 / radius;
    float sinangle = P1 / radius;

    float rad1, rad2, newradius;
    rad1 = (exp2((radius / optics) * 1.4427) - 1.0) / curvature;
    rad2 = optics * log2(1.0 + curvature * radius) / 1.4427;
    newradius = signcurvature > 0.0 ? rad1 : rad2;

    vec4 FE = vec4 (0.0, 0.0, 0.0, 1.0);
    FE[0] = newradius * cosangle + 0.5;
    FE[1] = newradius * sinangle + 0.5;
    FE = radius <= extent ? FE : posDevSpace;
    FE = curvature < EPSILON ? posDevSpace : FE;

    gl_FragColor = texture2D(p3d_Texture0, vec2(FE));
}

How are you applying it? Are you using FilterManager?

I am using FilterManager.

	def _apply_fisheye(self, camera):
		win = camera.display_region.getWindow()
		manager = FilterManager(win, camera.cam)
		tex = Texture()
		quad = manager.renderSceneInto(colortex=tex)
		myShader = Shader.load(
			Shader.SL_GLSL, vertex="fisheye.vert", fragment="fisheye.frag"
		)
		quad.setShader(myShader)
		quad.setShaderInput("tex", tex)

I believe that’s working correctly, as I’m able to use this other shader without issues modified as below

vertex

#version 120
varying vec4 p3d_Vertex;
uniform mat4 p3d_ModelViewProjectionMatrix;
void main()
{
  gl_Position = p3d_ModelViewProjectionMatrix * gl_Vertex;
  p3d_Vertex = gl_MultiTexCoord0;
}

fragment

uniform sampler2D p3d_Texture0;
varying vec4 p3d_Vertex;
const float PI = 3.1415926535;

void main()
{
  float aperture = 178.0;
  float apertureHalf = 0.5 * aperture * (PI / 180.0);
  float maxFactor = sin(apertureHalf);
  
  vec2 uv;
  vec2 xy = 2.0 * p3d_Vertex.xy - 1.0;
  float d = length(xy);
  if (d < (2.0-maxFactor))
  {
    d = length(xy * maxFactor);
    float z = sqrt(1.0 - d * d);
    float r = atan(d, z) / PI;
    float phi = atan(xy.y, xy.x);
    
    uv.x = r * cos(phi) + 0.5;
    uv.y = r * sin(phi) + 0.5;
  }
  else
  {
    uv = p3d_Vertex.xy;
  }
  vec4 c = texture2D(p3d_Texture0, uv);
  gl_FragColor = c;
}

You are passing in the texture via setShaderInput("tex") but accessing it as p3d_Texture0.

Instead, rename the variable in the shader from p3d_Texture0 to tex.

Also, don’t name your varying p3d_Vertex. That’s a built-in for a vertex input, not for a varying.

thanks for the advice @rdb. You’r correct. Note that on the shader I posted initially (the one I’m struggling with), I’m not incorrectly naming my variable as p3d_Texture0. In this case, I don’t think I even need the quad.setShaderInput("tex", tex) line?

Either way, the behaviour of the first shader seems the same, single color in the full frame :frowning:

Interestingly, I was able to get close to the desired results by plaing with this line, specifically, replacing the gl_Position.z with different numbers (looks like 1.5 or 2 do the trick…).

posDevSpace = gl_Position / gl_Position.z;

I think gl_Position.z refers to clipping plane?

You’re right, panda applies the texture by default to p3d_Texture0, so you don’t need the setShaderInput line then.

gl_Position.z is the depth, I believe. I am not sure what “dev space” is supposed to refer to. Note that the difference in your first and second shader is that in the second, you are actually using the coordinates from gl_MultiTexCoord0, whereas in the first shader, the Vertex_UV variable is written but never read.

I would first try to get a simple quad working that just displays the texture, without distortion. If that doesn’t work, I would try to set your shader to write out the texture coordinates that are being used to sample the texture to the red and blue channels of the output, then you can find out whether those might be the problem. It may indeed be that due to a difference in coordinate system (eg. expecting Y-up instead of Z-up), it is sampling the texture incorrectly.

1 Like