Я пытаюсь настроить конвейер для рендеринга лучей.
Сначала я установил вершинный и геометрический шейдеры, чтобы взять только 1 произвольное число с плавающей запятой, и сделал квад, чтобы я могиспользуйте только фрагментный шейдер и вводите данные, пропуская их через все шейдеры или униформы.
Но потом я наткнулся на вычислительный шейдер и нашел несколько учебных пособий, но все они делали почти одно и то же, делая квад и рендерингвывод на него шейдеров вычислений, я думаю, что это довольно глупо, если у вас есть возможность рендерить, как вы хотите, с помощью шейдера вычислений и все еще делать трюки, чтобы получить свой результат.
После некоторых дальнейших исследований я нашел функцию'glFramebufferImage2D' и, насколько я понял, он присоединяет ImageTexture (тот, который я написал с моим вычислительным шейдером в моем случае) к Framebuffer (буфер, который отображается, насколько я понял).Так что мне не нужно делать трюк, генерирующий квад.Но код, который я написал, просто показывает черный экран.Я что-то не так понял?или я что-то пропустил в своем коде?
Это мой код: (Я пока не беспокоюсь о предупреждениях и отключении шейдерных программ. Я просто хотел проверить концепцию сейчас.)
main.rs
extern crate sdl2;
extern crate gl;
use sdl2::pixels::Color;
use std::ffi::{CStr, CString};
fn main() {
let width = 512;
let height = 512;
let sdl = sdl2::init().unwrap();
let video_sys = sdl.video().unwrap();
let gl_attr = video_sys.gl_attr();
gl_attr.set_context_profile(sdl2::video::GLProfile::Core);
gl_attr.set_context_version(4, 1);
let window = video_sys.window("test", width, height).opengl().build().unwrap();
let gl_ctx = window.gl_create_context().unwrap();
let gl = gl::load_with(|s| video_sys.gl_get_proc_address(s) as *const std::os::raw::c_void);
unsafe {
gl::Viewport(0, 0, width as gl::types::GLsizei, height as gl::types::GLsizei);
gl::ClearColor(0.0, 0.0, 0.0, 1.0);
}
let shader = unsafe { gl::CreateShader(gl::COMPUTE_SHADER) };
unsafe {
gl::ShaderSource(shader, 1, &CString::new(include_str!("screen.comp")).unwrap().as_ptr(), std::ptr::null());
gl::CompileShader(shader);
}
let program = unsafe { gl::CreateProgram() };
unsafe {
gl::AttachShader(program, shader);
gl::LinkProgram(program);
gl::UseProgram(program);
}
let mut tex_out : gl::types::GLuint = 0;
unsafe {
gl::GenTextures(1, &mut tex_out);
gl::ActiveTexture(gl::TEXTURE0);
gl::BindTexture(gl::TEXTURE_2D, tex_out);
gl::TexImage2D(
gl::TEXTURE_2D,
0,
gl::RGBA32F as gl::types::GLint,
width as gl::types::GLsizei,
height as gl::types::GLsizei,
0,
gl::RGBA,
gl::FLOAT,
std::ptr::null()
);
gl::BindImageTexture(0, tex_out, 0, gl::FALSE, 0, gl::WRITE_ONLY, gl::RGBA32F);
}
let mut event_pump = sdl.event_pump().unwrap();
'main: loop {
for event in event_pump.poll_iter() {
match event {
sdl2::event::Event::Quit {..} => break 'main,
_ => {},
}
}
unsafe {
gl::DispatchCompute(width as gl::types::GLuint, height as gl::types::GLuint, 1);
gl::MemoryBarrier(gl::SHADER_IMAGE_ACCESS_BARRIER_BIT);
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, tex_out, 0);
}
window.gl_swap_window();
}
}
screen.comp
#version 430
layout(local_size_x = 1, local_size_y = 1) in;
layout(rgba32f, binding = 0) uniform image2D img_output;
void main() {
vec4 pixel = vec4(1.0, 1.0, 1.0, 1.0);
ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy);
imageStore(img_output, pixel_coords, pixel);
}
EDIT: рабочий код: (с некоторым цветовым тестом)
main.rs:
extern crate sdl2;
extern crate gl;
use std::ffi::{CStr, CString};
struct Renderer {
width : u32 ,
height : u32 ,
shader : gl::types::GLuint ,
program : gl::types::GLuint ,
}
impl Renderer {
fn new(width : u32, height : u32, shader_name : &CStr) -> Self {
unsafe {
gl::Viewport(0, 0, width as gl::types::GLsizei, height as gl::types::GLsizei);
gl::ClearColor(0.0, 0.0, 0.0, 1.0);
}
let shader = unsafe { gl::CreateShader(gl::COMPUTE_SHADER) };
unsafe {
gl::ShaderSource(shader, 1, &shader_name.as_ptr(), std::ptr::null());
gl::CompileShader(shader);
}
let program = unsafe { gl::CreateProgram() };
unsafe {
gl::AttachShader(program, shader);
gl::LinkProgram(program);
gl::UseProgram(program);
}
let mut tex_out : gl::types::GLuint = 0;
unsafe {
gl::GenTextures(1, &mut tex_out);
gl::ActiveTexture(gl::TEXTURE0);
gl::BindTexture(gl::TEXTURE_2D, tex_out);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as gl::types::GLint);
gl::TexImage2D(
gl::TEXTURE_2D,
0,
gl::RGBA32F as gl::types::GLint,
width as gl::types::GLsizei,
height as gl::types::GLsizei,
0,
gl::RGBA,
gl::FLOAT,
std::ptr::null()
);
gl::BindImageTexture(0, tex_out, 0, gl::FALSE, 0, gl::WRITE_ONLY, gl::RGBA32F);
}
let mut fbo : gl::types::GLuint = 0;
unsafe {
gl::GenFramebuffers(1, &mut fbo );
gl::BindFramebuffer(gl::FRAMEBUFFER, fbo );
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, tex_out, 0);
gl::BindFramebuffer(gl::READ_FRAMEBUFFER, fbo);
gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, 0);
}
let resolution = unsafe { gl::GetUniformLocation(program, CString::new("iResolution").unwrap().as_ptr()) };
unsafe { gl::Uniform2i(resolution, width as gl::types::GLint, height as gl::types::GLint); }
Self {
width : width ,
height : height ,
shader : shader ,
program : program ,
}
}
fn get_input(&self, name : &str) -> gl::types::GLint {
unsafe { gl::GetUniformLocation(self.program, CString::new(name).unwrap().as_ptr()) }
}
fn input1f(&self, ptr : gl::types::GLint, f : gl::types::GLfloat) {
unsafe { gl::Uniform1f(ptr, f) };
}
fn draw(&self) {
unsafe {
gl::DispatchCompute(self.width as gl::types::GLuint, self.height as gl::types::GLuint, 1);
gl::MemoryBarrier(gl::SHADER_IMAGE_ACCESS_BARRIER_BIT);
gl::BlitFramebuffer(0, 0, self.width as gl::types::GLint, self.height as gl::types::GLint, 0, 0, self.width as gl::types::GLint, self.height as gl::types::GLint, gl::COLOR_BUFFER_BIT, gl::LINEAR);
}
}
}
impl Drop for Renderer {
fn drop(&mut self) {
unsafe {
gl::DeleteShader(self.shader);
gl::DeleteProgram(self.program);
}
}
}
fn main() {
let width = 512;
let height = 512;
let sdl = sdl2::init().unwrap();
let video_sys = sdl.video().unwrap();
let gl_attr = video_sys.gl_attr();
gl_attr.set_context_profile(sdl2::video::GLProfile::Core);
gl_attr.set_context_version(4, 1);
let window = video_sys.window("test", width, height).opengl().build().unwrap();
let _gl_ctx = window.gl_create_context().unwrap();
let _gl = gl::load_with(|s| video_sys.gl_get_proc_address(s) as *const std::os::raw::c_void);
let render = Renderer::new(width, height, &CString::new(include_str!("screen.comp")).unwrap());
let time_attr = render.get_input("time");
let mut event_pump = sdl.event_pump().unwrap();
let mut time = 0.0;
'main: loop {
for event in event_pump.poll_iter() {
match event {
sdl2::event::Event::Quit {..} => break 'main,
_ => {},
}
}
time += 0.01;
if time > 1.0 {
time = 0.0;
}
render.input1f(time_attr, time);
render.draw();
window.gl_swap_window();
}
}
screen.comp:
#version 430
layout(local_size_x = 1, local_size_y = 1) in;
layout(rgba32f, binding = 0) uniform image2D img;
uniform ivec2 iResolution;
uniform float time;
void main() {
ivec2 iCoords = ivec2(gl_GlobalInvocationID.xy);
vec2 uv = vec2(iCoords) / vec2(iResolution);
vec4 pixel = vec4(uv, time, 1.0);
imageStore(img, iCoords, pixel);
}