
화면에 그릴 수 있는 파이프라인이 필요
gfx_defines! {
vertex Vertex {
pos: [f32; 2] = "a_Pos",
color: [f32; 3] = "a_Color",
}
pipeline pipe {
vbuf: gfx::VertexBuffer<Vertex> = (),
out: gfx::RenderTarget<ColorFormat> = "Target0",
}
}
그래픽 프로그래밍에서 모든 것은 삼각형으로 이루어지며 삼각형은 vertex에 의해 정의
vertex는 좌표 외에 추가 정보를 전달할 수 있으며, 우리는 2D 위치 a_Pos와 색상 a_Color 를 갖는 vertex를 정의
파이프라인에는 정점 버퍼와 렌더 대상만 있음
GPU는 vertex로 정확히 무엇을 하고 픽셀에 어떤 색상이 있어야 하는지 알지 못함
동작을 정의하기 위해 셰이더를 사용
셰이더는 3가지 종류가 있음
vertex shader
#version 150 core
in vec2 a_Pos;
in vec3 a_Color;
out vec4 v_Color;
void main() {
v_Color = vec4(a_Color, 1.0);
gl_Position = vec4(a_Pos, 0.0, 1.0);
}
OpenGL은 (x, y, z, w) 동차 좌표와 RGBA 색상을 사용
셰이더는 a_Pos 및 a_Color를 OpenGL 위치 및 색상으로 변환
fragment shader
#version 150 core
in vec4 v_Color;
out vec4 Target0;
void main() {
Target0 = v_Color;
}
fragment shader는 GPU에 의해 vertex v_Color 값에서 보간된 v_Color 값으로 픽셀 색상을 설정
vertex 설정
const WHITE: [f32; 3] = [1.0, 1.0, 1.0];
const SQUARE: [Vertex; 3] = [
Vertex { pos: [ 0.5, -0.5], color: WHITE },
Vertex { pos: [-0.5, -0.5], color: WHITE },
Vertex { pos: [-0.5, 0.5], color: WHITE },
];
그리기에 필요한 모든 것을 초기화
let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
let pso = factory.create_pipeline_simple(
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/rect_150.glslv")),
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/rect_150.glslf")),
pipe::new()
).unwrap();
let (vertex_buffer, slice) = factory.create_vertex_buffer_with_slice(&SQUARE, ());
let mut data = pipe::Data {
vbuf: vertex_buffer,
out: main_color.clone()
};
전체 코드
#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;
use gfx::traits::FactoryExt;
use gfx::Device;
use gfx_window_glutin as gfx_glutin;
pub type ColorFormat = gfx::format::Srgba8;
pub type DepthFormat = gfx::format::DepthStencil;
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
const WHITE: [f32; 3] = [1.0, 1.0, 1.0];
gfx_defines! {
vertex Vertex {
pos: [f32; 2] = "a_Pos",
color: [f32; 3] = "a_Color",
}
pipeline pipe {
vbuf: gfx::VertexBuffer<Vertex> = (),
out: gfx::RenderTarget<ColorFormat> = "Target0",
}
}
pub fn main() {
const SQUARE: [Vertex; 3] = [
Vertex { pos: [ 0.5, -0.5], color: WHITE },
Vertex { pos: [-0.5, -0.5], color: WHITE },
Vertex { pos: [-0.5, 0.5], color: WHITE },
];
let vertex_shader_src = r#"
#version 150 core
in vec2 a_Pos;
in vec3 a_Color;
out vec4 v_Color;
void main() {
v_Color = vec4(a_Color, 1.0);
gl_Position = vec4(a_Pos, 0.0, 1.0);
}
"#;
let fragment_shader_src = r#"
#version 150 core
in vec4 v_Color;
out vec4 Target0;
void main() {
Target0 = v_Color;
}
"#;
let events_loop = glutin::EventsLoop::new();
let builder = glutin::WindowBuilder::new()
.with_title("Square Toy".to_string())
.with_dimensions(800, 800)
.with_vsync();
let (window, mut device, mut factory, mut main_color, mut main_depth) =
gfx_glutin::init::<ColorFormat, DepthFormat>(builder, &events_loop);
let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
let pso = factory.create_pipeline_simple(
vertex_shader_src.as_bytes(),
fragment_shader_src.as_bytes(),
pipe::new()
).unwrap();
let (vertex_buffer, slice) = factory.create_vertex_buffer_with_slice(&SQUARE, ());
let mut data = pipe::Data {
vbuf: vertex_buffer,
out: main_color.clone()
};
let mut running = true;
while running {
events_loop.poll_events(
|glutin::Event::WindowEvent {
window_id: _,
event,
}| {
use glutin::WindowEvent::*;
match event {
KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape), _) | Closed => {
running = false
}
Resized(_, _) => {
gfx_glutin::update_views(&window, &mut main_color, &mut main_depth);
}
_ => (),
}
},
);
encoder.clear(&main_color, BLACK);
encoder.draw(&slice, &pso, &data);
encoder.flush(&mut device);
window.swap_buffers().unwrap();
device.cleanup();
}
}
