我正在用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)
任何帮助将不胜感激!谢谢!!!
1条答案
按热度按时间irlmq6kh1#
我想出了解决办法。我从来没有激活cubemap纹理。(仍然不工作,但显然试图使用sampler2D而不是cubemap将导致opengl默默失败)