ゲーム制作 環境原猫 21日目

昨日に引き続き、本日もちょっとした作業としてウィンドウリサイズ時の処理を実装しました。

以下コードの赤字部分です。ウィンドウサイズに合わせてビューポートを変更しています。

for event in event_pump.poll_iter() {
    match event {
        Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
            break;
        },
        Event::Window { timestamp: _timestamp, window_id: _window_id, win_event: sdl2::event::WindowEvent::Resized (resized_w, resized_h) } => {
            //println!("リサイズ {} x {}", resized_w, resized_h);
            if resized_w as u32 != window_w || resized_h as u32 != window_h {
                window_w = resized_w as u32;
                window_h = resized_h as u32;
                unsafe {
                    gl::Viewport(0, 0, window_w as i32, window_h as i32);
                }
            }
        },
        _ => {}
    }
}

次の日

ゲーム制作 環境原猫 20日目

昨日はポイントスプライトの描画を行いました。

今日は60FPSを保つためのちょっとした調整を行いました。

具体的なコードは以下の通りで、イベント処理や描画処理を除いて、1フレームが1/60秒で完了するように調整してウェイトを入れています。

    let mut event_pump = sdl_context.event_pump().unwrap();
    let time_for_wait = 1_000_000_000u32 / 63;  // 60 で割ると60FPS出ないので3の余裕を持たせておく
    
    'running: loop {
        let start = Instant::now();

        for event in event_pump.poll_iter() {
            ~イベント処理~
        }
        unsafe {
            gl::Clear(gl::COLOR_BUFFER_BIT);
        }
        // draw
        shader_program.set_used();
        unsafe {
            gl::BindVertexArray(vao);
            gl::DrawArrays(
                gl::POINTS, // mode
                0,             // starting index in the enabled arrays
                3,             // number of indices to be rendered
            );
        }

        let end = start.elapsed();
        let time_nanos: u32 = end.as_nanos() as u32;
        //println!("{}ナノ秒経過しました。", time_nanos);
        if time_nanos < time_for_wait {
            //println!("{}ナノ秒待機しました。", time_for_wait - time_nanos);
            ::std::thread::sleep(::std::time::Duration::new(0, time_for_wait - time_nanos));
        }
        // swap window
        window.gl_swap_window();
    }
}

次の日

ゲーム制作 環境原猫 19日目

昨日はこのザマでしたが、今日は失敗した原因を特定して水分子画像をアルファ値を考慮して正しく描画出来ました。

(੭ ˃̣̣̥ ω˂̣̣̥)੭ु⁾⁾

コードは以下です。一部このページのライブラリを使っています。

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
extern crate sdl2;
extern crate gl;
extern crate image;

pub mod render_gl;

use std::path::Path;
use std::os::raw::c_void;

use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::video::GLProfile;

fn main() {
    let window_w: u32= 800;
    let window_h: u32= 600;

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();
    
    let gl_attr = video_subsystem.gl_attr();
    gl_attr.set_context_profile(GLProfile::Core);
    gl_attr.set_context_version(4, 5);

    let window = video_subsystem.window("環境原猫", window_w, window_h)
        .opengl()
        .resizable()    // .fullscreen_desktop()
        .build()
        .unwrap();


    let _ctx = window.gl_create_context().unwrap();
    gl::load_with(|name| video_subsystem.gl_get_proc_address(name) as *const _);
    
    debug_assert_eq!(gl_attr.context_profile(), GLProfile::Core);
    debug_assert_eq!(gl_attr.context_version(), (4, 5));

    // shader program
    use std::ffi::CString;
    let vert_shader = render_gl::Shader::from_vert_source(&CString::new(include_str!("triangle.vert")).unwrap()).unwrap();
    let frag_shader = render_gl::Shader::from_frag_source(&CString::new(include_str!("triangle.frag")).unwrap()).unwrap();
    let shader_program = render_gl::Program::from_shaders(&[vert_shader, frag_shader]).unwrap();

    // texture
    let img = image::open(&Path::new("resources/textures/drop.png")).expect("Failed to load texture");
    let format = match img {
        image::DynamicImage::ImageLuma8(_) => gl::RED,
        image::DynamicImage::ImageLumaA8(_) => gl::RG,
        image::DynamicImage::ImageRgb8(_) => gl::RGB,
        image::DynamicImage::ImageRgba8(_) => gl::RGBA,
        _ => panic!("unknown format.")
    };
    let mut texture = 0;
    unsafe {
        gl::GenTextures(1, &mut texture);
        gl::BindTexture(gl::TEXTURE_2D, texture);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
        let data = img.as_bytes();
        gl::TexImage2D(gl::TEXTURE_2D,
                       0,
                       format as i32,
                       img.width() as i32,
                       img.height() as i32,
                       0,
                       format,
                       gl::UNSIGNED_BYTE,
                       &data[0] as *const u8 as *const c_void);
        gl::GenerateMipmap(gl::TEXTURE_2D);
    }

    // vertex buffer object
    let vertices: Vec<f32> = vec![-0.5, -0.5, 0.0, 0.5, -0.5, 0.0, 0.0, 0.5, 0.0];
    let mut vbo: gl::types::GLuint = 0;
    unsafe {
        gl::GenBuffers(1, &mut vbo);
    }
    unsafe {
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(
            gl::ARRAY_BUFFER,                                                       
            (vertices.len() * std::mem::size_of::<f32>()) as gl::types::GLsizeiptr,
            vertices.as_ptr() as *const gl::types::GLvoid,
            gl::STATIC_DRAW,
        );
        gl::BindBuffer(gl::ARRAY_BUFFER, 0);
    }
    // vertex array object
    let mut vao: gl::types::GLuint = 0;
    unsafe {
        gl::GenVertexArrays(1, &mut vao);
    }
    unsafe {
        gl::BindVertexArray(vao);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::EnableVertexAttribArray(0); // layout (location = 0)
        gl::VertexAttribPointer(
            0,         // index
            3,         // number of components
            gl::FLOAT, // data type
            gl::FALSE, // normalized
            (3 * std::mem::size_of::<f32>()) as gl::types::GLint, // stride 
            std::ptr::null(),                                     // offset 
        );
        gl::BindBuffer(gl::ARRAY_BUFFER, 0);
        gl::BindVertexArray(0);
    }

    // set up
    unsafe {
        gl::Viewport(0, 0, window_w as i32, window_h as i32);
        gl::ClearColor(0.6, 0.0, 0.8, 1.0);
        gl::Enable(gl::VERTEX_PROGRAM_POINT_SIZE);
        gl::Enable(gl::BLEND);
        gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::ONE, gl::ONE);
    }

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        unsafe {
            gl::Clear(gl::COLOR_BUFFER_BIT);
        }
        // draw point sprites
        shader_program.set_used();
        unsafe {
            gl::BindVertexArray(vao);
            gl::DrawArrays(
                gl::POINTS, // mode
                0,             // starting index
                3,             // number of indices
            );
        }
        // swap window
        window.gl_swap_window();

        ::std::thread::sleep(::std::time::Duration::new(0, 1_000_000_000u32 / 60));
    }
}

次の日

ゲーム制作 環境原猫 17日目

今日は、14日目に作成した三角形のコードを変更して

を描画しました。

赤い箇所が変更/追加部分です。

gl::DrawArrays(
    gl::POINTS,    // mode
    0,             // starting index
    3,             // number of indices to be rendered
);
gl::Enable(gl::VERTEX_PROGRAM_POINT_SIZE);
#version 330 core
layout (location = 0) in vec3 Position;
void main()
{
    gl_Position = vec4(Position, 1.0);
    gl_PointSize = 30.0;
}

次回以降は、この点を

ポイントスプライト

に置き換えて、当初の目的である水分子を描画します。

次の日

ゲーム制作 環境原猫 16日目

昨日から、描画部分をOpenGLとDirectXのどちらにするか悩んでいました。

OpenGLとDirectXを比較すると、

・OpenGLはWindows, Mac, Linuxなど色んなOSに対応

・DirectXはWindowsのみ対応

・ゲームによるが、だいだいOpenGLはDirectXの7割~9割のパフォーマンス(OpenGLは影の描画が汚かったり画質が悪いことがある)

でした。

思ったより差が無かったです。パフォーマンスが倍くらい違えば間違いなくDirectXにしたんですが、困りました。ちなみにOpenGL後継のVulkanは思ったよりパフォーマンス上がってないですね。

WebGLでブラウザ経由によりいろんな環境に対応できそうなので、明日からは引き続きOpenGLで開発を継続したいと思います。

次の日

ゲーム制作 環境原猫 15日目

昨日まではOpenGLでの描画基礎処理を行ってきましたが、今日はこのままOpenGLで開発すべきか悩んでいました。

過去にWebGLベースで開発してWebアプリiOSアプリの両対応したことがあるのですが、iOSアプリについては「売れていない&アップデートされていない」という理由で

Appleにアプリストアからアプリを削除されてしまいました。

OpenGLで開発して将来的にはiOS対応の選択肢も残しておこうと思っていましたが、Windowsだけ対応すれば良いじゃないかという気になってきました。iOSではOpenGL非推奨で、Metalが推されてもいますしね。

そこで今日はこのページを見たりこの動画を見たりしていました。

次の日

ゲーム制作 環境原猫 14日目

今日は昨日までにチェックした情報を元に

三角形を1つ

描画しました。

一応Steamに出す予定なのでソース全体は載せません・・・

このページを見ればどんなソースかわかると思います。

あとフルスクリーンをやめて、サイズ変更可能なウィンドウ表示に変更しました。

    let window = video_subsystem.window(“環境原猫”, window_w, window_h)
        .opengl()
        .resizable()    // .fullscreen_desktop()
        .build()
        .unwrap();

次の日

ゲーム制作 環境原猫 13日目

今日は、昨日に引き続きこのブログこのページを読みました。

これでOpenGLで

三角形

を描くとこまで読み進みました。

どうも私は会社で普通に働いてるのでなかなか作業が進みません。

このアプリの月額課金の売り上げで生活出来るようになればゲーム制作に集中するのですが・・・

次の日

ゲーム制作 環境原猫 12日目

今日は、昨日に引き続きこのブログこのページを読みました。

あとはVSCodeに、言語サーバとして

rust-analyzer (公式のRust Language Serverは廃止になった)

と、ステップ実行するために

CodeLLDB

の拡張機能をインストールしました。

この2つの拡張機能で

Visual Studio使ってるときみたいに

開発できるようになりました。

(੭ ˃̣̣̥ ω˂̣̣̥)੭ु⁾⁾

これで明日からゲーム開発がバリバリ進む・・・筈です。

次の日