main.py:
from camera import Camera
from config import *
from model import *
class App:
def __init__(self):
pygame.init()
self.screen_width = 900
self.screen_height = 500
self.create_window()
self.shader = load_shader('default')
self.depth_shader = load_shader('depth')
self.camera = Camera(position = (0, 10, 0), fov = 90, aspect_ratio = pygame.display.get_surface().get_size()[0] / pygame.display.get_surface().get_size()[1], near = 0.1, far = 50)
self.vao = get_vao()
self.vbo = get_vbo()
self.instance_vbo = get_vbo()
self.basic_transformations = {'position': (0, 0, 0), 'rotation': (0, 0, 0), 'scale': (1, 1, 1)}
self.old_tick = 0
self.current_tick = 0
self.delta_time = 0
self.clock = pygame.time.Clock()
self.set_attribs()
self.init_objects()
self.set_instance_data()
def create_window(self):
pygame.display.set_mode((self.screen_width, self.screen_height), pygame.OPENGL | pygame.DOUBLEBUF | pygame.RESIZABLE)
pygame.display.set_caption('PyOpenGL 3D Engine')
glClearColor(0.15, 0.15, 0.15, 1)
def set_attribs(self):
glEnable(GL_DEPTH_TEST)
def init_objects(self):
self.cube = Cube('textures/cubes/white_cube.png', self.shader, self.vao, self.vbo, self.instance_vbo, self.camera)
random_color = random.choice(('red', 'blue', 'green', 'yellow'))
self.cube_2 = Cube(f'textures/cubes/{random_color}_cube.png', self.shader, self.vao, self.vbo, self.instance_vbo, self.camera)
self.lights = []
self.sun = Sun()
self.shadow_map = ShadowMap(1, self.sun, self.depth_shader)
glUniform1i(glGetUniformLocation(self.shader, 'ShadowMap'), self.shadow_map.unit)
def set_instance_data(self):
platform_size = (32, 32)
for x in range(-platform_size[0] // 2, platform_size[0] // 2):
for z in range(-platform_size[1] // 2, platform_size[1] // 2):
self.cube.instance_positions.append((x, 0, z))
self.cube_2.instance_positions.append((0, 2, 0))
def draw(self):
self.shadow_map.draw()
glUseProgram(self.shader)
self.shadow_map.use()
glUniformMatrix4fv(glGetUniformLocation(self.shader, 'lightSpaceMatrix'), 1, GL_FALSE, glm.value_ptr(self.shadow_map.lightSpaceMatrix))
glViewport(0, 0, self.screen_width, self.screen_height)
self.camera.aspect_ratio = self.screen_width / self.screen_height
self.camera.projection_matrix = self.camera.calculate_projection_matrix()
self.cube.draw(ShinyLevel = 0.0, transformations = self.basic_transformations, lights = self.lights, sun = self.sun)
self.cube_2.draw(ShinyLevel = 0.5, transformations = self.basic_transformations, lights = self.lights, sun = self.sun)
def game_loop(self):
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
self.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_F11:
pygame.display.toggle_fullscreen()
if event.type == pygame.VIDEORESIZE:
self.screen_width, self.screen_height = event.size
glViewport(0, 0, self.screen_width, self.screen_height)
self.camera.aspect_ratio = self.screen_width / self.screen_height
self.camera.projection_matrix = self.camera.calculate_projection_matrix()
pygame.event.set_grab(True)
pygame.mouse.set_visible(False)
self.camera.update()
glUseProgram(self.shader)
self.view = self.camera.get_view_matrix()
glUniformMatrix4fv(glGetUniformLocation(self.shader, 'view'), 1, GL_FALSE, glm.value_ptr(self.view))
self.projection = self.camera.get_projection_matrix()
glUniformMatrix4fv(glGetUniformLocation(self.shader, 'projection'), 1, GL_FALSE, glm.value_ptr(self.projection))
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
self.draw()
pygame.display.flip()
def run(self):
self.game_loop()
def quit(self):
self.shadow_map.destroy()
self.cube.destroy()
self.cube_2.destroy()
glDeleteProgram(self.shader)
pygame.quit()
exit()
if __name__ == '__main__':
app = App()
app.run()
model.py:
from config import *
class Base:
def __init__(self, texture_path, shader, vao, vbo, instance_vbo, camera):
self.shader = shader
self.vao = vao
self.vbo = vbo
self.instance_vbo = instance_vbo
self.camera = camera
if texture_path is not None:
self.texture = Texture(texture_path, 0)
else:
self.texture = None
self.render_mode = GL_TRIANGLES
glUseProgram(self.shader)
self.set_vertices()
self.set_data()
self.set_attribs()
def set_vertices(self):
self.vertices = ()
def set_data(self):
self.vertices = np.array(self.vertices, dtype=np.float32)
self.instance_positions = []
self.attribs_count = 8
try:
self.vertex_count = int(len(self.vertices) / self.attribs_count)
except ZeroDivisionError:
self.vertex_count = 0
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, self.vertices.nbytes, self.vertices, GL_STATIC_DRAW)
glUniform1i(glGetUniformLocation(self.shader, 'Image'), self.texture.unit)
def set_instance_data(self):
self.instance_positions = np.array(self.instance_positions, dtype=np.float32)
glBindBuffer(GL_ARRAY_BUFFER, self.instance_vbo)
glBufferData(GL_ARRAY_BUFFER, self.instance_positions.nbytes, self.instance_positions, GL_STATIC_DRAW)
glEnableVertexAttribArray(3)
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0))
glVertexAttribDivisor(3, 1)
def set_attribs(self):
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, self.attribs_count * 4, ctypes.c_void_p(0))
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, self.attribs_count * 4, ctypes.c_void_p(12))
glEnableVertexAttribArray(2)
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, self.attribs_count * 4, ctypes.c_void_p(20))
def get_model_matrix(self, position, rotation, scale):
model = glm.mat4(1.0)
model = glm.translate(model, glm.vec3(position))
model = glm.rotate(model, glm.radians(rotation[0]), glm.vec3(1, 0, 0))
model = glm.rotate(model, glm.radians(rotation[1]), glm.vec3(0, 1, 0))
model = glm.rotate(model, glm.radians(rotation[2]), glm.vec3(0, 0, 1))
model = glm.scale(model, glm.vec3(scale))
return model
def update(self):
pass
def draw(self, ShinyLevel, transformations, lights, sun):
glUseProgram(self.shader)
glBindVertexArray(self.vao)
self.set_instance_data()
self.update()
glUniform1f(glGetUniformLocation(self.shader, 'ShinyLevel'), ShinyLevel)
glUniform1i(glGetUniformLocation(self.shader, 'IsF1Clicked'), pygame.key.get_pressed()[pygame.K_F1])
lights_num = len(lights)
if self.texture is not None:
self.texture.use()
self.model = self.get_model_matrix(transformations['position'], transformations['rotation'], transformations['scale'])
glUniformMatrix4fv(glGetUniformLocation(self.shader, 'model'), 1, GL_FALSE, glm.value_ptr(self.model))
for i, light in enumerate(lights):
glUniform3fv(glGetUniformLocation(self.shader, f'lights[{i}].position'), 1, glm.value_ptr(light.position))
glUniform3fv(glGetUniformLocation(self.shader, f'lights[{i}].color'), 1, glm.value_ptr(light.color))
glUniform1f(glGetUniformLocation(self.shader, f'lights[{i}].strength'), light.strength)
glUniform3fv(glGetUniformLocation(self.shader, 'sun.position'), 1, glm.value_ptr(sun.position))
glUniform3fv(glGetUniformLocation(self.shader, 'sun.color'), 1, glm.value_ptr(sun.color))
glUniform3fv(glGetUniformLocation(self.shader, 'sun.direction'), 1, glm.value_ptr(sun.direction))
glUniform3fv(glGetUniformLocation(self.shader, 'viewPos'), 1, glm.value_ptr(self.camera.position))
glUniform1i(glGetUniformLocation(self.shader, 'numLights'), lights_num)
glDrawArraysInstanced(self.render_mode, 0, self.vertex_count, len(self.instance_positions))
def destroy(self):
self.texture.destroy()
glDeleteVertexArrays(1, [self.vao])
glDeleteBuffers(1, [self.vbo])
glDeleteBuffers(1, [self.instance_vbo])
class Cube(Base):
def __init__(self, texture_path, shader, vao, vbo, instance_vbo, camera):
super().__init__(texture_path, shader, vao, vbo, instance_vbo, camera)
def set_vertices(self):
self.vertices = (
# Front face
-0.5, -0.5, -0.5, 0, 0, 0, 0, -1,
0.5, -0.5, -0.5, 1, 0, 0, 0, -1,
0.5, 0.5, -0.5, 1, 1, 0, 0, -1,
-0.5, -0.5, -0.5, 0, 0, 0, 0, -1,
0.5, 0.5, -0.5, 1, 1, 0, 0, -1,
-0.5, 0.5, -0.5, 0, 1, 0, 0, -1,
# Back face
-0.5, -0.5, 0.5, 0, 0, 0, 0, 1,
0.5, -0.5, 0.5, 1, 0, 0, 0, 1,
0.5, 0.5, 0.5, 1, 1, 0, 0, 1,
-0.5, -0.5, 0.5, 0, 0, 0, 0, 1,
0.5, 0.5, 0.5, 1, 1, 0, 0, 1,
-0.5, 0.5, 0.5, 0, 1, 0, 0, 1,
# Left face
-0.5, -0.5, -0.5, 0, 0, -1, 0, 0,
-0.5, 0.5, -0.5, 1, 0, -1, 0, 0,
-0.5, 0.5, 0.5, 1, 1, -1, 0, 0,
-0.5, -0.5, -0.5, 0, 0, -1, 0, 0,
-0.5, 0.5, 0.5, 1, 1, -1, 0, 0,
-0.5, -0.5, 0.5, 0, 1, -1, 0, 0,
# Right face
0.5, -0.5, -0.5, 0, 0, 1, 0, 0,
0.5, 0.5, -0.5, 1, 0, 1, 0, 0,
0.5, 0.5, 0.5, 1, 1, 1, 0, 0,
0.5, -0.5, -0.5, 0, 0, 1, 0, 0,
0.5, 0.5, 0.5, 1, 1, 1, 0, 0,
0.5, -0.5, 0.5, 0, 1, 1, 0, 0,
# Top face
-0.5, 0.5, -0.5, 0, 0, 0, 1, 0,
0.5, 0.5, -0.5, 1, 0, 0, 1, 0,
0.5, 0.5, 0.5, 1, 1, 0, 1, 0,
-0.5, 0.5, -0.5, 0, 0, 0, 1, 0,
0.5, 0.5, 0.5, 1, 1, 0, 1, 0,
-0.5, 0.5, 0.5, 0, 1, 0, 1, 0,
# Bottom face
-0.5, -0.5, -0.5, 0, 0, 0, -1, 0,
0.5, -0.5, -0.5, 1, 0, 0, -1, 0,
0.5, -0.5, 0.5, 1, 1, 0, -1, 0,
-0.5, -0.5, -0.5, 0, 0, 0, -1, 0,
0.5, -0.5, 0.5, 1, 1, 0, -1, 0,
-0.5, -0.5, 0.5, 0, 1, 0, -1, 0,
)
class Light:
def __init__(self, position = (0, 5, 0), color = (1, 1, 1), strength = 1):
self.position = glm.vec3(position)
self.color = glm.vec3(color)
self.strength = strength
def update_position(self, position):
self.position = glm.vec3(position)
def update_color(self, color):
self.color = glm.vec3(color)
def update_strength(self, strength):
self.strength = strength
class Sun:
def __init__(self, color = (1, 1, 1), direction = (-1, -1.5, -1)):
self.position = glm.vec3((0, 0, 0))
self.color = glm.vec3(color)
self.direction = glm.vec3(direction)
def update_position(self, position):
self.position = glm.vec3(position)
def update_color(self, color):
self.color = glm.vec3(color)
def update_direction(self, direction):
self.direction = direction
camera.py:
from config import *
class Camera:
def __init__(self, position, fov, aspect_ratio, near, far):
self.position = glm.vec3(position)
self.up = glm.vec3(0, 1, 0)
self.forward = glm.vec3(0, 0, 1)
self.right = glm.vec3(1, 0, 0)
self.fov = glm.radians(fov / 2)
self.aspect_ratio = aspect_ratio
self.near = near
self.far = far
self.view_matrix = self.calculate_view_matrix()
self.projection_matrix = self.calculate_projection_matrix()
self.yaw = 90
self.pitch = 0
self.speed = 0.0025
self.sens = 2
def update_vectors(self):
self.forward.x = glm.cos(self.yaw) * glm.cos(self.pitch)
self.forward.y = glm.sin(self.pitch)
self.forward.z = glm.sin(self.yaw) * glm.cos(self.pitch)
self.forward = glm.normalize(self.forward)
self.right = glm.normalize(glm.cross(self.forward, self.up))
def update(self):
self.update_vectors()
self.player_movement()
self.mouse_movement()
self.view_matrix = self.calculate_view_matrix()
def calculate_view_matrix(self):
return glm.lookAt(self.position, self.position + self.forward, self.up)
def calculate_projection_matrix(self):
return glm.perspective(self.fov, self.aspect_ratio, self.near, self.far)
def get_view_matrix(self):
return self.view_matrix
def get_projection_matrix(self):
return self.projection_matrix
def player_movement(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LSHIFT]:
speed = self.speed * 1.5
else:
speed = self.speed
if keys[pygame.K_w]:
self.position += self.forward * speed
if keys[pygame.K_s]:
self.position -= self.forward * speed
if keys[pygame.K_a]:
self.position -= self.right * speed
if keys[pygame.K_d]:
self.position += self.right * speed
if keys[pygame.K_q]:
self.position += self.up * speed
if keys[pygame.K_e]:
self.position -= self.up * speed
def mouse_movement(self):
x, y = pygame.mouse.get_rel()
self.yaw += (x / 1000) * self.sens
self.pitch -= (y / 1000) * self.sens
config.py:
import pygame
import glm
import numpy as np
import ctypes
import glm
import random
from OpenGL.GL import *
from OpenGL.GL.shaders import compileShader, compileProgram
from sys import exit
def load_shader(shader_name):
with open(f'shaders/{shader_name}.vert') as f:
vertex_src = f.readlines()
with open(f'shaders/{shader_name}.frag') as f:
fragment_src = f.readlines()
shader = compileProgram(compileShader(vertex_src, GL_VERTEX_SHADER),
compileShader(fragment_src, GL_FRAGMENT_SHADER))
glUseProgram(shader)
return shader
def get_vao():
vao = glGenVertexArrays(1)
glBindVertexArray(vao)
return vao
def get_vbo():
vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
return vbo
def get_fbo():
fbo = glGenFramebuffers(1)
glBindFramebuffer(GL_FRAMEBUFFER, fbo)
return fbo
class Texture:
def __init__(self, path, unit):
self.unit = unit
texture = pygame.image.load(path).convert_alpha()
width, height = texture.get_rect().size
texture_data = pygame.image.tostring(texture, 'RGBA', True)
self.texture_id = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.texture_id)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data)
glGenerateMipmap(GL_TEXTURE_2D)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
def use(self):
exec(f'glActiveTexture(GL_TEXTURE{self.unit})')
glBindTexture(GL_TEXTURE_2D, self.texture_id)
def destroy(self):
glDeleteTextures(1, [self.texture_id,])
class ShadowMap:
def __init__(self, unit, light, depth_shader):
self.fbo = get_fbo()
self.unit = unit
self.resolution = (1024, 1024)
self.BaseLight = light
self.depth_shader = depth_shader
self.lightSpaceMatrix = glm.mat4(1.0)
self.border_color = glm.vec4(1.0)
self.depth_map = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.depth_map)
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, *self.resolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, None)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER)
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, glm.value_ptr(self.border_color))
glBindFramebuffer(GL_FRAMEBUFFER, self.fbo)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, self.depth_map, 0)
glDrawBuffer(GL_NONE)
glReadBuffer(GL_NONE)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
def draw(self):
glUseProgram(self.depth_shader)
glViewport(0, 0, *self.resolution)
glBindFramebuffer(GL_FRAMEBUFFER, self.fbo)
glClear(GL_DEPTH_BUFFER_BIT)
self.position = 10 * self.BaseLight.direction
self.center = glm.vec3(0.0, 0.0, 0.0)
self.up = glm.vec3(0.0, 0.0, 1.0)
self.projection = glm.ortho(-10, 10, -10, 10, 1.0, 20.0)
self.view = glm.lookAt(self.position, self.center, self.up)
self.lightSpaceMatrix = self.projection * self.view
glUniformMatrix4fv(glGetUniformLocation(self.depth_shader, 'lightSpaceMatrix'), 1, GL_FALSE, glm.value_ptr(self.lightSpaceMatrix))
glBindFramebuffer(GL_FRAMEBUFFER, 0)
def use(self):
exec(f'glActiveTexture(GL_TEXTURE{self.unit})')
glBindTexture(GL_TEXTURE_2D, self.depth_map)
def destroy(self):
glDeleteTextures(1, [self.depth_map,])
glDeleteFramebuffers(1, [self.fbo,])
class LoadOBJ:
def __init__(self, model):
self.model = model
self.vertices = []
def load(self):
...
default.vert:
#version 330 core
layout(location = 0) in vec3 vertexPos;
layout(location = 1) in vec2 vertexTexCoord;
layout(location = 2) in vec3 vertexNormal;
layout(location = 3) in vec3 instancePos;
out vec3 position;
out vec2 texcoord;
out vec3 normal;
out vec4 PositionLightSpace;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform mat4 lightSpaceMatrix;
void main()
{
vec4 worldPosition = model * vec4(vertexPos, 1.0) + vec4(instancePos, 0.0);
gl_Position = projection * view * worldPosition;
position = worldPosition.xyz;
texcoord = vertexTexCoord;
normal = normalize(mat3(model) * vertexNormal);
PositionLightSpace = lightSpaceMatrix * vec4(position, 1.0);
int renderMode = 0;
}
default.frag:
#version 330 core
in vec3 position;
in vec2 texcoord;
in vec3 normal;
in vec4 PositionLightSpace;
struct Light
{
vec3 position;
vec3 color;
vec3 strength;
};
struct DirectionalLight
{
vec3 color;
vec3 direction;
};
out vec4 FragColor;
vec3 calculatePointLight(Light light, vec3 Position, vec3 Normal);
vec3 calculateDirectionalLight(DirectionalLight Sun, vec3 Position, vec3 Normal);
float calculateShadow(vec4 PositionLightSpace);
#define MAX_LIGHTS 100
uniform Light lights[MAX_LIGHTS];
uniform DirectionalLight sun;
uniform int numLights;
uniform vec3 viewPos;
uniform sampler2D Image;
uniform sampler2D shadowMap;
uniform float ShinyLevel;
uniform bool IsF1Clicked;
void main()
{
vec3 temp = vec3(0.0);
vec3 lightDir = -sun.direction;
float shadow = calculateShadow(PositionLightSpace);
temp += (1.0 - shadow) * calculateDirectionalLight(sun, position, normal);
for(int i = 0; i < numLights; i++)
{
temp += calculatePointLight(lights[i], position, normal);
}
int renderMode = 0;
if (IsF1Clicked)
{
renderMode = 1;
}
if (renderMode == 0)
{
FragColor = vec4(temp, 1.0);
}
if (renderMode == 1)
{
FragColor = vec4(vec3(shadow), 1.0);
}
}
vec3 calculatePointLight(Light light, vec3 Position, vec3 Normal)
{
vec3 result = vec3(0.0);
vec3 baseTexture = texture(Image, texcoord).rgb;
vec3 lightDir = light.position - Position;
float distance = length(lightDir);
lightDir = normalize(lightDir);
vec3 viewDir = normalize(viewPos - Position);
vec3 reflectDir = reflect(-lightDir, Normal);
// ambient
result += 0.1 * baseTexture;
// diffuse
float diff = max(0.0, dot(Normal, lightDir));
result += light.color * light.strength * diff * baseTexture;
// specular
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
result += light.color * light.strength * spec;
return result;
}
vec3 calculateDirectionalLight(DirectionalLight Sun, vec3 Position, vec3 Normal)
{
vec3 result = vec3(0.0);
vec3 baseTexture = texture(Image, texcoord).rgb;
vec3 normal = normalize(Normal);
vec3 lightDir = normalize(-Sun.direction);
lightDir = normalize(lightDir);
vec3 viewDir = normalize(viewPos - Position);
vec3 reflectDir = reflect(-lightDir, normal);
// ambient
result += 0.2 * baseTexture;
// diffuse
float diffuse = max(0.0, dot(normal, lightDir));
result += Sun.color * diffuse * baseTexture;
// specular
float specular = pow(max(dot(viewDir, reflectDir), 0.0), 32);
result += ShinyLevel * Sun.color * specular * baseTexture;
return result;
}
float calculateShadow(vec4 fragPosLightSpace)
{
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
float d1 = texture(shadowMap, projCoords.xy).r;
float d2 = projCoords.z;
vec3 normal = normal;
vec3 lightDir = normalize(-10 * sun.direction - position);
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
float shadow = 0.0;
vec2 texelsize = 1.0 / textureSize(shadowMap, 0);
for (int x = -1; x <= 1; ++x)
{
for (int y = -1; y <= 1; ++y)
{
float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelsize).r;
shadow += d2 - bias > pcfDepth ? 1.0 : 0.0;
}
}
shadow /= 9.0;
if (projCoords.z > 1.0)
{
shadow = 0.0;
}
return shadow;
}
depth.vert
#version 330 core
layout(location = 0) in vec3 vertexPos;
uniform mat4 lightSpaceMatrix;
uniform mat4 model;
void main()
{
gl_Position = lightSpaceMatrix * model * vec4(vertexPos, 1.0);
}
depth.frag:
#version 330 core
void main()
{
gl_FragDepth = gl_FragCoord.z;
}
I tried to make shadows in pyopengl, but the shadow map renders non-existent shapes.The program does not return any error.What am I doing wrong? Can somebody help me?
non-existent shapes generated by shadow map, screenshot
New contributor
Franek B is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.