scripts i used to make this work
from this post from rdb Texture Buffers for hardware instanced geometry - #8 by rdb
wezu’s shadows made easy
import random
from panda3d.core import *
loadPrcFileData("init-ms-meter", """
show-frame-rate-meter true
frame-rate-meter-ms-text-pattern %0.2f ms
""")
from direct.showbase.ShowBase import ShowBase
from direct.actor.Actor import Actor
#vertex shader:
v_shader='''#version 330
struct p3d_LightSourceParameters {
vec4 color;
vec3 spotDirection;
sampler2DShadow shadowMap;
mat4 shadowViewMatrix; // Use shadowViewMatrix for view space
};
uniform p3d_LightSourceParameters my_light;
uniform mat4 p3d_ModelViewProjectionMatrix;
uniform mat3 p3d_NormalMatrix;
uniform mat4 p3d_ModelViewMatrix;
uniform bool isInstanced;
in vec4 p3d_Vertex;
in vec3 p3d_Normal;
in vec2 p3d_MultiTexCoord0;
in vec4 offset;
out vec2 uv;
out vec4 shadow_uv;
out vec3 normal;
out vec4 fragPos;
void main()
{
vec4 vertexPosition = p3d_Vertex;
if (isInstanced) {
vertexPosition += offset;
}
//position
gl_Position = p3d_ModelViewProjectionMatrix * vertexPosition;
//normal
normal = p3d_NormalMatrix * p3d_Normal;
//uv
uv = p3d_MultiTexCoord0;
//shadows
shadow_uv = my_light.shadowViewMatrix * (p3d_ModelViewMatrix * vertexPosition); // Use shadowViewMatrix
//frag position
fragPos = p3d_ModelViewMatrix * vertexPosition; // Add this line
}'''
#fragment shader
f_shader='''#version 330
struct p3d_LightSourceParameters {
vec4 color;
vec3 spotDirection;
sampler2DShadow shadowMap;
mat4 shadowViewMatrix; // Use shadowViewMatrix for view space
};
uniform p3d_LightSourceParameters my_light;
uniform sampler2D p3d_Texture0;
uniform vec3 camera_pos;
uniform float shadow_blur;
uniform vec4 ambientLightColor;
uniform vec4 fogColor;
uniform float fogStart;
uniform float fogEnd;
in vec2 uv;
in vec4 shadow_uv;
in vec3 normal;
in vec4 fragPos;
out vec4 color;
float textureProjSoft(sampler2DShadow tex, vec4 uv, float bias, float blur)
{
float result = textureProj(tex, uv, bias);
result += textureProj(tex, vec4(uv.xy + vec2( -0.326212, -0.405805)*blur, uv.z-bias, uv.w));
result += textureProj(tex, vec4(uv.xy + vec2(-0.840144, -0.073580)*blur, uv.z-bias, uv.w));
result += textureProj(tex, vec4(uv.xy + vec2(-0.695914, 0.457137)*blur, uv.z-bias, uv.w));
result += textureProj(tex, vec4(uv.xy + vec2(-0.203345, 0.620716)*blur, uv.z-bias, uv.w));
result += textureProj(tex, vec4(uv.xy + vec2(0.962340, -0.194983)*blur, uv.z-bias, uv.w));
result += textureProj(tex, vec4(uv.xy + vec2(0.473434, -0.480026)*blur, uv.z-bias, uv.w));
result += textureProj(tex, vec4(uv.xy + vec2(0.519456, 0.767022)*blur, uv.z-bias, uv.w));
result += textureProj(tex, vec4(uv.xy + vec2(0.185461, -0.893124)*blur, uv.z-bias, uv.w));
result += textureProj(tex, vec4(uv.xy + vec2(0.507431, 0.064425)*blur, uv.z-bias, uv.w));
result += textureProj(tex, vec4(uv.xy + vec2(0.896420, 0.412458)*blur, uv.z-bias, uv.w));
result += textureProj(tex, vec4(uv.xy + vec2(-0.321940, -0.932615)*blur, uv.z-bias, uv.w));
result += textureProj(tex, vec4(uv.xy + vec2(-0.791559, -0.597705)*blur, uv.z-bias, uv.w));
return result/13.0;
}
void main()
{
//base color
vec3 ambient = ambientLightColor.rgb; // Use the ambient light color from the uniform
//texture
vec4 tex = texture(p3d_Texture0, uv);
//light ..sort of, not important
vec3 light = my_light.color.rgb * max(dot(normalize(normal), -my_light.spotDirection), 0.0);
//shadows
//float shadow = textureProj(my_light.shadowMap, shadow_uv); //meh :|
float shadow = textureProjSoft(my_light.shadowMap, shadow_uv, 0.0001, shadow_blur); //yay! :)
//make the shadow brighter
shadow = 0.5 + shadow * 0.5;
//fog calculation
float fogFactor = clamp((fogEnd - length(fragPos.xyz)) / (fogEnd - fogStart), 0.0, 1.0);
vec4 foggedColor = mix(fogColor, vec4(tex.rgb * (light * shadow + ambient), tex.a), fogFactor);
color = foggedColor;
}'''
def setup_instancing(nodefunc, positionlist=[], seed=29, fromvalue=0, tovalue=250, new_location=(0, 0, 0), zlevel=True, total_instances=0, poswriter=None):
gnode = nodefunc.find("**/+GeomNode").node()
# Check if the "offset" column already exists
vdata = gnode.modifyGeom(0).modifyVertexData()
format = GeomVertexFormat(gnode.getGeom(0).getVertexData().getFormat())
if not format.hasColumn("offset"):
iformat = GeomVertexArrayFormat()
iformat.setDivisor(1)
iformat.addColumn("offset", 4, Geom.NT_stdfloat, Geom.C_other)
format.addArray(iformat)
format = GeomVertexFormat.registerFormat(format)
vdata.setFormat(format)
if zlevel == None:
sorted_positions = positionlist
else:
sorted_positions = sorted(positionlist, key=lambda pos: pos[2], reverse=zlevel)
if poswriter is None:
poswriter = GeomVertexWriter(vdata.modifyArray(2), 0)
for i in range(fromvalue, tovalue):
x, y, z = sorted_positions[i]
poswriter.add_data3(x + new_location[0], y + new_location[1], z + new_location[2])
total_instances += (tovalue - fromvalue)
nodefunc.setInstanceCount(total_instances)
nodefunc.node().setBounds(OmniBoundingVolume())
nodefunc.node().setFinal(True)
return total_instances, poswriter
base = ShowBase()
node = Actor('panda-model', {'walk' : 'panda-walk4'})
node.loop('walk')
node.setScale(0.01)
shadershadows = Shader.make(Shader.SL_GLSL,v_shader, f_shader)
node.setShader(shadershadows)
node.reparentTo(render)
def position_gen(value=1000, seed=29, area_width=486, area_height=486, height_map=None):
random.seed(seed)
occupied_positions = []
for i in range(value):
x = random.uniform(0, area_width)
y = random.uniform(0, area_height)
z = 0.01
pos = (int(x), int(y), z)
occupied_positions.append(pos)
return occupied_positions
positionlist = position_gen(1000, 12, 486, 486)
sun = Spotlight("Spot")
sun_path = render.attachNewNode(sun)
sun_path.node().set_shadow_caster(True, 512, 512)
sun_path.node().set_color((0.9, 0.9, 0.8, 1.0))
sun_path.node().showFrustum()
sun_path.node().get_lens().set_fov(20)
sun_path.node().get_lens().set_near_far(0.1, 400)
sun_path.setHpr(0,-90,0)
sun_path.setPos(0,0,90)
node.setShaderInput("isInstanced", True)
# Create a texture to store the shadow map
render.setShaderInput("ambientLightColor", (0.1, 0.1, 0.1, 1.0))
render.set_shader_input('my_light',sun_path)
render.set_shader_input('shadow_blur',0.5)
render.setShaderInput("fogColor", (0.5, 0.5, 0.5, 1.0)) # Set the fog color
render.setShaderInput("fogStart", 50.0) # Set the fog start distance
render.setShaderInput("fogEnd", 450.0) # Set the fog end distance
total_instances = 0
poswriter = None
total_instances, poswriter = setup_instancing(node, positionlist, seed=29, fromvalue=0, tovalue=250, new_location=(0,0,0), zlevel=None, total_instances=total_instances, poswriter=poswriter)
total_instances, poswriter = setup_instancing(node, positionlist, seed=29, fromvalue=250, tovalue=500, new_location=(486,486,0), zlevel=None, total_instances=total_instances, poswriter=poswriter)
# Adding more instances to the existing node
total_instances, poswriter = setup_instancing(node, positionlist, seed=29, fromvalue=500, tovalue=750, new_location=(0,0,900), zlevel=None, total_instances=total_instances, poswriter=poswriter)
base.trackball.node().set_pos(4.7, 112.7, -9.7)
base.trackball.node().set_hpr(61.5281, 12.0915, -18.2124)
base.run()