Here is a short sample program to demonstrate the problem. The geom is 1000 points in a half circle around the camera. The camera frustum is configured to use an infinite far plane. When scaling up the geom, using key Z, around scale 80000000 the points starts flickering in and out of existence. However, in the vertex shader if one uncomment the line setting the gl_Position.z, there is not flickering at all even with far greater scaling factor.
from panda3d.core import *
from math import pi, cos, sin
load_prc_file_data("", """
gl-version 3 2
hardware-point-sprites #t
view-frustum-cull #f
""")
from direct.directbase import DirectStart
def shader():
return Shader.make(Shader.SL_GLSL,
vertex="""
#version 410
uniform mat4 p3d_ProjectionMatrix;
uniform mat4 p3d_ModelViewMatrix;
in vec4 p3d_Vertex;
in vec4 p3d_Color;
in float size;
out vec4 color;
void main() {
gl_Position = p3d_ProjectionMatrix * (p3d_ModelViewMatrix * p3d_Vertex);
//Uncomment this line to force the points to be on the infinite plane
//gl_Position.z = -gl_Position.w;
gl_PointSize = size;
color = p3d_Color;
}
""",
fragment="""
#version 410
in vec4 color;
out vec4 frag_color;
void main() {
frag_color = color;
}
""")
def make_geom(points, colors, size):
array = GeomVertexArrayFormat()
array.add_column(InternalName.make('vertex'), 3, Geom.NTFloat32, Geom.CPoint)
array.add_column(InternalName.make('color'), 4, Geom.NTFloat32, Geom.CColor)
array.add_column(InternalName.make('size'), 1, Geom.NTFloat32, Geom.COther)
format = GeomVertexFormat()
format.addArray(array)
format = GeomVertexFormat.registerFormat(format)
vdata = GeomVertexData('vdata', format, Geom.UH_static)
vwriter = GeomVertexWriter(vdata, 'vertex')
colorwriter = GeomVertexWriter(vdata, 'color')
sizewriter = GeomVertexWriter(vdata, 'size')
geompoints = GeomPoints(Geom.UH_static)
for index, (point, color) in enumerate(zip(points, colors)):
vwriter.add_data3(point)
colorwriter.add_data4(color)
sizewriter.add_data1(size)
geompoints.add_vertex(index)
geom = Geom(vdata)
geom.add_primitive(geompoints)
return geom
size = 1000
points = []
colors = []
for i in range(size):
theta = pi * i / size
x = cos(theta)
y = sin(theta)
z = 0
points.append(LPoint3(x, y, z))
colors.append(LColor(1, i / size, 0, 1))
geom = make_geom(points, colors, 2)
gnode = GeomNode('gnode')
gnode.add_geom(geom)
np = NodePath(gnode)
np.set_shader(shader())
attrib = np.getAttrib(ShaderAttrib)
attrib = attrib.setFlag(ShaderAttrib.F_shader_point_size, True)
np.setAttrib(attrib)
np.reparent_to(render)
scale = 1.0
def zoom():
global scale
scale *= 1.1
np.set_scale(scale)
print(f"ZOOM {scale}")
def unzoom():
global scale
scale /= 1.1
np.set_scale(scale)
print(f"ZOOM {scale}")
base.accept('z', zoom)
base.accept('z-repeat', zoom)
base.accept('shift-z', unzoom)
base.accept('shift-z-repeat', unzoom)
base.cam.set_pos(0, -1, 0)
base.camLens.set_near_far(1.0, float('inf'))
base.run()