環境原猫 32~37日目

29日目でCPUにより水分子をグリグリ動かしましたが、今回はシェーダでTransform Feedbackを利用して動かすことが出来ました!

シェーダは以下のように変更しています。

layout (location = 0) in vec3 Position;
layout (location = 1) in vec2 Speed;
out vec3 feedbackPosition;
uniform float pointSize;

void main()
{
    gl_Position = vec4(Position, 1.0);
    float x = Position.x + Speed.x;
    float y = Position.y + Speed.y;
    if (1.0 < x) { x = -1.0; }
    if (x < -1.0) { x = 1.0; }
    if (1.0 < y) { y = -1.0; }
    if (y < -1.0) { y = 1.0; }
    feedbackPosition = vec3(x, y, 0.0);
    gl_PointSize = pointSize;
}
~略~
let c_string = CString::new("feedbackPosition").unwrap();
let c_string_ptr = &c_string.as_ptr();
gl::TransformFeedbackVaryings(program_id, 1, c_string_ptr, gl::SEPARATE_ATTRIBS);
gl::LinkProgram(program_id);
~略~

out vec3 feedbackPositionに、シェーダによる計算結果が格納されます。

位置情報をもう1つ作って、入力と出力用に分けました。

    let mut vertices: Vec<f32> = Vec::with_capacity(POINTS * 3);
    let mut vertices2: Vec<f32> = Vec::with_capacity(POINTS * 3);
    let mut vertices_speed: Vec<f32> = Vec::with_capacity(POINTS * 2);
    let mut rng = rand::thread_rng();
    for _i in 0..POINTS {
        vertices.push(rng.gen_range(-1.0..1.0));    // x
        vertices.push(rng.gen_range(-1.0..1.0));    // y
        vertices.push(0.0);                         // z
        vertices2.push(0.0);    // x
        vertices2.push(0.0);    // y
        vertices2.push(0.0);    // z
        vertices_speed.push(rng.gen_range(-0.01..0.01));    // speed x
        vertices_speed.push(rng.gen_range(-0.01..0.01));    // speed y
    }

描画時に、入力と出力を毎フレーム入れ替えるようにしました。出力結果が次の入力値になるようにし、その際の出力結果は次の入力に・・・と毎回入れ替えながら分子の位置を更新しています。

let mut b_turn: bool = false;

'running: loop {
    ~略~
    // draw points
    unsafe {
        if b_turn {
            gl::BindVertexArray(vao2);
            gl::BindBufferBase(gl::TRANSFORM_FEEDBACK_BUFFER, 0, vbo);
        } else {
            gl::BindVertexArray(vao);
            gl::BindBufferBase(gl::TRANSFORM_FEEDBACK_BUFFER, 0, vbo2);
        }
        // Transform Feedback 開始
        gl::BeginTransformFeedback(gl::POINTS);
        gl::DrawArrays(
            gl::POINTS,     // mode
            0,              // starting index in the enabled arrays
            POINTS as i32,  // number of indices to be rendered
        );
        // Transform Feedback 終了
        gl::EndTransformFeedback();
        // 後片付け
        gl::BindBuffer(gl::ARRAY_BUFFER, 0);
        gl::BindVertexArray(0);
    }
    // swap window
    window.gl_swap_window();
    }
    b_turn = !b_turn;
}

気になるベンチマークですが、
Transform Feedback未使用(CPUで計算)の場合、

1000万ポイント = 28FPS
1億ポイント = 3FPS

Transform Feedback 使用(シェーダで計算)の場合、

1000万ポイント = 60FPS
1億ポイント = 20FPS

となり、大幅な性能向上を果たしました。なんとこれ、分子を動かす前とFPS値がほぼ変わって無いです。Transform Feedbackにより、余って無駄になっていたGPUリソースを有効活用できました。

( ✌’ω’)✌

次の週

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です