Opengl纹理函数有时会中断着色器

lskq00tm  于 2023-04-05  发布在  其他
关注(0)|答案(1)|浏览(126)

我正在用OpenGl和Rust在一个小迷宫应用程序中实现点光源。我的一切都正常,直到我想要阴影。我生成一个空的立方体图,并将其附加到帧缓冲区,试图按照本教程Learn Opengl Point Shadow tutorail(代码在底部here
主要的片段着色器代码似乎是这个问题

#version 330 core
out vec4 FragColor;

struct Material {
    sampler2D diffuse;
    sampler2D specular;
    float shininess;
};

struct PointLight {
    vec3 position;

    float constant;
    float linear;
    float quadratic;

    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

in vec3 FragPos;
in vec3 Normal;
in vec2 TexCords;
in vec4 ourColor;

uniform vec3 viewPos;
uniform PointLight pointLight;
uniform Material material;
uniform float far_plane;
uniform samplerCube depthMap;

vec3 gridSamplingDisk[20] = vec3[](
   vec3(1, 1,  1), vec3( 1, -1,  1), vec3(-1, -1,  1), vec3(-1, 1,  1),
   vec3(1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
   vec3(1, 1,  0), vec3( 1, -1,  0), vec3(-1, -1,  0), vec3(-1, 1,  0),
   vec3(1, 0,  1), vec3(-1,  0,  1), vec3( 1,  0, -1), vec3(-1, 0, -1),
   vec3(0, 1,  1), vec3( 0, -1,  1), vec3( 0, -1, -1), vec3( 0, 1, -1)
);

vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
float ShadowCalculations(vec3 fragPos);

void main()
{
    // properties
    vec3 norm = normalize(Normal);
    vec3 viewDir = normalize(viewPos - FragPos);

    FragColor = vec4(CalcPointLight(pointLight, norm, FragPos, viewDir), 1.0);

}

// calculates the color when using a point light.
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
    vec3 lightDir = normalize(light.position - fragPos);
    // diffuse shading
    float diff = max(dot(normal, lightDir), 0.0);
    // specular shading
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    // attenuation
    float distance = length(light.position - fragPos);
    float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
    // combine results
    vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCords));
    vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCords));
    vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCords));
    ambient *= attenuation;
    diffuse *= attenuation;
    specular *= attenuation;

    float shadow = 0.0;
    // float shadow = ShadowCalculations(fragPos);
    return (ambient + (1.0 - shadow) * (diffuse + specular)) ;
}

float ShadowCalculations(vec3 fragPos){
    // get vector between fragment position and light position
    vec3 fragToLight = fragPos - pointLight.position;
    // use the fragment to light vector to sample from the depth map
    // float closestDepth = texture(depthMap, fragToLight).r;
    // it is currently in linear range between [0,1], let's re-transform it back to original depth value
    // closestDepth *= far_plane;
    // now get current linear depth as the length between the fragment and light position



    float currentDepth = length(fragToLight);



    // test for shadows
    // float bias = 0.05; // we use a much larger bias since depth is now in [near_plane, far_plane] range
    // float shadow = currentDepth -  bias > closestDepth ? 1.0 : 0.0;
    // PCF
    // float shadow = 0.0;
    // float bias = 0.05;
    // float samples = 4.0;
    // float offset = 0.1;
    // for(float x = -offset; x < offset; x += offset / (samples * 0.5))
    // {
        // for(float y = -offset; y < offset; y += offset / (samples * 0.5))
        // {
            // for(float z = -offset; z < offset; z += offset / (samples * 0.5))
            // {
                // float closestDepth = texture(depthMap, fragToLight + vec3(x, y, z)).r; // use lightdir to lookup cubemap
                // closestDepth *= far_plane;   // Undo mapping [0;1]
                // if(currentDepth - bias > closestDepth)
                    // shadow += 1.0;
            // }
        // }
    // }
    // shadow /= (samples * samples * samples);



    float shadow = 0.0;
    float bias = 0.15;
    int samples = 20;
    float viewDistance = length(viewPos - fragPos);
    float diskRadius = (1.0 + (viewDistance / far_plane)) / 25.0;
    for(int i = 0; i < samples; ++i)
    {
        // this is the bad line of code
        float closestDepth = texture(depthMap, fragToLight + gridSamplingDisk[i] * diskRadius).r;
        closestDepth *= far_plane;   // undo mapping [0;1]
        if(currentDepth - bias > closestDepth) {
            shadow += 1.0;
        }
    }
    shadow /= float(samples);

    // display closestDepth as debug (to visualize depth cubemap)
    // FragColor = vec4(vec3(closestDepth / far_plane), 1.0);

    return shadow;
}
// calculates the color when using a spot light.

但是由于某些原因,当我在深度贴图上运行纹理函数时,片段着色器停止运行,但是如果我不运行pointLight,阴影函数“工作”(至少在屏幕上渲染一些东西,我不知道它的准确性,但我稍后会处理)
举个例子

void main() {
   float r = texture(depthMap, vec3(1.0)).r; 
   FragColor = vec4(r,1.0);
}

这是可行的,但如果我在CalculatePointLight例程中运行它,opengl不会渲染任何东西。这两个都运行似乎有一些问题,因为它们中的任何一个单独都不会破坏着色器,但如果它们都在同一个程序中,它将无法正常工作
主要的生 rust 程序是

use std::{fs::read_to_string, path::Path};

use cgmath::{perspective, vec3, vec4, Deg, EuclideanSpace, Matrix4, Point3};
use glfw::{Action, Key};
use learn_opengl::{
    camera::{Camera, CameraDirection, CameraDirectionTrait},
    gls::{
        buffers::{
            bindable::Bindable,
            framebuffer::FrameBuffer,
            texture::{CubeMap, Texture2D},
            Attribute, VOs,
        },
        shader::{Shader, ShaderProgram},
    },
    lights::{material::Material, point_lights::PointLightBuilder},
    window::Window,
};

use maze::logic::{Maze, MazeEntry, MazeIndex};
const SCR_WIDTH: u32 = 1600;
const SCR_HEIGHT: u32 = 1200;

const VERTEX_SHADER_SOURCE: &'static str = include_str!("../../shader/vert.glsl");
const FRAGMENT_SHADER_SOURCE: &'static str = include_str!("../../shader/frag.glsl");

const VERTEX_SHADER_SOURCE_LAMP: &'static str = include_str!("../../shader/lamp_vert.glsl");
const FRAGMENT_SHADER_SOURCE_LAMP: &'static str = include_str!("../../shader/lamp_frag.glsl");

const VERTEX_SHADER_SOURCE_DEPTH: &'static str = include_str!("../../shader/depth_vs.glsl");
const FRAGMENT_SHADER_SOURCE_DEPTH: &'static str = include_str!("../../shader/depth_fs.glsl");
const GEOMETRY_SHADER_SOURCE_DEPTH: &'static str = include_str!("../../shader/depth_ge.glsl");

fn main() {
    let mut maze: Maze = read_to_string("./maze.txt")
        .expect("Failed to find file maze.txt")
        .parse()
        .expect("Error parsing maze");
    let mut window = Window::new(SCR_WIDTH, SCR_HEIGHT, "Learn Opengl", false, false).unwrap();
    let shader = ShaderProgram::new([
        Shader::new(VERTEX_SHADER_SOURCE, gl::VERTEX_SHADER).expect("Failed to Compile V Shader"),
        Shader::new(FRAGMENT_SHADER_SOURCE, gl::FRAGMENT_SHADER)
            .expect("Failed to Compile F Normal Shader"),
    ])
    .expect("Failed to Create Shader Program");
    let lamp_shader = ShaderProgram::new([
        Shader::new(VERTEX_SHADER_SOURCE_LAMP, gl::VERTEX_SHADER)
            .expect("Failed to Compile V Shader"),
        Shader::new(FRAGMENT_SHADER_SOURCE_LAMP, gl::FRAGMENT_SHADER)
            .expect("Failed to Compile F Lamp Shader"),
    ])
    .expect("Failed to Create Shader Program");

    let depth_shader = ShaderProgram::new([
        Shader::new(VERTEX_SHADER_SOURCE_DEPTH, gl::VERTEX_SHADER)
            .expect("Failed to Compile V Shader"),
        Shader::new(FRAGMENT_SHADER_SOURCE_DEPTH, gl::FRAGMENT_SHADER)
            .expect("Failed to Compile F Depth Shader"),
        Shader::new(GEOMETRY_SHADER_SOURCE_DEPTH, gl::GEOMETRY_SHADER)
            .expect("Failed to Compile G Shader"),
    ])
    .expect("Failed to Create Shader Program Depth");

    #[rustfmt::skip]
    let cube_verts: [f32; 288] = [
        // positions       // normals        // texture coords
        -0.5, -0.5, -0.5,  0.0,  0.0, -1.0,  0.0,  0.0,
         0.5, -0.5, -0.5,  0.0,  0.0, -1.0,  1.0,  0.0,
         0.5,  0.5, -0.5,  0.0,  0.0, -1.0,  1.0,  1.0,
         0.5,  0.5, -0.5,  0.0,  0.0, -1.0,  1.0,  1.0,
        -0.5,  0.5, -0.5,  0.0,  0.0, -1.0,  0.0,  1.0,
        -0.5, -0.5, -0.5,  0.0,  0.0, -1.0,  0.0,  0.0,

        -0.5, -0.5,  0.5,  0.0,  0.0,  1.0,  0.0,  0.0,
         0.5, -0.5,  0.5,  0.0,  0.0,  1.0,  1.0,  0.0,
         0.5,  0.5,  0.5,  0.0,  0.0,  1.0,  1.0,  1.0,
         0.5,  0.5,  0.5,  0.0,  0.0,  1.0,  1.0,  1.0,
        -0.5,  0.5,  0.5,  0.0,  0.0,  1.0,  0.0,  1.0,
        -0.5, -0.5,  0.5,  0.0,  0.0,  1.0,  0.0,  0.0,

        -0.5,  0.5,  0.5, -1.0,  0.0,  0.0,  1.0,  0.0,
        -0.5,  0.5, -0.5, -1.0,  0.0,  0.0,  1.0,  1.0,
        -0.5, -0.5, -0.5, -1.0,  0.0,  0.0,  0.0,  1.0,
        -0.5, -0.5, -0.5, -1.0,  0.0,  0.0,  0.0,  1.0,
        -0.5, -0.5,  0.5, -1.0,  0.0,  0.0,  0.0,  0.0,
        -0.5,  0.5,  0.5, -1.0,  0.0,  0.0,  1.0,  0.0,

         0.5,  0.5,  0.5,  1.0,  0.0,  0.0,  1.0,  0.0,
         0.5,  0.5, -0.5,  1.0,  0.0,  0.0,  1.0,  1.0,
         0.5, -0.5, -0.5,  1.0,  0.0,  0.0,  0.0,  1.0,
         0.5, -0.5, -0.5,  1.0,  0.0,  0.0,  0.0,  1.0,
         0.5, -0.5,  0.5,  1.0,  0.0,  0.0,  0.0,  0.0,
         0.5,  0.5,  0.5,  1.0,  0.0,  0.0,  1.0,  0.0,

        -0.5, -0.5, -0.5,  0.0, -1.0,  0.0,  0.0,  1.0,
         0.5, -0.5, -0.5,  0.0, -1.0,  0.0,  1.0,  1.0,
         0.5, -0.5,  0.5,  0.0, -1.0,  0.0,  1.0,  0.0,
         0.5, -0.5,  0.5,  0.0, -1.0,  0.0,  1.0,  0.0,
        -0.5, -0.5,  0.5,  0.0, -1.0,  0.0,  0.0,  0.0,
        -0.5, -0.5, -0.5,  0.0, -1.0,  0.0,  0.0,  1.0,

        -0.5,  0.5, -0.5,  0.0,  1.0,  0.0,  0.0,  1.0,
         0.5,  0.5, -0.5,  0.0,  1.0,  0.0,  1.0,  1.0,
         0.5,  0.5,  0.5,  0.0,  1.0,  0.0,  1.0,  0.0,
         0.5,  0.5,  0.5,  0.0,  1.0,  0.0,  1.0,  0.0,
        -0.5,  0.5,  0.5,  0.0,  1.0,  0.0,  0.0,  0.0,
        -0.5,  0.5, -0.5,  0.0,  1.0,  0.0,  0.0,  1.0
        ];
    let attributes = [
        Attribute {
            // cords
            location: 0,
            size: 3,
            normalized: false,
            stride: 8,
            offset: 0,
        },
        Attribute {
            // normal
            location: 1,
            size: 3,
            normalized: false,
            stride: 8,
            offset: 3,
        },
        Attribute {
            // texture
            location: 2,
            size: 2,
            normalized: false,
            stride: 8,
            offset: 6,
        },
    ];
    let vbo_vba =
        VOs::new(&cube_verts, &attributes, gl::TRIANGLES).expect("vbo or vba failed to bind");

    // textures
    let floor_textures = [
        Texture2D::new(
            image::open(&Path::new("./maze/resources/floor/albedo.jpg")).unwrap(),
            [gl::REPEAT, gl::REPEAT],
            [gl::LINEAR, gl::LINEAR],
            gl::RGB,
            None,
        )
        .unwrap(),
        Texture2D::new(
            image::open(&Path::new("./maze/resources/floor/specular.jpg")).unwrap(),
            [gl::REPEAT, gl::REPEAT],
            [gl::LINEAR, gl::LINEAR],
            gl::RGB,
            None,
        )
        .unwrap(),
    ];

    let floor_texture =
        learn_opengl::gls::buffers::texture::Textures::<2>::new(core::array::from_fn(|i| {
            &floor_textures[i]
        }))
        .unwrap();
    floor_texture.bind().unwrap();

    const SHADOW_WIDTH: i32 = 1024;
    const SHADOW_HEIGHT: i32 = 1024;

    let depth_map_fbo = FrameBuffer::new();

    let cube_map = CubeMap::new(SHADOW_WIDTH, SHADOW_HEIGHT, gl::DEPTH_COMPONENT)
        .expect("Couldn't make cube map");

    depth_map_fbo
        .attach_tex(&cube_map, gl::DEPTH_ATTACHMENT)
        .expect("failled attaching cubemap to depth buffer");

    depth_map_fbo.drr().unwrap();
    depth_map_fbo.unbind().unwrap();

    shader
        .set_uniform("material", Material::new(0, 1, 0.5))
        .expect("error with material");

    shader.set_uniform("depthMap", 1).unwrap();

    let point_light = PointLightBuilder::default()
        .pos(maze.get_player_loc() + vec3(0., 0., 0.))
        .build();

    shader
        .set_uniform("pointLight", &point_light)
        .expect("couldn't send point light uniform");

    let mut cam = Camera::new(
        Point3::from_vec(maze.get_player_loc()),
        90f32,
        0f32,
        vec3(2.5, 2.5, 2.5),
    );
    shader.set_uniform("viewPos", cam.get_pos()).unwrap();

    let mut projection: Matrix4<f32> =
        perspective(Deg(45.0), SCR_WIDTH as f32 / SCR_HEIGHT as f32, 0.1, 100.0);

    shader.set_uniform("projection", projection).unwrap();
    lamp_shader.set_uniform("projection", projection).unwrap();

    let near_plane = 1.0f32;
    let far_plane = 25.0f32;
    shader.set_uniform("far_plane", far_plane).unwrap();

    let shadow_proj = perspective(
        Deg(90.),
        SHADOW_WIDTH as f32 / SHADOW_HEIGHT as f32,
        near_plane,
        far_plane,
    );

    let shadow_transforms = vec![
        shadow_proj
            * Matrix4::look_at_rh(
                Point3::from_vec(point_light.get_pos()),
                Point3::from_vec(point_light.get_pos() + vec3(1., 0., 0.)),
                vec3(0., -1., 0.),
            ),
        shadow_proj
            * Matrix4::look_at_rh(
                Point3::from_vec(point_light.get_pos()),
                Point3::from_vec(point_light.get_pos() + vec3(-1., 0., 0.)),
                vec3(0., -1., 0.),
            ),
        shadow_proj
            * Matrix4::look_at_rh(
                Point3::from_vec(point_light.get_pos()),
                Point3::from_vec(point_light.get_pos() + vec3(0., 1., 0.)),
                vec3(0., 0., 1.),
            ),
        shadow_proj
            * Matrix4::look_at_rh(
                Point3::from_vec(point_light.get_pos()),
                Point3::from_vec(point_light.get_pos() + vec3(0., -1., 0.)),
                vec3(0., 0., -1.),
            ),
        shadow_proj
            * Matrix4::look_at_rh(
                Point3::from_vec(point_light.get_pos()),
                Point3::from_vec(point_light.get_pos() + vec3(0., 0., 1.)),
                vec3(0., -1., 0.),
            ),
        shadow_proj
            * Matrix4::look_at_rh(
                Point3::from_vec(point_light.get_pos()),
                Point3::from_vec(point_light.get_pos() + vec3(0., 0., -1.)),
                vec3(0., -1., 0.),
            ),
    ];
    depth_shader
        .set_uniform("shadowMatricies", shadow_transforms)
        .unwrap();
    depth_shader.set_uniform("far_plane", far_plane).unwrap();
    depth_shader
        .set_uniform("lightPos", point_light.get_pos())
        .unwrap();

    window.app_loop(|mut w| {
        // Pre Stuff
        process_events(&mut w, &mut cam, &mut projection);
        let dir = process_input(&mut w.window);
        if let Some(dir) = dir {
            if dir != 0 {
                let time = w.delta_time;
                let new_pos: MazeIndex = cam.try_translate_camera(dir, time).into();
                if maze[new_pos] != MazeEntry::Wall {
                    cam.translate_camera(dir, time);
                    shader.set_uniform("viewPos", cam.get_pos()).unwrap();
                    maze.move_player_to(new_pos);
                }
            }
        }
        let view = cam.get_view();
        // 1. render scene to depth cubemap
        //
        unsafe {
            gl::Viewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
            depth_map_fbo.bind().unwrap();
            gl::Clear(gl::DEPTH_BUFFER_BIT);
        }

        depth_shader.use_program();
        render(&vbo_vba, &depth_shader, &maze);
        depth_map_fbo.unbind().unwrap();
        //
        // // 2. render normally
        unsafe {
            gl::Viewport(0, 0, SCR_WIDTH as i32, SCR_HEIGHT as i32);
            gl::Clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);
        }
        shader.set_uniform("view", view.clone()).unwrap();
        cube_map.bind().unwrap();
        render(&vbo_vba, &shader, &maze);

        lamp_shader.use_program();
        lamp_shader.set_uniform("view", view).unwrap();
        lamp_shader
            .set_uniform(
                "model",
                Matrix4::from_translation(point_light.get_pos()) * Matrix4::from_scale(0.2),
            )
            .unwrap();
        vbo_vba.draw_arrays(0, 36).unwrap();
    });
}

fn render(vbo_vba: &VOs, shader: &ShaderProgram, maze: &Maze) {
    for (y, row) in maze.iter().enumerate() {
        for (x, entry) in row.iter().enumerate() {
            let model: Matrix4<f32> = match entry {
                maze::logic::MazeEntry::Wall => {
                    Matrix4::from_translation(vec3(x as f32, 1., y as f32))
                }
                _ => Matrix4::from_translation(vec3(x as f32, 0., y as f32)),
            };
            shader.set_uniform("model", model).unwrap();
            vbo_vba.draw_arrays(0, 36).unwrap();
        }
    }
}

fn process_events(w: &mut Window, cam: &mut Camera, proj: &mut Matrix4<f32>) -> bool {
    for (_, event) in glfw::flush_messages(&w.events) {
        match event {
            glfw::WindowEvent::FramebufferSize(width, height) => {
                // make sure the viewport matches the new window dimensions; note that width and
                // height will be significantly larger than specified on retina displays.
                w.width = width as u32;
                w.height = height as u32;
                *proj = perspective(Deg(45.0), SCR_WIDTH as f32 / SCR_HEIGHT as f32, 0.1, 100.0);
                unsafe {
                    gl::Viewport(0, 0, width, height);
                };
            }
            glfw::WindowEvent::CursorPos(x, y) => {
                cam.move_point_pos(x as f32, y as f32);
            }
            _ => {}
        };
    }
    return false;
}
fn process_input(window: &mut glfw::Window) -> Option<CameraDirection> {
    if window.get_key(Key::Escape) == Action::Press {
        window.set_should_close(true);
        return None;
    }
    let mut dirs = CameraDirection::new();

    if window.get_key(Key::W) == Action::Press {
        dirs.toggle_forward();
    }

    if window.get_key(Key::S) == Action::Press {
        dirs.toggle_backward();
    }

    if window.get_key(Key::D) == Action::Press {
        dirs.toggle_right();
    }

    if window.get_key(Key::A) == Action::Press {
        dirs.toggle_left();
    }

    // if window.get_key(Key::LeftShift) == Action::Press {
    //     dirs.toggle_down();
    // }
    //
    // if window.get_key(Key::Space) == Action::Press {
    //     dirs.toggle_up();
    // }
    return Some(dirs);
}

这里,有几个重要的附件,我只是链接的repo的情况下,他们是相关的(忽略平庸的API设计,这是我第一次玩opengl)
任何帮助将不胜感激!谢谢!!!

irlmq6kh

irlmq6kh1#

我想出了解决办法。我从来没有激活cubemap纹理。(仍然不工作,但显然试图使用sampler2D而不是cubemap将导致opengl默默失败)

相关问题