python - 如何制作阴影贴图?

标签 python opengl glsl pyglet shadow-mapping

我试图了解阴影映射如何独立工作,并描述了这个 Python 程序来测试阴影映射,这是尽可能的。

enter image description here

我搜索了阴影贴图问题,但我还没有发现已经发生过这样的事情,那么我如何为灯光前的正常旋转立方体着色以及如何纠正阴影的位置所以它出现并准确地放置在表面上?我只是在修改着色器。

import pyglet, math, pyrr, ctypes
import numpy as np
from OpenGL.GL import *
from OpenGL.GL.shaders import *

app = pyglet.window.Window()

v = """
in layout(location=0) vec3 posicao;
uniform mat4 view;
uniform vec3 translate;
uniform float rot;
uniform float rot2;
uniform vec3 t2;
out vec3 outpos;
void main(){
    vec3 p = posicao;
    p = vec3(sin(rot)*p.x+cos(rot)*p.z,p.y,-sin(rot)*p.z+cos(rot)*p.x);
    p = translate+p+t2;
    p = vec3(p.x,sin(rot2)*p.z+cos(rot2)*p.y,-sin(rot2)*p.y+cos(rot2)*p.z);
    outpos = p;
    gl_Position = view*vec4(p,1);
}
"""

f = """
uniform vec3 cor;
uniform int modo;
uniform sampler2D shadow;
in vec3 outpos;
void main(){
    if(modo==0){
        float pi = 3.141592653589793;
        vec3 o = outpos+vec3(0,-5,0);
        o = vec3(o.x,sin(-30*pi/180)*o.z+cos(-30*pi/180)*o.y,-sin(-30*pi/180)*o.y+cos(-30*pi/180)*o.z);
        o.z+=0.05;
        float d = texture(shadow,vec2(.5)+o.xy/20).z;
        float i = 1;
        if(d<-o.z/20){
            i = 0.5;
        }
        gl_FragColor = vec4(vec3(cor),1)*i;
        //gl_FragColor = texture(shadow,outpos.xy);
    }else{
        gl_FragColor = vec4(vec3(-outpos.z/20),1);
    }
}
"""

shader = compileProgram(compileShader(v,GL_VERTEX_SHADER),compileShader(f,GL_FRAGMENT_SHADER))

glUseProgram(shader)

tudo = [-200,-4,200,
        200,-4,200,
        200,-4,-200,
        -200,-4,-200,
        -2,-2,2,
        -2,-2,-2,
        2,-2,-2,
        2,-2,2,
        2,2,2,
        2,2,-2,
        -2,2,-2,
        -2,2,2,
        -2,2,2,
        -2,2,-2,
        -2,-2,-2,
        -2,-2,2,
        2,-2,2,
        2,-2,-2,
        2,2,-2,
        2,2,2,
        -2,2,-2,
        2,2,-2,
        2,-2,-2,
        -2,-2,-2,
        -2,-2,2,
        2,-2,2,
        2,2,2,
        -2,2,2]

tudo = np.array(tudo, dtype=np.float32)

CUBO = glGenBuffers(1)

glBindBuffer(GL_ARRAY_BUFFER, CUBO)
glBufferData(GL_ARRAY_BUFFER, len(tudo)*4, tudo, GL_STREAM_DRAW)

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, ctypes.c_void_p(0))
glEnableVertexAttribArray(0)

view = pyrr.matrix44.create_perspective_projection_matrix(60, app.width/app.height, .1, 10000)
p = glGetUniformLocation(shader, "view")
glUniformMatrix4fv(p, 1, GL_FALSE, view)

glEnable(GL_DEPTH_TEST)

# Tentativa de Shadow Mapping

glEnable(GL_TEXTURE_2D)

tf = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, tf)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, app.width, app.height, 0, GL_RGB, GL_UNSIGNED_BYTE, None)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
f = glGenFramebuffers(1)
r = glGenRenderbuffers(1)
glBindFramebuffer(GL_FRAMEBUFFER, f)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tf, 0)
glBindRenderbuffer(GL_RENDERBUFFER, r)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, app.width, app.height)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, r)
glBindRenderbuffer(GL_RENDERBUFFER, 0)
glBindFramebuffer(GL_FRAMEBUFFER, 0)

pos = [0,-10,0]
comando = {"a":0,"w":0,"s":0,"d":0,"q":0,"e":0}
girar = -1

@app.event
def on_draw():
    global CUBO, shader, pos, comando, tudo, girar, f
    glBindFramebuffer(GL_FRAMEBUFFER, f)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    # Z-Buffer
    p = glGetUniformLocation(shader, "modo")
    glUniform1i(p, 1)
    p = glGetUniformLocation(shader, "rot2")
    glUniform1f(p, -30*math.pi/180)
    p = glGetUniformLocation(shader, "t2")
    glUniform3f(p, 0, -5, 0)
    # Movimento
    v = .04
    if comando["a"] == 1:
        pos[0]-=v
    if comando["d"] == 1:
        pos[0]+=v
    if comando["w"] == 1:
        pos[1]-=v
    if comando["s"] == 1:
        pos[1]+=v
    if comando["q"] == 1:
        pos[2]-=v
    if comando["e"] == 1:
        pos[2]+=v
    # fundo vermelho
    p = glGetUniformLocation(shader, "translate")
    glUniform3f(p, 0, 0, 0)
    p = glGetUniformLocation(shader, "rot")
    glUniform1f(p, 0)
    p = glGetUniformLocation(shader, "cor")
    glUniform3f(p, 1, 0, 0)
    glDrawArrays(GL_QUADS, 0, 4)
    # objeto no meio
    p = glGetUniformLocation(shader, "translate")
    glUniform3f(p, -1, -5, -10)
    p = glGetUniformLocation(shader, "rot")
    glUniform1f(p, 0)
    p = glGetUniformLocation(shader, "cor")
    glUniform3f(p, 0, 0, 1)
    glDrawArrays(GL_QUADS, 8, 4)
    # objeto azul
    p = glGetUniformLocation(shader, "translate")
    glUniform3f(p, pos[0], pos[2], pos[1])
    p = glGetUniformLocation(shader, "rot")
    girar+=.4
    glUniform1f(p, girar*math.pi/180)
    p = glGetUniformLocation(shader, "cor")
    glUniform3f(p, 0, 0, 1)
    glDrawArrays(GL_QUADS, 4, 8)
    p = glGetUniformLocation(shader, "cor")
    glUniform3f(p, 0, 1, 0)
    glDrawArrays(GL_QUADS, 12, 8)
    p = glGetUniformLocation(shader, "cor")
    glUniform3f(p, 1, 1, 0)
    glDrawArrays(GL_QUADS, 20, 8)
    # gravar o Framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, 0)
    # reset
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    # Z-Buffer tirando
    p = glGetUniformLocation(shader, "modo")
    glUniform1i(p, 0)
    p = glGetUniformLocation(shader, "rot2")
    glUniform1f(p, 0*math.pi/180)
    p = glGetUniformLocation(shader, "t2")
    glUniform3f(p, 0, 0, 0)
    # fundo vermelho
    p = glGetUniformLocation(shader, "translate")
    glUniform3f(p, 0, 0, 0)
    p = glGetUniformLocation(shader, "rot")
    glUniform1f(p, 0)
    p = glGetUniformLocation(shader, "cor")
    glUniform3f(p, 1, 0, 0)
    glDrawArrays(GL_QUADS, 0, 4)
    # objeto no meio
    p = glGetUniformLocation(shader, "translate")
    glUniform3f(p, -1, -5, -10)
    p = glGetUniformLocation(shader, "rot")
    glUniform1f(p, 0)
    p = glGetUniformLocation(shader, "cor")
    glUniform3f(p, 0, 0, 1)
    glDrawArrays(GL_QUADS, 8, 4)
    # objeto azul
    p = glGetUniformLocation(shader, "translate")
    glUniform3f(p, pos[0], pos[2], pos[1])
    p = glGetUniformLocation(shader, "rot")
    glUniform1f(p, girar*math.pi/180)
    p = glGetUniformLocation(shader, "cor")
    glUniform3f(p, 0, 0, 1)
    glDrawArrays(GL_QUADS, 4, 8)
    p = glGetUniformLocation(shader, "cor")
    glUniform3f(p, 0, 1, 0)
    glDrawArrays(GL_QUADS, 12, 8)
    p = glGetUniformLocation(shader, "cor")
    glUniform3f(p, 1, 1, 0)
    glDrawArrays(GL_QUADS, 20, 8)

@app.event
def on_key_press(k,m):
    global comando, grandeG
    if k == pyglet.window.key.A:
        comando["a"] = 1
    if k == pyglet.window.key.W:
        comando["w"] = 1
    if k == pyglet.window.key.S:
        comando["s"] = 1
    if k == pyglet.window.key.D:
        comando["d"] = 1
    if k == pyglet.window.key.Q:
        comando["q"] = 1
    if k == pyglet.window.key.E:
        comando["e"] = 1

@app.event
def on_key_release(k,m):
    global comando
    if k == pyglet.window.key.A:
        comando["a"] = 0
    if k == pyglet.window.key.W:
        comando["w"] = 0
    if k == pyglet.window.key.S:
        comando["s"] = 0
    if k == pyglet.window.key.D:
        comando["d"] = 0
    if k == pyglet.window.key.Q:
        comando["q"] = 0
    if k == pyglet.window.key.E:
        comando["e"] = 0

def SRO(dt):
    on_draw()

pyglet.clock.schedule(SRO)

pyglet.app.run()

最佳答案

此问题是由阴影深度缓冲区的有限精度引起的。由于每个片段只需要在阴影缓冲区中存储 1 个 channel ,因此我建议使用浮点内部纹理格式 GL_R16F(或 GL_R32F):

glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, app.width, app.height, 0, GL_RED, GL_UNSIGNED_BYTE, None)

注意(阴影)深度现在存储在红色 channel 中,因此您必须从红色 (x) channel 而不是蓝色 (z) 片段着色器中的 channel :

floaz d = texture(shadow,vec2(.5)+o.xy/20).z;

float d = texture(shadow,vec2(.5)+o.xy/20).x;

关于python - 如何制作阴影贴图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62801258/

相关文章:

iphone - GLSL ES 2.0(适用于 iPhone/iPod touch/iPad)中的 highp float 的精度是多少?

python - 直接对 celery 任务进行单元测试

c++ - 在 XCode 5 上编译 g++?

c++ - 如何从 "STL"格式转换为 "3DS"

c++ - 打破 GLSL 着色器指令限制的错误消息是什么?

c++ - 光不断覆盖旋转立方体的 2 个相同面

python - 如何标准化seaborn distplot?

python - pytesseract 不适用于一位数图像

python - 从输入文件中的引用文件中查找字符串的出现

c++ - 帧缓冲区大小发生变化但无法设置视口(viewport)