2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CPUによる描画ができるようにフレームワークを作った。

2
Last updated at Posted at 2026-02-15

経緯

  • 現状のゲームプログラムにおいて描画対象をGPUに投げるのがメインで、自前でレンダリング命令を構築するとかは行うことは少ない(=CPU側で描画を制御することは少なくなる)
  • ただ基礎知識は必要
  • 応用しやすい。例えば内部でテクスチャに描画だけを行って表示する等が可能。また、レイマーチングはGPU側で処理しているが、結局のところレンダラーを簡易的に作成している位置づけになる
  • GPUでシェーダによる制御を行う場合1ピクセル単位なのでできることに限度があるが、CPU側では手続き的に記述を書くことができるので、アルゴリズムを試行するテスト環境としても最適

作成したフレームワークについて

  • 特定のメモリ領域に色を置いて、それを自動的に描画領域として表示するプログラムを作成した
  • OpenGL等3DAPIは使わない想定
  • 大量に機能は追加せず、まずは枠組みを作ることにした
  • ピクセルが描画できれば方法はなんでもいいんだけど、実装について楽したいのでライブラリを利用する。今回はSFMLを使うことにした
  • メイン(ウィンドウ)スレッドと描画スレッドを分割した。どちらかの処理待ちによるボトルネックを軽減させる目的
  • ついでに低解像度で試したいのでスケーリングも想定して実装済み

ソースコード

main.cpp
#include <SFML/Graphics.hpp>
#include <thread>

unsigned int x = 0;
unsigned int y = 0;

//描画イメージ。低解像度の場合ここを変更してもいいかも。
sf::Image image({ 800, 600 }, sf::Color::Black);

void renderingThread(sf::RenderWindow* window)
{
    // ウィンドウのコンテキストを有効化する
    window->setActive(true);

    //描画した仮想領域の描画準備
    sf::Texture texture;

    //イメージをセットする
    texture.loadFromImage(image);

    //スプライト(2D描画)として描画する
    sf::Sprite sprite(texture);

    //仮想の描画領域の位置を指定(左上)
    sprite.setPosition({ 0,0 });

    //スケーリング(今回は8倍)
    sprite.setScale({ 8,8 });

    // レンダリングループ。メインとは別スレッドで動く
    while (window->isOpen())
    {
        // ウィンドウ側の描画をクリアする。SFML上でダブルバッファが有効化になっているため、これでOKになってる
        window->clear(sf::Color::Black);
        // イメージ(メモリ上の描画領域)のクリア。一面に黒色を塗る実装
        for (unsigned int i = 0; i < 200; i++) {
            for (unsigned int j = 0; j < 150; j++) {
                image.setPixel({ i, j }, sf::Color::Black);
            }
        }

        //================================================
        //以下、描画テスト。
        //本来だとここは別のソースコードに書く等できる
        //================================================

        //適当にピクセル描画のテスト
        sf::Color test(0, 25, 25, 255);
        image.setPixel({ 1, 2 }, test);

        //線分の描画(横)
        for (unsigned int i = 0; i < 70; i++) {
            int plus = i;
            image.setPixel({10+i, 10 }, sf::Color::Red);
        }

        //線分の描画(縦)
        for (unsigned int i = 0; i < 70; i++) {
            image.setPixel({ 10, 10+i }, sf::Color::Red);
        }

        //線分の描画(斜め)
        for (unsigned int i = 0; i < 70; i++) {
            int plus = i;
            image.setPixel({ 10 + i, 10+i }, sf::Color::Blue);
        }

        //メインスレッド上で更新した値を参照して描画する
        image.setPixel({ x, y }, sf::Color::Green);

        //================================================
        
        //描画領域を更新する
        texture.update(image);

        //描画反映
        window->draw(sprite);

        // end the current frame
        window->display();
    }
}

int main()
{
    // create the window (remember: it's safer to create it in the main thread due to OS limitations)
    sf::RenderWindow window(sf::VideoMode({ 800, 600 }), "CPU drawing test framework");

    // メインスレッドではウィンドウのコンテキストを無効にする
    window.setActive(false);

    // レンダリングスレッドを起動する(以降、メインスレッドとは関係なく動く)
    std::thread thread(&renderingThread, &window);

    // イベント処理用のループ
    while (window.isOpen())
    {
        //イベント受信はメインスレッド側で行う
        while (const std::optional event = window.pollEvent())
        {
            // クローズのリクエストが来たら、ウィンドウをクローズする
            if (event->is<sf::Event::Closed>())
                window.close();
        }
        
        //メインスレッド側で特定ピクセル更新
        x = rand() % 200;
        y = rand() % 150;

        //ウェイト命令を入れる
        sf::sleep(sf::milliseconds(100));
    }
    
    thread.join();
}

今後の予定

  • ブレゼンハムのアルゴリズムについて調べてみる
  • そもそも基本的な図形の描画ができないので実装してみる
  • 高速な描画はどうすれば実現できるのか調べてみる
  • 重ね合わせの描画順位について調べてみる
  • レイトレーシング実装してみる
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?