Drawing a triangle

Mickey·2022년 1월 29일

gfx-rs Tutorial

목록 보기
3/6
post-thumbnail

https://suhr.github.io/gsgt/

화면에 그릴 수 있는 파이프라인이 필요

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
  • geometry shader
  • fragment shader
    각 셰이더는 GPU에서 병렬로 실행

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();
    }
}

profile
Mickey

0개의 댓글