ATMWRIによるUE5の記録

Unreal Engine 5 を使い始めました

Code::Blocksをダークテーマにする(Ubuntu 20.04)

Code::Blocksを完全なダークテーマにすることは出来ないと思い込んでいたがそうでもなかった。

Code::Blocksだけをダークテーマにしたらこうなる
全部ダークにならないんだ・・・

環境

Ubuntu 20.04 LTS
Code::Blocks 20.03

手順

「codeblocks darktheme」などで検索していると大抵以下のような手順が紹介されている。指示に従うと冒頭のようにエディタ部分だけがダークになって余計目につらい。

  1. 解説動画やサイトでダークテーマ用の設定ファイルをダウンロードする
    defaultファイルを上書きすることになるので予め/home/[ユーザー名]/.config/codeblocks隠しフォルダ内にあるdefault.confを別名でコピーしておいた方がいいかもしれない。

  2. Code::Blocksを終了して以下のコマンドで設定プログラムを起動
    cb_share_config

  3. 左のソース側へダウンロードしてきたファイル、右側へdefault.confを指定する

    Code::Blocksの設定プログラムを起動

  4. チェックボックスを全て選択してTransfer>>をクリックして保存

    設定ファイルのチェックボックスをすべてチェックして保存する

  5. Code::Blocksを起動してdefaultテーマがダークに上書きされていることを確認
    この段階で冒頭のようになる

デスクトップ自体をダークテーマにする

Code::BlocksがGTKで動作している環境であればデスクトップ自体をダークテーマにすると残りの部分もしっかりダークになる。

デスクトップを暗くしたらダークテーマ完成

  • 設定->外観->ウィンドウの色 : 暗いに変更
    デスクトップで外観を設定する

ちなみにデスクトップの設定だけではCode::Blocksのエディタ部分以外がダークになる。

C++入門者がOpenGLでハマったポイント〜ModelLoading辺り

頂点配列は正しいはずなのにキューブが崩れて表示される

前のセクションのコードを元にして次のセクションに向かうと描画が崩れる事が発生。新しく追加したコードから順に確認していくと最後にたどり着くのが頂点データの生配列だった。チュートリアルによってはポジション以外に法線、テクスチャ座標などがあったりなかったりするのが原因。 Texcoordsを使用しないのに配列に残していた場合glVertexAttribPointerでセットした配列の解釈通りにいくとTexCoordsを想定した値が頂点座標として扱われ表示が崩れる。配列を変更しない場合はストライドを調整し3ではなく5*sizeof(float)にすれば良かったのかもしれない。

float vertices[] = {
        // position              Texcoords 
        -0.5f, -0.5f, -0.5f,    0.0f, 1.0f
         0.5f, -0.5f, -0.5f,     ...,  ...,
         0.5f,  0.5f, -0.5f,     ...,  ...,
         0.5f,  0.5f, -0.5f,     ...,  ...,

assimpで警告発生

assimpというライブラリを使用して3Dモデルをロードする。
aptでインストールして

sudo apt-get update
sudo apt-get install libassimp-dev

CMakeFileLists.txtでfind_package(assimp REQUIRED)を試したらこんなログがでた

[cmake] CMake Warning (dev) at /usr/lib/x86_64-linux-gnu/cmake/assimp-5.0/assimpTargets.cmake:54 (if):
[cmake]   if given arguments:
[cmake] 
[cmake]     "ON"
[cmake] 
[cmake]   An argument named "ON" appears in a conditional statement.  Policy CMP0012
[cmake]   is not set: if() recognizes numbers and boolean constants.  Run "cmake
[cmake]   --help-policy CMP0012" for policy details.  Use the cmake_policy command to
[cmake]   set the policy and suppress this warning.
[cmake] Call Stack (most recent call first):
[cmake]   /usr/lib/x86_64-linux-gnu/cmake/assimp-5.0/assimp-config.cmake:1 (include)
[cmake]   CMakeLists.txt:28 (find_package)
[cmake] This warning is for project developers.  Use -Wno-dev to suppress it.
[cmake] 

usr/lib内のcmakeディレクトリでassimp用の.cmakeが自動生成された模様。該当する部分はこんな感じ

# Create imported target assimp::assimp
if(ON)
  add_library(assimp::assimp SHARED IMPORTED)
else()
  add_library(assimp::assimp STATIC IMPORTED)
endif()

わからないのでWebを検索した。ubuntu20.04LTSでaptを使用してassimpをインストールした時に発生するらしい。どうにも出来ないのでスルーする。

discourse.choreonoid.org CMakeの警告に関する報告

複数のソースからstb_image.hをincludeできない

コメントにDo thisと書かれていたのでこれまで何も考えずに使用していたが、サンプルで複数のファイルにまたがってstb_image.hを使うケースに遭遇してハマった

// Do this:
//       #define STB_IMAGE_IMPLEMENTATION
//    before you include this file in *one* C or C++ file to create the implementation.

#define STB_IMAGE_STATICという手段もあるらしいけど、適当な関数を作って回避した。動くけどこれが正しいのかわからない。

// model.cpp 
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"

void set_flip_stbi(bool flag)
{
    stbi_set_flip_vertically_on_load(flag);
}

// main.cpp
set_flip_stbi(true);

またファイルのロードに失敗する

Makeで生成されるbuildディレクトリの実行ファイルを実行しているはずなのに。たまにロードに失敗する。原因はbuildディレクトリを削除して再生成したときに削除したbuildディレクトリに居るため../resource/xxx.objとか相対パスでたどり着けていない模様。

ここまでの感想

モデルをロードできると「おおっ」て何かを成し遂げた気分になるけど、まだ何もしていないという恐怖。

参考にしているWebサイト learnopengl.com

C++入門者がOpenGLでハマったポイント〜Hello Triangle辺り

開発環境を構築できたら後はチュートリアルサイトや動画の指示に従えば躓くことは無いはず。ただ理解不足で適当なことをやるとどこが悪いのかわからなくなってハマる。

1. 三角形が表示されなかった

VAOとVBOに対する理解不足でGLuint VAO, VBO;こう一括で宣言してやるのが気に入らずこんな書き方をしてしまった。VAOは頂点データでも入っているんだろうという認識だった。だったらVBOにはUV用のデータでもいれてやれと。

    // Create Vertex Array Object
    GLuint VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5* sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // Create Vertex Buffer Object -- TexCoords
    GLuint VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)(3*sizeof(float)));
    glEnableVertexAttribArray(1);

正しくはその時点でバインドされているVAOに対して生成したVBOに格納したデータを指すポインタglVertexAttribPointerを渡すのでこうなる。VAOは様々な頂点データ(座標・カラー・テクスチャ座標)に対する属性を取りまとめる役割があるようだ。

    // Create Vertex Array Object
    GLuint VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    // Create Vertex Buffer Object: Pos - TexCoords
    GLuint VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5* sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)(3*sizeof(float)));
    glEnableVertexAttribArray(1);

2. テクスチャが表示されなかった

頂点シェーダープログラムのタイプミス

TexCoordのタイプをvec3と無意識にやってしまっていた。VSCode拡張でShader languages support for VS Codeを入れるきっかけになる。がこの手のタイプミスは防げなさそう。

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;  // vec3にしていたら当然動かなかった

コピペミス

エラーは出ていないのにtexture1,2がビルド直後は表示されても次のlaunchでは表示されない imageloaderの不具合を疑ってfilepathを相対から絶対アドレスに変更したりしても徒労に終わった GDBを使おうと思ってCMakeLists.txtへtarget_compile_optionsを追加-Wall -g -O0でビルドすると警告してくれた

warning: ‘texture2’ may be used uninitialized in this function [-Wmaybe-uninitialized]

該当する箇所は2枚目のテクスチャを生成する手前

    GLuint texture2;
    glGenTextures(2, &texture1);    <-------------ここに警告
    glBindTexture(GL_TEXTURE_2D, texture2);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

見たまんまtexture2の参照用intを使用せずにtexture1を使ってしまっていた。ただのタイプミスというかコピペミス。

3. まとめ

入門用のコードなら-Wall付けなくてもいいかと面倒くさがっていた。というかCMakeListsでコンパイラオプションを設定するのを後回しにしていた。-Wallがついていれば一瞬で解決するミスを数日掛けて追いかけていた。悲しい。

C++入門者がOpenGLでハマったポイント〜環境構築(Ubuntu20.04 VSCode+GLFW+GLAD)

Webページや動画で紹介されているのはGLFWとGLADの組み合わせが多かったが初日にうまく構築出来なかったのでGLFW+GLEWの環境に逃げた。

1.GLFW + GLEWでもはまる

必要なパッケージはapt installで全部揃えることができた

sudo apt install libx11-dev
sudo apt install xorg-dev
sudo apt install libglu1-mesa libglu1-mesa-dev libgl1-mesa-glx libgl1-mesa-dev
sudo apt install libglfw3 libglfw3-dev
sudo apt install libglew-dev

makefile

makefileでglewを指定する際に小文字の-lglewでは/usr/bin/ld: -lglewがみつかりませんとエラーになった。ファイル名が大文字だったので試しに-GLEWにしたら通った

CXXFLAGS = -g -Wall -std=c++17
LDLIBS = -lGL -lglfw -lGLEW
OBJECTS = $(patsubst %.cpp,%.o,$(wildcard *.cpp))
TARGET = sample

.PHONY: clean

$(TARGET): $(OBJECTS)
    $(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@

clean:
    -$(RM) $(TARGET) $(OBJECTS) *~ .*~ core

2.GLADではまる

GLAD1とGLAD2の違いを知らなかった

参考にしている解説のヘッダーがglad/glad.hならGLAD1、glad/gl.hならGLAD2でダウンロードページが異なり更に初期化の記述も異なる。ヘッダーオンリーではうまく行かなかったので以下のオプションのものを使用した

Options:

  • ALIAS = False
  • DEBUG = False
  • HEADER_ONLY = False
  • LOADER = True
  • MX = False
  • ON_DEMAND = False

CMakeLists.txtでプロジェクトへの追加ができなかった

GLADのgithubページに書かれたCMakeLists.txtではpython定義した関数が使用されていて理解の範疇を超えていたのでダメ元でライブラリとしてコンパイルするだけの記述をしたが動いている。message(STATUS "${変数}"で地道に確認しながら作業を進めた。

gladがコンパイルされなかった

CMakeLists.txtの冒頭部分でproject(LearnOpenGL C CXX)とCを追加していなかったためコンパイルされなかった。気がつくのに時間がかかった。

GLAD2(glad/gl.h)の初期化方法

GLAD2のgithubページで解説されている

  • gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); これはGLAD1側の初期化法
  • int version = gladLoadGL(glfwGetProcAddress); こっちが正解

GLMが追加できなかった

チュートリアルが進むとGLMを使用してMatrixを扱うようになる。apt でインストールできるがCMakeLists.txtでglmでは認識されなかった。stackoverflowだったかがヒットしてglm::glmで使えるようになった。なぜそうなのか?はわからない。

ディレクトリ構成

LearnOpenGL
├── CMakeLists.txt               # main
├── glad
│   ├── CMakeLists.txt          # sub
│   ├── include
│   │   ├── KHR
│   │   │   └── khrplatform.h
│   │   └── glad
│   │       └── gl.h
│   └── src
│       └── gl.c
├── include
└── src
    └── main.cpp

mainのCMakeFileList.txt

cmake_minimum_required(VERSION 3.14)
project(LearnOpenGL C CXX)

set(PROJECT_VERSION 1.0.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED on)
set(CMAKE_CXX_EXTENSIONS off)

find_package(OpenGL REQUIRED)
find_package(glfw3 REQUIRED)
find_package(glm REQUIRED)

add_subdirectory(glad)

set(project_src
    src/main.cpp
    src/test.cpp
    src/shader.cpp
)

set(project_headers
    ${CMAKE_CURRENT_SOURCE_DIR}/include/shader.hpp
    ${CMAKE_CURRENT_SOURCE_DIR}/include/test.hpp
)

set(all_libs
    OpenGL
    glad
    glfw
    glm::glm
    X11
    Xrandr
    pthread
    Xi
    dl
)

add_executable(main ${project_src})
target_compile_options(main PUBLIC
    -Wall
)

target_include_directories(main PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/include/
)

target_link_libraries(main ${all_libs})
message(STATUS "CMAKE_DL_LIBS: ${CMAKE_DL_LIBS}")

sub側のCMakeLists.txt

file(GLOB SOURCES "src/*.c")
add_library(glad STATIC ${SOURCES})
target_include_directories(glad PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include )

message(STATUS "GLAD: SRCDIR - ${CMAKE_CURRENT_SOURCE_DIR}")
message(STATUS "GLAD: SOURCES - ${SOURCES}")

3.まとめ

誰かの教えに従えばつまづきようのない環境構築でおよそ3日は悩まされた。今の所GLEWとGLADの違いがわからない。無理にGLAD使う必要もないような気がする。

C++入門者がOpenGLを試した感想

動機

UE5の学習を開始して1年が経過し、そろそろ自由にゲームを作り始めようかと思い立ったがGame Ability SystemやGame Featuresなどの存在が気になり始めた。C++を勉強してそれらを使いこなせたら今後のゲーム開発に役立つかも?と思い始めたのがまず1つ目の動機。
2つ目の動機はメインマシンを置く部屋にエアコンが無い。この夏は特に暑く昼間は38度、夜になっても32度程度という生命の危機を感じるありさま。夏はエアコンのある部屋で省エネなノートPCでポチポチエディタをいじりたかった。
基本文法を終えた時点でUnreal C++へ挑戦しようとしたが一向に涼しくなる気配はなく興味がある分野ということでOpenGLの学習を選択した。

得られたもの

C++の基本へ入門してからOpenGLでカメラ(view)をマウスとキーボードでWSAD移動させるところまで(約一ヶ月)時点での収穫

  • MakefileやCMakeListを用いたプロジェクトの作成方法
  • 行列計算の基本の実践
  • ベクトル計算の実践
  • 結局ライブラリ頼みに気付く

現時点であまり収穫は無いが最後の結局ライブラリ頼みに気づいたのが大きい。

アンリアルクエスト4にオンライン参加した(中級編)

二日間にわたって開催されたアンリアルクエスト4、その期間内でなんとか中級クエストまでは完了できたのかな?と思っている。2番だけは勘違いして扉自身に弾を当てると開く仕組みを作ってしまったけど

やる気の出るイベントを開催してくださったHistoriaさんと、攻略法をDiscordで紹介してくださった方に感謝

中級クエス

  1. 踏んだらジャンプするジャンプパッドを作成せよ

  2. 的に弾を当てると扉が開く仕組みを作成せよ

  3. 秒数をUIで表示せよ

  4. ゲーム開始までのカウントダウンをUIで表示せよ

  5. ゴール演出を追加せよ

  6. スライディングを追加せよ

1.ジャンプパッド

プレイヤーの落下velocityを取得して適当な係数を乗算したものをLaunchCharacterへ渡した。

ジャンプパッドのBP編集前。見づらい

後日見直しがてらちょっと手を加えた  

  • 横に伸びたBPは見づらいのでSequence
  • velocityの計算にABSを使用
  • LaunchするのはBPインターフェースでPlayerBPに任せて、ジャンプパッドはLaunchするvelocityだけ渡す
    ジャンプパッドのBP編集後

2. 弾が当たると開く扉

Animation中に再度イベント発火したときの制御がうまくいかなかったのでDoOneceでフローを改善させた。

TimeLineを使用したドア開閉

3. 秒数をUIで表示せよ

UIとプレイヤーとコントローラーの関係をどうするか未だに整理しきれていない

  • GameModeがプレーヤーにタイマーUIを与える
  • タイマーUIとプレーヤーはインターフェースで通信
  • プレーヤーは一定の間隔でインターフェースで現在時間を送る

といった具合に落ち着いた

CountUp用のUI、BPインターフェースで表示を更新する

GameModeがタイマーUIをプレイヤーに与える
プレイヤーは一定の間隔でBPインターフェース越しにタイムを送信する

4.ゲーム開始までのカウントダウンをUIで表示せよ

ゲーム開始の合図はGameModeの仕事にした

GameModeのBeginPlayでゲームスタートカウントダウンを表示させる

スタートカウントダウン用のUIとアニメーション

5.ゴール演出を追加せよ

凝ったことをする時間も技術もないので、Niagaraサウンドで済ませた

  • Niagaraのエフェクトを作成
  • GoalBPにNiagaraコンポーネント追加、初期状態では無効にしておく
  • Playerがゴールに到達した時にイベント発生
  • PlayerのBPインターフェースにゴール処理を任せる

ゴール演出用NiagaraEffect

GoalBPの外観、AutoActivateはオフに

プレイヤーがゴールエリアに到達するとイベント発生

6.スライディング

検索したところABPからAnimationMontageを手軽に呼び出せるらしい

  • Animation SequenceからMontageの作成
  • ABPでMontage呼び出しと終了処理の設定(プレイヤーのEventDispacherにバインド)
  • プロジェクトセッティングでInputActionEvent追加してからプレイヤーBPで一連の処理を作成

アニメーションからmontageの作成、右クリから

ABPでmontageの設定、開始と終了を忘れずに

最初に思い付いたのがWalkSpeedを変化させる方法だった。後でDiscordで紹介されていた方法もためしてこんな感じになっている

プレイヤーBPでスライディング処理を作る
地面の摩擦なくしてLaunchする方法

感想

イベントの二日間で作業した時間よりも記録用にいろいろ整理する時間の方が長いような。
整理しているうちに気が付いた事

  • よく使うSet〇〇や演算ノード、Booleanノードの配置パターンを決めた方がよさげ
  • 横に伸ばすと見づらいのでSequenceで縦に伸ばす

アンリアルクエスト4にオンライン参加した(初級編)

先日開催されたアンリアルクエスト4「アンリアルエンジンを使って1日で作品を作ろう!」というイベントに参加した記録と感想

初級クエス

  1. 的を壊せ

    • 弾のBPにProjectileタグをつける
    • 的のBPでOn Component Hitイベントを使用、Actor has Tagで分岐
    • 弾が当たった時にはDestroyActor
  2. 的を動かせ
    SetActorLocationを使用してランダム指定したLocationにむけてEventTick毎にDirectionをNormalizeして変数MoveSpeedで移動する妙な方法しか思いつかなかった。後でInterpToMovementコンポーネントという便利な存在を知る

    • DetailからControl Pointsを複数設定可能
    • Behaiviour TypeをPingPongにする
  3. ゴールを作成せよ
    エディタ内のモデリングツールで外枠のリングと内側のエリアを作成した

    • 内側のメッシュのコリジョンOverlapAllDynamicにしてGenerateOverlapEventsをチェック
    • OnComponentBeginOverlapイベントでActorHasTagでPlayerを検出
    • Delay使ってGoalEvent発火
  4. 秒数が増える仕組みを作成せよ

    • EventTickDeltaSecondsを加算していく
  5. ステージを作成せよ
    エディタ内のモデリングツールを初めて使った。ワールド内に配置された既存のメッシュを選択して取り返しのつかない変更をしてしまう。メッシュに変な穴があいた

  6. 当たると死ぬ棘を作成せよ
    モデリングツールを使用して棘を作る。簡単そうだがメッシュが気のせいレベルで動いてまともに使えな・・・原因はマテリアルスロットになぜか入れてしまったvertex animationのあるAdvancedFlagだった

    • モデリングツールで作成したものをStatickMesh化、editorの最上部のActorメニューからConvert [xxx] to StaticMesh
    • OnComponentHitイベントでPlayerタグを検出してプレイヤーをcastして死亡イベントを発火させた。(インターフェースでやった方がいいのかな)
    • プレイヤーBPで死亡イベントはSetCollisionEnabledSetAllbodies SimulatePhysicsを使うといいらしい

感想

「これはこうやるんだよ」といった情報があれば1日でこなせる設定で、それらの情報を知らなかったら苦労するのを実感した。制限時間内に終わらせるには知らない事を一人考えこむより公式ドキュメント読んで検索するか他の人に聞いてどうにかするのが正解なんだろう。目の前の得体のしれないパラメータ総当たりして時間を浪費してしまう癖は直さないとなぁ