Gouraud Shading

Mickey·2022년 1월 27일
0

glium

목록 보기
8/14
post-thumbnail

https://github.com/glium/glium/blob/master/book/tuto-08-gouraud.md

이전 내용의 주전자 그림은 라이팅이 없어서 현실적으로 보이지 않음
라이팅 방법중 하나인 Gouraud Shading

The theory

빛의 방향이 물체의 표면에 수직이면 그 부분이 밝아야 한다는 내용
위 내용은 fragment shader에서 수행하는데, 각 픽셀의 밝기는 sin(angle(surface, light))로 계산됨
빛이 표면과 수직이면 밝기는 1, 빛이 표면과 평행하면 밝기는 0

빛과의 표면의 각도는 normal 정보로 계산
normal은 표면과 수직이므로 각 픽셀의 밝기 계산은 cos(angle(surface, light))로 계산됨

In practice

주된 계산은 fragment shader에서 이루어짐
normal data를 fragment shader로 전달하기 위해서는 glsl v150 이상으로 설정 해야함

vertex shader

#version 150      // updated

in vec3 position;
in vec3 normal;

out vec3 v_normal;      // new

uniform mat4 matrix;

void main() {
    v_normal = transpose(inverse(mat3(matrix))) * normal;       // new
    gl_Position = matrix * vec4(position, 1.0);
}

fragment shader

#version 140

in vec3 v_normal;
out vec4 color;
uniform vec3 u_light;

void main() {
    float brightness = dot(normalize(v_normal), normalize(u_light));
    vec3 dark_color = vec3(0.6, 0.0, 0.0);
    vec3 regular_color = vec3(1.0, 0.0, 0.0);
    color = vec4(mix(dark_color, regular_color, brightness), 1.0);
}

main.rs에 조명 코드 추가

// the direction of the light
let light = [-1.0, 0.4, 0.9f32];

target.draw((&positions, &normals), &indices, &program,
            &uniform! { matrix: matrix, u_light: light },
            &Default::default()).unwrap();

전체 코드

#[macro_use]
extern crate glium;

mod teapot;

fn main() {
    #[allow(unused_imports)]
    use glium::{glutin, Surface};

    let mut event_loop = glutin::event_loop::EventLoop::new();
    let wb = glutin::window::WindowBuilder::new();
    let cb = glutin::ContextBuilder::new();
    let display = glium::Display::new(wb, cb, &event_loop).unwrap();

    let positions = glium::VertexBuffer::new(&display, &teapot::VERTICES).unwrap();
    let normals = glium::VertexBuffer::new(&display, &teapot::NORMALS).unwrap();
    let indices = glium::IndexBuffer::new(
        &display,
        glium::index::PrimitiveType::TrianglesList,
        &teapot::INDICES,
    )
    .unwrap();

    let light = [-1.0, 0.4, 0.9f32];

    let vertex_shader_src = r#"
    #version 150      // updated

    in vec3 position;
    in vec3 normal;

    out vec3 v_normal;      // new

    uniform mat4 matrix;

    void main() {
        v_normal = transpose(inverse(mat3(matrix))) * normal;       // new
        gl_Position = matrix * vec4(position, 1.0);
    }
"#;

    let fragment_shader_src = r#"
    #version 140

    in vec3 v_normal;
    out vec4 color;
    uniform vec3 u_light;

    void main() {
        float brightness = dot(normalize(v_normal), normalize(u_light));
        vec3 dark_color = vec3(0.6, 0.0, 0.0);
        vec3 regular_color = vec3(1.0, 0.0, 0.0);
        color = vec4(mix(dark_color, regular_color, brightness), 1.0);
    }
"#;

    let program =
        glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None)
            .unwrap();

    let mut t: f32 = -0.5;
    event_loop.run(move |event, _, control_flow| {
        match event {
            glutin::event::Event::WindowEvent { event, .. } => match event {
                glutin::event::WindowEvent::CloseRequested => {
                    *control_flow = glutin::event_loop::ControlFlow::Exit;
                    return;
                }
                _ => return,
            },
            glutin::event::Event::NewEvents(cause) => match cause {
                glutin::event::StartCause::ResumeTimeReached { .. } => (),
                glutin::event::StartCause::Init => (),
                _ => return,
            },
            _ => return,
        }

        let next_frame_time =
            std::time::Instant::now() + std::time::Duration::from_nanos(16_666_667);
        *control_flow = glutin::event_loop::ControlFlow::WaitUntil(next_frame_time);

        t += 0.002;
        if t > 0.5 {
            t = -0.5;
        }

        let uniforms = uniform! {
            // matrix: [
            //     [ t.cos(), t.sin(), 0.0, 0.0],
            //     [-t.sin(), t.cos(), 0.0, 0.0],
            //     [0.0, 0.0, 1.0, 0.0],
            //     [0.0, 0.0, 0.0, 1.0f32],
            // ]
            matrix: [
                [0.01, 0.0, 0.0, 0.0],
                [0.0, 0.01, 0.0, 0.0],
                [0.0, 0.0, 0.01, 0.0],
                [0.0, 0.0, 0.0, 1.0f32]
            ],
            u_light: light
        };

        let mut target = display.draw();
        target.clear_color(0.3, 0.5, 0.7, 1.0);
        target
            .draw(
                (&positions, &normals),
                &indices,
                &program,
                &uniforms,
                &Default::default(),
            )
            .unwrap();
        target.finish().unwrap();
    });
}

profile
Mickey

0개의 댓글