トップ | puarts.com
メモ  |  制作記  |  開発記  |  日常の記録  |  デジタルコンテンツ制作  |  ファイアーエムブレム  |  ゲーム  |  C/C++  |  C#  |  PC/ソフトウェア  |  Web 開発  |  スクリプト言語  |  その他プログラミング  |  
「C++」に関連する記事一覧

0  1  2  3  4  5  

C++ MSTest で浮動小数点数型の比較

2017/12/02 16:00

今まで C++ MSTest で float や double といった浮動小数点数型を比較するとき、私はわざわざ以下のように自前で比較関数を用意して書いていました。


TEST_CLASS(MyTest)
{
public:
    TEST_METHOD(Test0)
    {
        float value = ...;
        Assert::IsTrue(AreEquals(1.5f, value, 0.000001f));
    }

private:
    bool AreEquals(float lhs, float rhs, float eps)
    {
        return fabs(lhs - rhs) <= eps;
    }
};

ところが、よく見たら標準の Assert 関数にちゃんと誤差を加味した関数あるじゃないですか..


TEST_CLASS(MyTest)
{
public:
    TEST_METHOD(Test0)
    {
        float value = ...;
        Assert::AreEqual(1.5f, value, 0.000001f);
    }
};

そりゃないと面倒ですもんね..今更気が付くとは。最初にちゃんとドキュメント読めって話ですね。

fbxsdk でアニメーション関連の機能を使ったらリンクエラー

2017/11/26

昔作っていたモデル描画プログラムで fbx ファイルからアニメーション読み込み対応しようと、FBXSDK のアニメーション機能を使ってみたところ、以下のリンクエラーが発生しました。


error LNK2001: 外部シンボル ""public: static class fbxsdk::FbxClassId fbxsdk::FbxAnimStack::ClassId" (?ClassId@FbxAnimStack@fbxsdk@@2VFbxClassId@2@A)" は未解決です。
error LNK2001: 外部シンボル ""class fbxsdk::FbxDataType fbxsdk::FbxColor3DT" (?FbxColor3DT@fbxsdk@@3VFbxDataType@1@A)" は未解決です。
error LNK2001: 外部シンボル ""class fbxsdk::FbxDataType fbxsdk::FbxColor4DT" (?FbxColor4DT@fbxsdk@@3VFbxDataType@1@A)" は未解決です。
error LNK2001: 外部シンボル ""private: static void (__cdecl* fbxsdk::FbxAnimCurveKey::mDeallocatorFct)(class fbxsdk::FbxAnimCurveKey_Impl *)" (?mDeallocatorFct@FbxAnimCurveKey@fbxsdk@@0P6AXPEAVFbxAnimCurveKey_Impl@2@@ZEA)" は未解決です。
error LNK2001: 外部シンボル ""public: static class fbxsdk::FbxClassId fbxsdk::FbxAnimLayer::ClassId" (?ClassId@FbxAnimLayer@fbxsdk@@2VFbxClassId@2@A)" は未解決です。

これまで頂点データの読み込み等は問題なく行えていたので、なぜアニメーション関連の機能だけリンクエラーになるんだろうと思って、ネットで調べたところ、Autodesk のフォーラムで同じ問題にはまっている人がいました。

https://forums.autodesk.com/t5/fbx-forum/cannot-find-static-symbol/td-p/5816698

こちらのフォーラムにあるように私も libfbxsdk.lib をリンクしていたのですが、これではなく libfbxsdk-md.lib の方をリンクしたらビルドが通るようになりました。FBXSDK のライブラリディレクトリには fbxsdk.lib、fbxsdk-mt.lib、fbxsdk-md.lib の3つがありますが、mt と md は意味はわかるのですが、無印のは何用なんでしょうか。アニメーション機能を利用するまでは libfbxsdk.lib でもちゃんとビルド通るし、この lib の役割がよくわからないですね。

fread がファイル読み込み途中で失敗

2017/04/29
C++ 

C++ でファイル読み込み処理を書くときは昔作ったユーティリティ関数を使っていたため、fread を使って書くことが最近ありませんでした。久しぶりに fread でファイル読み込み処理を書いたら、なんかファイル読み取り途中で失敗してしまう(戻り値が途中までしか読み込めてない結果になってしまう)症状でややはまったので一応メモ。

すごく初歩的ですが、単純に引数のモードを rb にしていなかったのが原因。r にしていたため、ファイルの途中で EOF と誤判定されてしまっていただけでした。

プログラマーになって何年も経つのに未だにこういうミスはしてしまいます。

FBX SDK スキニングしているジョイントのローカル座標、変換行列取得

2017/04/16

FBX SDK を使って fbx からスキニングしているジョイントのローカル座標を取得する方法がヘルプ読まずにわからなかったので、メモ代わりにスキニングしているジョイントのローカル座標と変換行列をコンソール出力する関数を載せておきます。

ソースコード


void PrintLocalSrtAndTransformMatrixOfJoints(FbxNode* root_node)
{
    FbxMesh* mesh = root_node->GetMesh();
    int skin_count = mesh->GetDeformerCount(FbxDeformer::eSkin);
    for (int skin_index = 0; skin_index < skin_count; ++skin_index)
    {
        FbxSkin* skin = static_cast<FbxSkin*>(mesh->GetDeformer(skin_index, FbxDeformer::eSkin));
        int cluster_count = skin->GetClusterCount();
        for (int cluster_index = 0; cluster_index < cluster_count; ++cluster_index)
        {
            FbxCluster* cluster = skin->GetCluster(cluster_index);
            FbxNode* linked_node = cluster->GetLink();
            printf("%s:\n", linked_node->GetName());

            // ジョイントのローカル SRT を表示
            fbxsdk::FbxDouble3 local_translate = linked_node->LclTranslation.Get();
            fbxsdk::FbxDouble3 local_rotate = linked_node->LclRotation.Get();
            fbxsdk::FbxDouble3 local_scale = linked_node->LclScaling.Get();
            printf("    t = (%8.3f, %8.3f, %8.3f)\n    r = (%8.3f, %8.3f, %8.3f)\n    s = (%8.3f, %8.3f, %8.3f)\n",
                local_translate[0],
                local_translate[1],
                local_translate[2],
                local_rotate[0],
                local_rotate[1],
                local_rotate[2],
                local_scale[0],
                local_scale[1],
                local_scale[2]);

            // ジョイントの変換行列を表示
            fbxsdk::FbxAMatrix init_matrix;
            cluster->GetTransformLinkMatrix(init_matrix);
            printf("    matrix =\n");
            for (int row = 0; row < 4; ++row)
            {
                printf("        ");
                for (int col = 0; col < 4; ++col)
                {
                    printf("%8.3f, ", init_matrix.Get(row, col));
                }
                printf("\n");
            }
        }
    }
}

コンソール出力結果例

joint1:
    t = (   0.000,    0.000,    0.000)
    r = (   0.000,    0.000,    0.000)
    s = (   1.000,    1.000,    1.000)
    matrix =
           1.000,    0.000,    0.000,    0.000,
          -0.000,    1.000,    0.000,    0.000,
           0.000,   -0.000,    1.000,    0.000,
           0.000,    0.000,    0.000,    1.000,
joint2:
    t = (   0.000,    1.000,    0.000)
    r = (   0.000,    0.000,    0.000)
    s = (   1.000,    1.000,    1.000)
    matrix =
           1.000,    0.000,    0.000,    0.000,
          -0.000,    1.000,    0.000,    0.000,
           0.000,   -0.000,    1.000,    0.000,
           0.000,    1.000,    0.000,    1.000,
joint3:
    t = (   0.000,    1.000,   -0.000)
    r = (   0.000,    0.000,    0.000)
    s = (   1.000,    1.000,    1.000)
    matrix =
           1.000,    0.000,    0.000,    0.000,
          -0.000,    1.000,    0.000,    0.000,
           0.000,   -0.000,    1.000,    0.000,
           0.000,    2.000,   -0.000,    1.000,
joint4:
    t = (   1.000,    1.000,   -0.000)
    r = (   0.000,    0.000,    0.000)
    s = (   1.000,    1.000,    1.000)
    matrix =
           1.000,    0.000,    0.000,    0.000,
          -0.000,    1.000,    0.000,    0.000,
           0.000,   -0.000,    1.000,    0.000,
           1.000,    3.000,   -0.000,    1.000,

ついでにサンプルにあったバインドポーズのトンラスフォームの取得方法もメモ代わりに載せておきます。

バインドポーズのトランスフォームと行列(サンプルより)


void DisplayPose(FbxScene* pScene)
{
    int      i, j, k, lPoseCount;
    FbxString  lName;

    lPoseCount = pScene->GetPoseCount();

    for (i = 0; i < lPoseCount; i++)
    {
        FbxPose* lPose = pScene->GetPose(i);

        lName = lPose->GetName();
        printf("Pose Name: %s\n", lName.Buffer());

        printf("    Is a bind pose: %s\n", lPose->IsBindPose()?"true":"false");

        printf("    Number of items in the pose: %d\n", lPose->GetCount());

        printf("\n");

        for (j = 0; j<lPose->GetCount(); j++)
        {
            lName = lPose->GetNodeName(j).GetCurrentName();
            printf("    Item name: %s\n", lName.Buffer());

            if (!lPose->IsBindPose())
            {
                // Rest pose can have local matrix
                printf("    Is local space matrix: %s\n", lPose->IsLocalMatrix(j)?"true":"false");
            }

            printf("    Matrix value: \n");

            FbxString lMatrixValue;

            FbxNode* node = lPose->GetNode(j);

            for (k = 0; k<4; k++)
            {
                FbxMatrix  lMatrix = lPose->GetMatrix(j);
                FbxVector4 lRow = lMatrix.GetRow(k);
                char        lRowValue[1024];

                FBXSDK_sprintf(lRowValue, 1024, "%9.4f %9.4f %9.4f %9.4f\n", lRow[0], lRow[1], lRow[2], lRow[3]);
                lMatrixValue += FbxString("        ") + FbxString(lRowValue);
            }

            printf("%s\n", lMatrixValue.Buffer());
        }
    }

    lPoseCount = pScene->GetCharacterPoseCount();

    for (i = 0; i < lPoseCount; i++)
    {
        FbxCharacterPose* lPose = pScene->GetCharacterPose(i);
        FbxCharacter*     lCharacter = lPose->GetCharacter();

        if (!lCharacter) break;

        printf("Character Pose Name: %s\n", lCharacter->GetName());

        FbxCharacterLink lCharacterLink;
        FbxCharacter::ENodeId  lNodeId = FbxCharacter::eHips;

        while (lCharacter->GetCharacterLink(lNodeId, &lCharacterLink))
        {
            FbxAMatrix& lGlobalPosition = lCharacterLink.mNode->EvaluateGlobalTransform(FBXSDK_TIME_ZERO);

            printf("    Matrix value: %s\n", "");

            FbxString lMatrixValue;

            for (k = 0; k<4; k++)
            {
                FbxVector4 lRow = lGlobalPosition.GetRow(k);
                char        lRowValue[1024];

                FBXSDK_sprintf(lRowValue, 1024, "%9.4f %9.4f %9.4f %9.4f\n", lRow[0], lRow[1], lRow[2], lRow[3]);
                lMatrixValue += FbxString("        ") + FbxString(lRowValue);
            }

            printf("%s\n", lMatrixValue.Buffer());

            lNodeId = FbxCharacter::ENodeId(int(lNodeId) + 1);
        }
    }
}

メッセージと音の出力テスト

2017/01/29

かなり久しぶりの投稿になってしまいました。 ドラクエのメッセージみたいなのを作りたくて、プログラム作りました。

文字描画は SDL_ttf を使用しました。CPU で文字のビットマップを作っておいて、GPU では UV をずらして描画する文字を変更する方式です。

この方式だと等幅フォントじゃないと面倒そうだったので等幅フォント限定です。

音は適当な正弦波を出力しているだけです。メッセージの中で頭文字とスペース、カンマやピリオドは周波数を変更しています。

一応それぞれの文字は独立したパラメーターで管理しているので、回転したり、色を変えたり、光らせたりはできるようになっています。

これを応用したらきっと何か楽しいことができるはず..

名前付きパイプのプロセス間通信をサーバー側 C#、クライアント側 C++ で書く

2016/09/27

C++ 名前付きパイプによるプロセス間通信の小さいサンプルの記事で載せた C++ のIPCサンプルで、サーバー側を C# にしたくなったので、C# に置き換えました。挙動は全く同じです。

ソースコードを載せておきます。

サーバー側の C# コード


using System.IO;
using System.IO.Pipes;

namespace PicSample
{
    class Program
    {
        static void Main(string[] args)
        {
            var server = new NamedPipeServerStream("mynamedpipe");
            System.Console.WriteLine("クライアント起動待ち..");
            server.WaitForConnection();
            StreamWriter streamWriter = new StreamWriter(server);
            string sendMessage = string.Empty;
            do
            {
                System.Console.Write("送信する文字を入力(Endで終了): ");
                sendMessage = System.Console.ReadLine();
                streamWriter.Write(sendMessage);
                streamWriter.Flush();
                server.WaitForPipeDrain();
            } while (sendMessage != "End");

            server.Dispose();
        }
    }
}

クライアント側の C++ コード


#include <Windows.h>
#include <iostream>

void main()
{
    HANDLE pipeHandle = CreateFile(L"\\\\.\\pipe\\mynamedpipe", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
    if (pipeHandle == INVALID_HANDLE_VALUE)
    {
        std::cout << "パイプ作成に失敗" << std::endl;
        return;
    }

    std::cout << "サーバーから受信開始" << std::endl;

    // 文字列受信
    char recvBuffer[256];    //受信バッファ
    do
    {
        recvBuffer[0] = '\0';
        DWORD recvBuffer;
        ReadFile(pipeHandle, recvBuffer, sizeof(recvBuffer), &recvBuffer, NULL);
        if (recvBuffer[0] == '\0')
        {
            continue;
        }
        recvBuffer[readBytes] = '\0';
        std::cout << "受信: " << recvBuffer << std::endl;
    } while (strcmp(recvBuffer, "End") != 0);

    CloseHandle(pipeHandle);
}

C++ 名前付きパイプによるプロセス間通信の小さいサンプル

2016/09/26

以前作った GL のアプリケーションをプロセス間通信で外から操作できるようにしたくなったので、第1歩として名前付きパイプを使ったプロセス間通信の Windows 版小 C++ サンプルを作りましたので載せておきます。

サーバー側のプロセス起動後にクライアント側を起動し、サーバー側で文字列を入力すると、クライアント側に出力されるというサンプルです。

サーバー側のコード


#include <Windows.h>
#include <iostream>

void main()
{
    char sendBuffer[256];
    HANDLE pipeHandle = CreateNamedPipe(
        L"\\\\.\\pipe\\mynamedpipe",
        PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE,
        1,
        sizeof(sendBuffer),
        sizeof(sendBuffer),
        1000, NULL);
    if (pipeHandle == INVALID_HANDLE_VALUE)
    {
        std::cout << "パイプ作成に失敗" << std::endl;
        return;
    }

    std::cout << "クライアント起動待ち.." << std::endl;
    ConnectNamedPipe(pipeHandle, NULL);

    sendBuffer[0] = '\0';
    do
    {
        std::cout << "送信する文字を入力(Endで終了): ";
        // 入力文字列を送信
        std::cin >> sendBuffer;
        DWORD dwResult;
        WriteFile(pipeHandle, sendBuffer, strlen(sendBuffer) + 1, &dwResult, NULL);
    } while (strcmp(sendBuffer, "End") != 0);

    CloseHandle(pipeHandle);
}

クライアント側のコード


#include <Windows.h>
#include <iostream>

void main()
{
    HANDLE pipeHandle = CreateFile(L"\\\\.\\pipe\\mynamedpipe", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
    if (pipeHandle == INVALID_HANDLE_VALUE)
    {
        std::cout << "パイプ作成に失敗" << std::endl;
        return;
    }

    std::cout << "サーバーから受信開始" << std::endl;

    // 文字列受信
    char recvBuffer[256];    //受信バッファ
    do
    {
        recvBuffer[0] = '\0';
        DWORD recvBuffer;
        ReadFile(pipeHandle, recvBuffer, sizeof(recvBuffer), &recvBuffer, NULL);
        if (recvBuffer[0] == '\0')
        {
            continue;
        }
        recvBuffer[readBytes] = '\0';
        std::cout << "受信: " << recvBuffer << std::endl;
    } while (strcmp(recvBuffer, "End") != 0);

    CloseHandle(pipeHandle);
}

参考
https://msdn.microsoft.com/ja-jp/library/windows/desktop/aa365592(v=vs.85).aspx

C++ ミサイルの回転プログラム

2015/07/12

以前作ったミサイルの軌跡を描画するC++プログラムで、ミサイル部分をつけました。とりあえずダミーの三角錐を描画したものです。

ミサイルの前のフレームの座標と今のフレームの座標の方向に向かせるようにしただけです。Maya でいうエイムコンストレイン的なやつです。

ある対象の方向を向かせるための回転行列を取得する関数を載せておきます。


void LookAt(
    float *o_matrix4x4,
    float eye_x, float eye_y, float eye_z,
    float target_x, float target_y, float target_z,
    float up_x, float up_y, float up_z)
{
    target_x = eye_x - target_x;
    target_y = eye_y - target_y;
    target_z = eye_z - target_z;
    float length = sqrtf(target_x * target_x + target_y * target_y + target_z * target_z);
    o_matrix4x4[2] = target_x / length;
    o_matrix4x4[6] = target_y / length;
    o_matrix4x4[10] = target_z / length;

    target_x = up_y * o_matrix4x4[10] - up_z * o_matrix4x4[6];
    target_y = up_z * o_matrix4x4[2] - up_x * o_matrix4x4[10];
    target_z = up_x * o_matrix4x4[6] - up_y * o_matrix4x4[2];
    length = sqrtf(target_x * target_x + target_y * target_y + target_z * target_z);
    o_matrix4x4[0] = target_x / length;
    o_matrix4x4[4] = target_y / length;
    o_matrix4x4[8] = target_z / length;

    o_matrix4x4[1] = o_matrix4x4[6] * o_matrix4x4[8] - o_matrix4x4[10] * o_matrix4x4[4];
    o_matrix4x4[5] = o_matrix4x4[10] * o_matrix4x4[0] - o_matrix4x4[2] * o_matrix4x4[8];
    o_matrix4x4[9] = o_matrix4x4[2] * o_matrix4x4[4] - o_matrix4x4[6] * o_matrix4x4[0];

    o_matrix4x4[12] = -(eye_x * o_matrix4x4[0] + eye_y * o_matrix4x4[4] + eye_z * o_matrix4x4[8]);
    o_matrix4x4[13] = -(eye_x * o_matrix4x4[1] + eye_y * o_matrix4x4[5] + eye_z * o_matrix4x4[9]);
    o_matrix4x4[14] = -(eye_x * o_matrix4x4[2] + eye_y * o_matrix4x4[6] + eye_z * o_matrix4x4[10]);

    o_matrix4x4[3] = o_matrix4x4[7] = o_matrix4x4[11] = 0.0f;
    o_matrix4x4[15] = 1.0f;
}

waveInProc で waveInAddBuffer を呼ぶとデッドロック

waveInOpen の dwCallback に CALLBACK_FUNCTION を指定した時に waveInProc コールバック内で waveInAddBuffer をコールすると、スレッドがフリーズして処理が返ってこなくなる問題に少しはまりました。

コールバックの外から呼ぶとフリーズしないので、メインスレッドの処理では何もしないようにしても直らない...と思ったら、MSDN の waveInProc のページにコールバックでシステム定義関数呼ぶなと書いてありました。

EnterCriticalSection、LeaveCriticalSection、midiOutLongMsg、midiOutShortMsg、OutputDebugString、PostMessage、PostThreadMessage、SetEvent、timeGetSystemTime、timeGetTime、timeKillEvent および timeSetEvent を除き、アプリケーションでコールバック関数内からシステム定義関数を呼び出さないようにしてください。ほかのウェーブ関数を呼び出すと、デッドロックの原因となります。

悩む前にドキュメントちゃんと読めってやつですね...

C++ MIDIノート値から音階名を取得

2015/03/01 21:05

あまり需要ないかもしれませんが、MIDIノートの値から音階名を文字列で取得する関数を作ったので載せておきます。


void GetMidiNoteAsString(char *o_midi_note_as_string, int midi_note)
{
    const char* ScaleAsString[] = {
        "C",
        "C#",
        "D",
        "D#",
        "E",
        "F",
        "F#",
        "G",
        "G#",
        "A",
        "A#",
        "B",
    };

    int scale_index = midi_note % 12;
    int octave_offset = -1; // 国際式は-1、YAMAHA式は-2
    int octave = midi_note / 12 + octave_offset; 
    sprintf(o_midi_note_as_string, "%s %d", ScaleAsString[scale_index], octave);
}

0  1  2  3  4  5  

にほんブログ村 ゲームブログ ファイアーエムブレムへ にほんブログ村 デザインブログ コンピュータグラフィックスへ

0.0219 sec

Copyright(C)2006-2018 wsp All Rights Reserved