ぬの部屋(仮)
nu-no-he-ya
  •  123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
         12
    3456789
    10111213141516
    17181920212223
    2425262728  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
       1234
    567891011
    12131415161718
    19202122232425
    26272829   
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28      
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • Windowsでファイルからそれを開くアプリケーションを特定して開く

    AssocQueryStringWを使ってファイルの拡張子または存在するファイルから関連付けられたアプリケーションを特定できる。

    使用例

    #include <iostream>
    
    #include <windows.h>
    #include <shlwapi.h>
    #include <string>
    #include <vector>
    
    #pragma comment(lib, "shlwapi.lib")
    
    
    std::wstring CallAssocQueryString(const std::wstring& filepath, ASSOCSTR str) {
    
    
        DWORD len = 0;
        // まずは、必要なバッファサイズを取得
        // lenにはnull終端を含む文字列の長さが返される
        HRESULT hr = AssocQueryStringW(
            ASSOCF_NONE,
            str,
            filepath.c_str(), // 拡張子".txt"等、 または存在するファイルパス
            nullptr,
            nullptr,// 結果を格納するバッファを指定するが、先にサイズを取得するためnullptrを指定
            &len    // 結果を格納するのに必要なバッファサイズを取得
        );
    
        if (hr != S_OK && hr != S_FALSE) {
            std::wcerr << L"AssocQueryStringW failed with error: " << hr << std::endl;
            return L"";
        }
    
        // バッファサイズがわかったので、結果を格納するバッファを確保
        std::vector<wchar_t> appPath(len , L'\0');
    
        hr = AssocQueryStringW(
            ASSOCF_NONE,
            str,
            filepath.c_str(),
            nullptr,
            &appPath[0],
            &len
        );
    
        return std::wstring(appPath.data());
    
    }
    
    int main() {
    
    
        std::wstring target = L".sln";
    
        // 拡張子から関連付けられたアプリケーションのパスを取得
        std::wstring appPath = CallAssocQueryString(target, ASSOCSTR_EXECUTABLE);
        std::wcout << appPath << std::endl;
    
        // 関連付けられたアプリケーションの表示名を取得。
        // ただし登録されていない場合も多いので、必ずしも取得できるとは限らない。
        std::wstring appName = CallAssocQueryString(target, ASSOCSTR_FRIENDLYAPPNAME);
        std::wcout << appName << std::endl;
    
        // 関連付けられたアプリケーションの実行コマンドを取得
        std::wstring appCommand = CallAssocQueryString(target, ASSOCSTR_COMMAND);
        std::wcout << appCommand << std::endl;
    
        return 0;
        
    }
    

    実行結果

    C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe
    Microsoft Visual Studio 2022
    "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe" "%1"

    CreateProcessで関連付けられたアプリケーションを実行

    windowsではアプリケーションの第一引数にファイルを与えるのが一般的らしいのでASSOCSTR_EXECUTABLEで取得した アプリケーションのパス + ファイルパスでもいいが、より確実にはASSOCSTR_COMMANDで取得した実行コマンドの %1 の部分をファイルパスに置換した方が確実。

    #include <iostream>
    
    #include <windows.h>
    #include <shlwapi.h>
    #include <string>
    #include <vector>
    #include <regex>
    
    #pragma comment(lib, "shlwapi.lib")
    
    
    std::wstring CallAssocQueryString(const std::wstring& filepath, ASSOCSTR str) {
    
    
        DWORD len = 0;
        // まずは、必要なバッファサイズを取得
        // lenにはnull終端を含む文字列の長さが返される
        HRESULT hr = AssocQueryStringW(
            ASSOCF_NONE,
            str,
            filepath.c_str(), // 拡張子".txt"等、 または存在するファイルパス
            nullptr,
            nullptr,// 結果を格納するバッファを指定するが、先にサイズを取得するためnullptrを指定
            &len    // 結果を格納するのに必要なバッファサイズを取得
        );
    
        if (hr != S_OK && hr != S_FALSE) {
            std::wcerr << L"AssocQueryStringW failed with error: " << hr << std::endl;
            return L"";
        }
    
        // バッファサイズがわかったので、結果を格納するバッファを確保
        std::vector<wchar_t> appPath(len , L'\0');
    
        hr = AssocQueryStringW(
            ASSOCF_NONE,
            str,
            filepath.c_str(),
            nullptr,
            &appPath[0],
            &len
        );
    
        return std::wstring(appPath.data());
    
    }
    
    int main() {
    
    
        std::wstring target = LR"(C:\test\test.txt)";
    
        // 関連付けられたアプリケーションの実行コマンドを取得
        std::wstring appCommand = CallAssocQueryString(target, ASSOCSTR_COMMAND);
        std::wcout << appCommand << std::endl;
        // appCommandは、"C:\Path\To\App.exe" "%1" のような形式
    
        // "%1"をファイルパスに置き換えるとApp.exeでファイルを開ける
    
        std::wregex percent1_pattern(LR"((\"?)%1(\"?))"); // %1 または "%1" にマッチ
        std::wstring quoted_path = L"\"" + target + L"\"";
        std::wstring command = std::regex_replace(appCommand, percent1_pattern, quoted_path);
    
        std::wcout << "Command: " << command << std::endl;
    
        STARTUPINFOW si = { sizeof(si) };
        PROCESS_INFORMATION pi;
    
        BOOL ret = CreateProcessW(
            nullptr,
            &command[0], // 開きたいファイルを含むコマンド
            nullptr,
            nullptr,
            FALSE,
            CREATE_UNICODE_ENVIRONMENT,
            nullptr,
            nullptr,
            &si,
            &pi
        );
    
        return 0;
    }
    

    Windowsで環境変数を設定してアプリケーション起動(2)既存の環境変数を引き継いで実行

    CreateProcessで外部アプリケーションを起動するとき、アプリケーションによっては現在の環境変数が有効でないと起動できない場合がある。lpEnvironmentが非nullptrの場合、現在の環境変数が反映されないらしく、この場合は自分で取得して、それに今回自分が必要な値を加えて渡してやるという形をとる。

    現在の環境変数の一括取得

    GetEnvironmentStringsを使用すれば、環境変数設定をまるごと取得できる。

    #include <iostream>
    
    #include <windows.h>
    //#include <shlwapi.h>
    #include <string>
    #include <vector>
    
    
    // 現在の環境変数一覧を取得
    void GetCurrentEnvironemts() {
    
        // \0区切りの環境変数を一括取得する。
        // 例:
        // SystemRoot=C:\WINDOWS\0SystemDrive=C:\0\0
        LPWCH envStrings = GetEnvironmentStringsW();
    
        LPWCH p = envStrings;
        while(*p != 0) {
    
            // 現在のpから\0までの文字列を取得
            std::wstring envVar(p);
            std::wcout << envVar << std::endl;
    
            // 次の環境変数へ移動
            // p+envVar.size が \0 を表すので、+1すると次の環境変数の先頭
            p += envVar.size() + 1; 
        }
    
        FreeEnvironmentStringsW(envStrings);
    
    
    }
    
    int main() {
        GetCurrentEnvironemts();
    }
    

    NAME=VALUE\0の形で取得できるので、必要であれば加工して渡してもいい。

    今回はただCreateProcessの呼び出しに継承したいだけなので、環境変数の終端\0\0から\0を一つとり、その後に自分が設定したい値を加える。

    #include <iostream>
    
    #include <windows.h>
    #include <string>
    #include <vector>
    
    
    // 現在の環境変数一覧を取得
    std::wstring GetCurrentEnvironemts() {
    
        // \0区切りの環境変数を一括取得する。
        // 例:
        // SystemRoot=C:\WINDOWS\0SystemDrive=C:\0\0
        LPWCH envStrings = GetEnvironmentStringsW();
    
        std::wstring allenv;
        LPWCH p = envStrings;
        while(*p != 0) {
    
            // 現在のpから\0までの文字列を取得
           	std::wstring envVar(p);
            allenv += envVar;
            allenv.push_back(L'\0'); // 環境変数の区切り
    
            // 次の環境変数へ移動
            // p+envVar.size が \0 を表すので、+1すると次の環境変数の先頭
            p += envVar.size() + 1; 
        }
    
        FreeEnvironmentStringsW(envStrings);
    
        return allenv; // 末尾は\0なので、このまま与えたいときは\0をもう一つ追加
    
    }
    
    int main() {
        /////////////////////////////////////////////////
        // 現在の環境変数を取得
        std::wstring all_environments = GetCurrentEnvironemts();
    
        /////////////////////////////////////////////////
        // 自分が追加したい環境変数
        std::wstring envVar1 = L"MY_ENV_STR=HelloWorld";
        std::wstring envVar2 = L"MY_ENV_INT=12345";
    
        // 追加可能な形に整形
        // 環境変数の終端はNULL文字
        std::wstring envVars;
        envVars += envVar1;
        envVars.push_back(L'\0'); // 環境変数の区切り
        envVars += envVar2;
        envVars.push_back(L'\0'); // 環境変数の区切り
        // ここまでで、
        // envVars=="MY_ENV_STR=HelloWorld\0MY_ENV_INT=12345\0"
    
        // all_environmentsの末尾にenvVarsを追加
        std::wstring new_environments = all_environments + envVars;
    
        // 最後に\0を追加して\0\0にする
        new_environments.push_back(L'\0'); 
    
        /////////////////////////////////////////////////
        // アプリケーション起動
        STARTUPINFOW si = { sizeof(si) };
        PROCESS_INFORMATION pi;
        std::wstring apppath = L"notepad.exe";
    
        BOOL ret = CreateProcessW(
            nullptr,
            &apppath[0], // 破壊的パースがされるため非constで渡す
            nullptr,
            nullptr,
            FALSE,
            CREATE_UNICODE_ENVIRONMENT,
            (void*)new_environments.c_str(),
            nullptr,
            &si,
            &pi
        );
    
    
    }
    

    Windowsで環境変数を設定してアプリケーション起動(1)

    CreateProcessで環境変数を設定してアプリケーションを起動できる。

    display_myenvs.exe(テスト用)

    テスト用の環境変数を表示するプログラム。

    // プログラム1 環境変数を表示
    // display_myenvs.exe
    
    #include <iostream>
    
    #include <windows.h>
    
    
    int main()
    {
        char EnvVal[32767];
        size_t limit = sizeof(EnvVal) / sizeof(EnvVal[0]);
    
        std::cout << "------------------------" << std::endl;
        // 環境変数を取得
        GetEnvironmentVariableA("MY_ENV_STR", EnvVal, limit);
        std::cout << "MY_ENV_STR: " << EnvVal << std::endl;
    
        std::cout << "------------------------" << std::endl;
    
        GetEnvironmentVariableA("MY_ENV_INT",EnvVal, limit);
        std::cout << "MY_ENV_INT: " << EnvVal << std::endl;
    
    }
    

    test.exe

    // プログラム2 環境変数設定してアプリケーションを起動
    
    #include <iostream>
    
    #include <windows.h>
    
    int main()
    {
        ////////////////////////////////////////////////////
        // 独自の環境変数設定
        // 環境変数作成
        std::wstring envVar1 = L"MY_ENV_STR=HelloWorld";
        std::wstring envVar2 = L"MY_ENV_INT=12345";
    
        // 環境変数を設定するときは各変数を\0文字で区切り、終端を\0\0にする
        // "VAL1=value1\0VAL2=value2\0\0"
    
        std::wstring envVars;
        envVars += envVar1;
        envVars.push_back(L'\0'); // 環境変数の区切り
        envVars += envVar2;
        envVars.push_back(L'\0'); // 環境変数の区切り
        // 最後は\0\0で終端
        envVars.push_back(L'\0');
        envVars.push_back(L'\0');
    
    
       // アプリ起動
       STARTUPINFOW si = { sizeof(si) };
       PROCESS_INFORMATION pi;
       std::wstring apppath = L"display_myenvs.exe";
    
       BOOL ret = CreateProcessW(
           nullptr,
           &apppath[0], // 破壊的パースがされるため非constで渡す
           nullptr,
           nullptr,
           FALSE,
           CREATE_UNICODE_ENVIRONMENT,
           (void*)envVars.c_str(),
           nullptr,
           &si,
           &pi
       );
    
       // エラー処理
       if (!ret) {
          std::cerr << "CreateProcessA failed with error: " << GetLastError() << std::endl;
          return 1;
       }
    
    }
    

    C++でfunc(param=10);のように関数呼び出しに引数名を使用する方法を考える

    やってできないことはない。実用性があるかどうかは別。これを使うと引数を与える順番を考えなくてよくなるのと、引数の意味が呼び出し側でわかるようになるので若干可読性が上がるかもしれない。

    #include <iostream>
    #include <type_traits>
    
    
    // 型TがArgs...に含まれているかどうかを判定するメタ関数
    template <typename T, typename... Args>
    constexpr bool is_contains_type = (std::is_same_v<T, Args> || ...);
    

    // 可変引数テンプレートから特定の型Tで与えられた変数を取得する
    template<typename T, typename First, typename... Rest>
    decltype(auto) get_value(First&& first, Rest&&... rest) {
        if constexpr (std::is_same_v<T, std::decay_t<First> > == true) {
            return std::forward<First>(first);
        }
        // sizeof...(rest)で残りの引数の数をチェック
        else if constexpr (sizeof...(rest) > 0) {
    
            // 残りの引数restから T を探す
            return get_value<T>( std::forward<Rest>(rest)...);
        }
        else {
            static_assert(sizeof...(rest) > 0, "No matching type found in arguments.");
        }
    
    }
    
          
    template<int ID> // IDを与えてusing時にそれぞれを違う型として認識されるようにする
    struct ArgString {
        std::string value;
        ArgString& operator=(const std::string& str) {
            value = str;
            return *this;
        }
    };
    template<int ID>
    struct ArgInt {
        int value;
        ArgInt& operator=(int i) {
            value = i;
            return *this;
        }
    };
    
    using Text = ArgString<0>;
    using Title = ArgString<1>;
    using Index = ArgInt<0>;
    using Count = ArgInt<1>;
    
    // グローバル引数として、関数に渡す時に指定する引数名を定義
    Index index;
    Count count;
    Text text;
    Title title;
    
          
    // print関数の定義
    template <class... Args>
    void print(Args&&... args) {// argsにはindex,count,text,titleのいずれかが入っている
        Index index;
        Count count;
        Text text;
        Title title;
        if constexpr (is_contains_type<Index, std::decay_t<Args>...>) {
            auto&& arg = get_value<Index>( std::forward<Args>(args)... );
            index = arg; // 引数の値をIndexに設定
        }
        if constexpr (is_contains_type<Count, std::decay_t<Args>...>) {
            auto&& arg = get_value<Count>( std::forward<Args>(args)... );
            count = arg; // 引数の値をCountに設定
        }
        if constexpr (is_contains_type<Text, std::decay_t<Args>...>) {
            auto&& arg = get_value<Text>( std::forward<Args>(args)... );
            text = arg; // 引数の値をTextに設定
        }
        if constexpr (is_contains_type<Title, std::decay_t<Args>...>) {
            auto&& arg = get_value<Title>( std::forward<Args>(args)... );
            title = arg; // 引数の値をTitleに設定
        }
    
        // 各値を使用
        std::cout << "index: " << index.value << std::endl;
        std::cout << "count: " << count.value << std::endl;
        std::cout << "text: " << text.value << std::endl;
        std::cout << "title: " << title.value << std::endl;
    
    }
    
    
    int main()
    {
        print(
            index = 5,
            count = 10,
            text = "Hello, World!",
            title = "My Title"
        );
    }
    

    実行結果

    index: 5
    count: 10
    text: Hello, World!
    title: My Title

    OptiX 9.0を試す(2)optixRaycastingのプロジェクトに必要なファイルを確認

    optixRaycastingのプロジェクトにどのファイルが必要かを確認する

    ソースコードの場所:

    C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0\SDK\optixRaycasting\

    に、以下のファイルが存在

    • optixRaycasting.cpp
    • optixRaycasting.cu
    • optixRaycasting.h
    • optixRaycastingKernels.cu
    • optixRaycastingKernels.h

    .cu.obj / dlink.obj / .cu.optixir の作成

    プロジェクトの作成の前に、nvccで以下を生成しておく。

    cl.exeも呼び出されるので、x64 Native Tools Command Prompt等で実行する。

    .cu.optixir

    nvcc optixRaycasting.cu -o optixRaycasting_generated_optixRaycasting.cu.optixir -arch compute_50 -lineinfo -use_fast_math -optix-ir -rdc true -D__x86_64 -I"C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0\include" -I"C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0\SDK"

    .cu.obj の作成

    本体のC++プロジェクトがMTかMDかでビルドオプションを変える

    MT

    nvcc optixRaycastingKernels.cu -c -o optixRaycasting_generated_optixRaycastingKernels.cu.obj -arch compute_50 -lineinfo -use_fast_math -rdc true -D__x86_64 -I"C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0\include" -I"C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0\SDK"

    MD

    nvcc optixRaycastingKernels.cu -c -o optixRaycasting_generated_optixRaycastingKernels.cu.obj -arch compute_50 -lineinfo -use_fast_math -rdc true -D__x86_64 -Xcompiler "/MD" -I"C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0\include" -I"C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0\SDK"

    dlink.obj (デバイスリンク)

    nvcc -dlink optixRaycasting_generated_optixRaycastingKernels.cu.obj -o optixRaycasting_generated_optixRaycastingKernels_dlink.obj -arch compute_50 -Xcompiler "/MD" -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.8\lib\x64" -lcudart_static

    C++プロジェクト

    • optixRaycasting.cpp
    • optixRaycasting.h
    • optixRaycastingKernels.h

    で、VC++で、C++プロジェクトを作成。

    ぱっと見いらないものなどを消して、依存関係やらを整頓する。

    ・サンプルをビルドしたディレクトリ内にある sutil_7_sdk.lib が必要。

    gladはこの段階では取り除けなかった。

    ・sutil::loadSceneがモデルの他にシーン情報も設定している

    ・optixRaycasting_generated_optixRaycastingKernels.cu.obj optixRaycasting_generated_optixRaycastingKernels_dlink.obj をリンカー → 入力 → 追加の依存ファイルに追記しておく

     

    /*
    
     * SPDX-FileCopyrightText: Copyright (c) 2019 - 2024  NVIDIA CORPORATION & AFFILIATES. All rights reserved.
     * SPDX-License-Identifier: BSD-3-Clause
     * 
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     * list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form must reproduce the above copyright notice,
     * this list of conditions and the following disclaimer in the documentation
     * and/or other materials provided with the distribution.
     *
     * 3. Neither the name of the copyright holder nor the names of its
     * contributors may be used to endorse or promote products derived from
     * this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    
    #include <cuda_runtime.h>
    
    #include <optix.h>
    #include <optix_function_table_definition.h>
    #include <optix_stack_size.h>
    #include <optix_stubs.h>
    
     /*
     // Include ディレクトリ
     C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0\include
     C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0\SDK\cuda
     C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0\SDK
     C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.8\include
     C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0\SDK\support\imgui\..
     */
    
    /*
    // nvccでビルドして作成する各種関連ファイル:
    optixRaycasting_generated_optixRaycastingKernels.cu.obj
    optixRaycasting_generated_optixRaycastingKernels_dlink.obj
    */
    
    /*
    プリプロセッサ
    _USE_MATH_DEFINES
    NOMINMAX
    GLAD_GLAPI_EXPORT
    */
    
    // D:\tmp\optixbuild ここでインクルードしなくてもよい
    //#include <sampleConfig.h>
    
    #include <fstream> // getInputDataの代わりにifstreamを使う
    
    #include "cuda/whitted.h"
    #include <sutil/CUDAOutputBuffer.h>
    #include <sutil/Matrix.h>
    #include <sutil/Record.h>
    #include <sutil/Scene.h>
    #include <sutil/sutil.h>
    
    #include "optixRaycasting.h"
    #include "optixRaycastingKernels.h"
    
    #include <iomanip>
    
    
    #pragma comment(lib, "D:\\tmp\\optixbuild\\lib\\Release\\glad.lib")
    #pragma comment(lib, "D:\\tmp\\optixbuild\\lib\\Release\\sutil_7_sdk.lib")
    
    #pragma comment(lib, "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v12.8\\lib\\x64\\cudart_static.lib")
    #pragma comment(lib, "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v12.8\\lib\\x64\\cudadevrt.lib")
    
    
    struct RaycastingState
    {
        int                         width                    = 0;
        int                         height                   = 0;
    
        OptixDeviceContext          context                  = 0;
        sutil::Scene                scene                    = {};
    
        OptixPipelineCompileOptions pipeline_compile_options = {};
        OptixModule                 ptx_module               = 0;
        OptixPipeline               pipeline_1               = 0;
        OptixPipeline               pipeline_2               = 0;
    
        OptixProgramGroup           raygen_prog_group        = 0;
        OptixProgramGroup           miss_prog_group          = 0;
        OptixProgramGroup           hit_prog_group           = 0;
    
        Params                      params                   = {};
        Params                      params_translated        = {};
        OptixShaderBindingTable     sbt                      = {};
    
        sutil::Texture           mask                     = {};
    };
    
    
    typedef sutil::Record<whitted::HitGroupData> HitGroupRecord;
    
    
    void createModule( RaycastingState& state )
    {
        OptixModuleCompileOptions module_compile_options = {};
    #if OPTIX_DEBUG_DEVICE_CODE
        module_compile_options.optLevel   = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0;
        module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL;
    #else
        module_compile_options.optLevel   = OPTIX_COMPILE_OPTIMIZATION_DEFAULT;
        module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_MINIMAL;
    #endif
    
        state.pipeline_compile_options.usesMotionBlur        = false;
        state.pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING;
        state.pipeline_compile_options.numPayloadValues      = 4;
        state.pipeline_compile_options.numAttributeValues    = 2;
        state.pipeline_compile_options.exceptionFlags        = OPTIX_EXCEPTION_FLAG_NONE;
        state.pipeline_compile_options.pipelineLaunchParamsVariableName = "params";
    
        size_t      inputSize = 0;
    
        // 使いにくいので書き換え
    #if 0
        const char* input     = sutil::getInputData( OPTIX_SAMPLE_NAME, OPTIX_SAMPLE_DIR, "optixRaycasting.cu", inputSize );
    #else
     
        std::string filepath = "optixRaycasting_generated_optixRaycasting.cu.optixir";
        std::ifstream file(filepath, std::ios::binary | std::ios::ate);
        if (!file)
            throw std::runtime_error("Failed to open file: " + filepath);
    
        std::streamsize size = file.tellg(); // ファイルサイズ
        file.seekg(0, std::ios::beg); // 先頭へ移動
    
        std::vector<char> buffer;
        buffer.resize(size);
    
        if (!file.read(buffer.data(), size))
            throw std::runtime_error("Failed to read file: " + filepath);
    
        const char* input = buffer.data();
        inputSize = size;
    
    #endif
        // optixModuleCreateに.optixirを与える
        OPTIX_CHECK_LOG( optixModuleCreate( state.context, &module_compile_options, &state.pipeline_compile_options, input,
                                            inputSize, LOG, &LOG_SIZE, &state.ptx_module ) );
    }
    
    void createProgramGroups( RaycastingState& state )
    {
        OptixProgramGroupOptions program_group_options = {};
    
        OptixProgramGroupDesc raygen_prog_group_desc    = {};
        raygen_prog_group_desc.kind                     = OPTIX_PROGRAM_GROUP_KIND_RAYGEN;
        raygen_prog_group_desc.raygen.module            = state.ptx_module;
        raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__from_buffer";
    
        OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &raygen_prog_group_desc,
                                                  1,  // num program groups
                                                  &program_group_options, LOG, &LOG_SIZE, &state.raygen_prog_group ) );
    
        OptixProgramGroupDesc miss_prog_group_desc  = {};
        miss_prog_group_desc.kind                   = OPTIX_PROGRAM_GROUP_KIND_MISS;
        miss_prog_group_desc.miss.module            = state.ptx_module;
        miss_prog_group_desc.miss.entryFunctionName = "__miss__buffer_miss";
        OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &miss_prog_group_desc,
                                                  1,  // num program groups
                                                  &program_group_options, LOG, &LOG_SIZE, &state.miss_prog_group ) );
    
    
        OptixProgramGroupDesc hit_prog_group_desc = {};
        hit_prog_group_desc.kind                  = OPTIX_PROGRAM_GROUP_KIND_HITGROUP;
        hit_prog_group_desc.hitgroup.moduleAH            = state.ptx_module;
        hit_prog_group_desc.hitgroup.entryFunctionNameAH = "__anyhit__texture_mask";
        hit_prog_group_desc.hitgroup.moduleCH            = state.ptx_module;
        hit_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__buffer_hit";
        OPTIX_CHECK_LOG( optixProgramGroupCreate( state.context, &hit_prog_group_desc,
                                                  1,  // num program groups
                                                  &program_group_options, LOG, &LOG_SIZE, &state.hit_prog_group ) );
    }
    
    
    void createPipelines( RaycastingState& state )
    {
        const uint32_t    max_trace_depth   = 1;
        OptixProgramGroup program_groups[3] = {state.raygen_prog_group, state.miss_prog_group, state.hit_prog_group};
    
        OptixPipelineLinkOptions pipeline_link_options = {};
        pipeline_link_options.maxTraceDepth            = max_trace_depth;
    
        OPTIX_CHECK_LOG( optixPipelineCreate( state.context, &state.pipeline_compile_options, &pipeline_link_options,
                                              program_groups, sizeof( program_groups ) / sizeof( program_groups[0] ), LOG,
                                              &LOG_SIZE, &state.pipeline_1 ) );
        OPTIX_CHECK_LOG( optixPipelineCreate( state.context, &state.pipeline_compile_options, &pipeline_link_options,
                                              program_groups, sizeof( program_groups ) / sizeof( program_groups[0] ), LOG,
                                              &LOG_SIZE, &state.pipeline_2 ) );
    
        OptixStackSizes stack_sizes_1 = {};
        OptixStackSizes stack_sizes_2 = {};
        for( auto& prog_group : program_groups )
        {
            OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes_1, state.pipeline_1 ) );
            OPTIX_CHECK( optixUtilAccumulateStackSizes( prog_group, &stack_sizes_2, state.pipeline_2 ) );
        }
    
        uint32_t direct_callable_stack_size_from_traversal;
        uint32_t direct_callable_stack_size_from_state;
        uint32_t continuation_stack_size;
        OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes_1, max_trace_depth,
                                                 0,  // maxCCDepth
                                                 0,  // maxDCDEpth
                                                 &direct_callable_stack_size_from_traversal,
                                                 &direct_callable_stack_size_from_state, &continuation_stack_size ) );
        OPTIX_CHECK( optixPipelineSetStackSize( state.pipeline_1, direct_callable_stack_size_from_traversal,
                                                direct_callable_stack_size_from_state, continuation_stack_size,
                                                2  // maxTraversableDepth
                                                ) );
        OPTIX_CHECK( optixUtilComputeStackSizes( &stack_sizes_2, max_trace_depth,
                                                 0,  // maxCCDepth
                                                 0,  // maxDCDEpth
                                                 &direct_callable_stack_size_from_traversal,
                                                 &direct_callable_stack_size_from_state, &continuation_stack_size ) );
        OPTIX_CHECK( optixPipelineSetStackSize( state.pipeline_2, direct_callable_stack_size_from_traversal,
                                                direct_callable_stack_size_from_state, continuation_stack_size,
                                                2  // maxTraversableDepth
                                                ) );
    }
    
    
    void createSBT( RaycastingState& state )
    {
        // raygen
        CUdeviceptr  d_raygen_record    = 0;
        const size_t raygen_record_size = sizeof( sutil::EmptyRecord );
        CUDA_CHECK( cudaMalloc( reinterpret_cast<void**>( &d_raygen_record ), raygen_record_size ) );
    
        sutil::EmptyRecord rg_record;
        OPTIX_CHECK( optixSbtRecordPackHeader( state.raygen_prog_group, &rg_record ) );
        CUDA_CHECK( cudaMemcpy( reinterpret_cast<void*>( d_raygen_record ), &rg_record, raygen_record_size, cudaMemcpyHostToDevice ) );
    
        // miss
        CUdeviceptr  d_miss_record    = 0;
        const size_t miss_record_size = sizeof( sutil::EmptyRecord );
        CUDA_CHECK( cudaMalloc( reinterpret_cast<void**>( &d_miss_record ), miss_record_size ) );
    
        sutil::EmptyRecord ms_record;
        OPTIX_CHECK( optixSbtRecordPackHeader( state.miss_prog_group, &ms_record ) );
        CUDA_CHECK( cudaMemcpy( reinterpret_cast<void*>( d_miss_record ), &ms_record, miss_record_size, cudaMemcpyHostToDevice ) );
    
        // hit group
        std::vector<HitGroupRecord> hitgroup_records;
        for( const auto& mesh : state.scene.meshes() )
        {
            for( size_t i = 0; i < mesh->material_idx.size(); ++i )
            {
                HitGroupRecord rec = {};
                OPTIX_CHECK( optixSbtRecordPackHeader( state.hit_prog_group, &rec ) );
                GeometryData::TriangleMesh triangle_mesh = {};
                triangle_mesh.positions                  = mesh->positions[i];
                triangle_mesh.normals                    = mesh->normals[i];
                for( size_t j = 0; j < GeometryData::num_texcoords; ++j )
                    triangle_mesh.texcoords[j] = mesh->texcoords[j][i];
                triangle_mesh.indices = mesh->indices[i];
                rec.data.geometry_data.setTriangleMesh( triangle_mesh );
                rec.data.material_data = state.scene.materials()[mesh->material_idx[i]];
                hitgroup_records.push_back( rec );
            }
        }
    
        CUdeviceptr  d_hitgroup_record    = 0;
        const size_t hitgroup_record_size = sizeof( HitGroupRecord );
        CUDA_CHECK( cudaMalloc( reinterpret_cast<void**>( &d_hitgroup_record ), hitgroup_record_size * hitgroup_records.size() ) );
        CUDA_CHECK( cudaMemcpy( reinterpret_cast<void*>( d_hitgroup_record ), hitgroup_records.data(),
                                hitgroup_record_size * hitgroup_records.size(), cudaMemcpyHostToDevice ) );
    
        state.sbt.raygenRecord                = d_raygen_record;
        state.sbt.missRecordBase              = d_miss_record;
        state.sbt.missRecordStrideInBytes     = static_cast<uint32_t>( miss_record_size );
        state.sbt.missRecordCount             = RAY_TYPE_COUNT;
        state.sbt.hitgroupRecordBase          = d_hitgroup_record;
        state.sbt.hitgroupRecordStrideInBytes = static_cast<uint32_t>( hitgroup_record_size );
        state.sbt.hitgroupRecordCount         = static_cast<int>( hitgroup_records.size() );
    }
    
    
    void bufferRays( RaycastingState& state )
    {
        // Create CUDA buffers for rays and hits
        sutil::Aabb aabb = state.scene.aabb();
        aabb.invalidate();
        for( const auto& instance : state.scene.instances() )
            aabb.include( instance->world_aabb );
        const float3 bbox_span = aabb.extent();
        state.height           = static_cast<int>( state.width * bbox_span.y / bbox_span.x );
    
        Ray*   rays_d             = 0;
        Ray*   translated_rays_d  = 0;
        size_t rays_size_in_bytes = sizeof( Ray ) * state.width * state.height;
        CUDA_CHECK( cudaMalloc( &rays_d, rays_size_in_bytes ) );
        CUDA_CHECK( cudaMalloc( &translated_rays_d, rays_size_in_bytes ) );
    
        createRaysOrthoOnDevice( rays_d, state.width, state.height, aabb.m_min, aabb.m_max, 0.05f );
        CUDA_CHECK( cudaGetLastError() );
        CUDA_CHECK( cudaMemcpy( translated_rays_d, rays_d, rays_size_in_bytes, cudaMemcpyDeviceToDevice ) );
    
        translateRaysOnDevice( translated_rays_d, state.width * state.height, bbox_span * make_float3( 0.2f, 0, 0 ) );
        CUDA_CHECK( cudaGetLastError() );
    
        Hit*   hits_d             = 0;
        Hit*   translated_hits_d  = 0;
        size_t hits_size_in_bytes = sizeof( Hit ) * state.width * state.height;
        CUDA_CHECK( cudaMalloc( &hits_d, hits_size_in_bytes ) );
        CUDA_CHECK( cudaMalloc( &translated_hits_d, hits_size_in_bytes ) );
    
        state.params            = {state.scene.traversableHandle(), rays_d, hits_d};
        state.params_translated = {state.scene.traversableHandle(), translated_rays_d, translated_hits_d};
    }
    
    
    void launch( RaycastingState& state )
    {
        CUstream stream_1 = 0;
        CUstream stream_2 = 0;
        CUDA_CHECK( cudaStreamCreate( &stream_1 ) );
        CUDA_CHECK( cudaStreamCreate( &stream_2 ) );
    
        Params* d_params            = 0;
        Params* d_params_translated = 0;
        CUDA_CHECK( cudaMalloc( reinterpret_cast<void**>( &d_params ), sizeof( Params ) ) );
        CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast<void*>( d_params ), &state.params, sizeof( Params ),
                                     cudaMemcpyHostToDevice, stream_1 ) );
    
        OPTIX_CHECK( optixLaunch( state.pipeline_1, stream_1, reinterpret_cast<CUdeviceptr>( d_params ), sizeof( Params ),
                                  &state.sbt, state.width, state.height, 1 ) );
    
        // Translated
        CUDA_CHECK( cudaMalloc( reinterpret_cast<void**>( &d_params_translated ), sizeof( Params ) ) );
        CUDA_CHECK( cudaMemcpyAsync( reinterpret_cast<void*>( d_params_translated ), &state.params_translated,
                                     sizeof( Params ), cudaMemcpyHostToDevice, stream_2 ) );
    
        OPTIX_CHECK( optixLaunch( state.pipeline_2, stream_2, reinterpret_cast<CUdeviceptr>( d_params_translated ),
                                  sizeof( Params ), &state.sbt, state.width, state.height, 1 ) );
    
        CUDA_SYNC_CHECK();
    
        CUDA_CHECK( cudaFree( reinterpret_cast<void*>( d_params ) ) );
        CUDA_CHECK( cudaFree( reinterpret_cast<void*>( d_params_translated ) ) );
    }
    
    
    void shadeHits( RaycastingState& state, const std::string& outfile )
    {
        sutil::CUDAOutputBufferType     output_buffer_type = sutil::CUDAOutputBufferType::CUDA_DEVICE;
        sutil::CUDAOutputBuffer<float3> output_buffer( output_buffer_type, state.width, state.height );
    
        sutil::ImageBuffer buffer;
        buffer.width        = state.width;
        buffer.height       = state.height;
        buffer.pixel_format = sutil::BufferImageFormat::FLOAT3;
    
        // Original
        shadeHitsOnDevice( output_buffer.map(), state.width * state.height, state.params.hits );
        CUDA_CHECK( cudaGetLastError() );
        output_buffer.unmap();
    
        std::string ppmfile = outfile + ".ppm";
        buffer.data         = output_buffer.getHostPointer();
        sutil::saveImage( ppmfile.c_str(), buffer, false );
        std::cerr << "Wrote image to " << ppmfile << std::endl;
    
        // Translated
        shadeHitsOnDevice( output_buffer.map(), state.width * state.height, state.params_translated.hits );
        CUDA_CHECK( cudaGetLastError() );
        output_buffer.unmap();
    
        ppmfile     = outfile + "_translated.ppm";
        buffer.data = output_buffer.getHostPointer();
        sutil::saveImage( ppmfile.c_str(), buffer, false );
        std::cerr << "Wrote translated image to " << ppmfile << std::endl;
    }
    
    
    void cleanup( RaycastingState& state )
    {
        OPTIX_CHECK( optixPipelineDestroy( state.pipeline_1 ) );
        OPTIX_CHECK( optixPipelineDestroy( state.pipeline_2 ) );
        OPTIX_CHECK( optixProgramGroupDestroy( state.raygen_prog_group ) );
        OPTIX_CHECK( optixProgramGroupDestroy( state.miss_prog_group ) );
        OPTIX_CHECK( optixProgramGroupDestroy( state.hit_prog_group ) );
        OPTIX_CHECK( optixModuleDestroy( state.ptx_module ) );
    
        CUDA_CHECK( cudaFree( reinterpret_cast<void*>( state.params.rays ) ) );
        CUDA_CHECK( cudaFree( reinterpret_cast<void*>( state.params.hits ) ) );
        CUDA_CHECK( cudaFree( reinterpret_cast<void*>( state.params_translated.rays ) ) );
        CUDA_CHECK( cudaFree( reinterpret_cast<void*>( state.params_translated.hits ) ) );
        CUDA_CHECK( cudaFree( reinterpret_cast<void*>( state.sbt.raygenRecord ) ) );
        CUDA_CHECK( cudaFree( reinterpret_cast<void*>( state.sbt.missRecordBase ) ) );
        CUDA_CHECK( cudaFree( reinterpret_cast<void*>( state.sbt.hitgroupRecordBase ) ) );
    
        CUDA_CHECK( cudaDestroyTextureObject( state.mask.texture ) );
        CUDA_CHECK( cudaFreeArray( state.mask.array ) );
    }
    
    
    int main( int argc, char** argv )
    {
        std::string     infile, outfile;
        RaycastingState state;
        state.width = 640;
    
        // .gltfはモデルとシーン情報を含む
    
        // データの場所:
        // C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0\SDK\data
        infile = sutil::sampleDataFilePath("Duck/DuckHole.gltf");
        outfile = "output";
    
        try
        {
            sutil::loadScene( infile.c_str(), state.scene );
            state.scene.createContext();
    
            state.scene.buildMeshAccels();
            state.scene.buildInstanceAccel( RAY_TYPE_COUNT );
            state.context = state.scene.context();
    
            OPTIX_CHECK( optixInit() );  // Need to initialize function table
            createModule( state );
            createProgramGroups( state );
            createPipelines( state );
            createSBT( state );
    
            bufferRays( state );
            launch( state );
            shadeHits( state, outfile );
            cleanup( state );
        }
        catch( std::exception& e )
        {
            std::cerr << "Caught exception: " << e.what() << std::endl;
            return 1;
        }
    
        return 0;
    }
    

    OptiX 9.0を試す(1) ダウンロード / サンプルのビルド

    Windows 11 + Visual C++ 2022 + CUDA 12.8 でOptiX 9.0を試す。

    以下からドライバとCUDAを最新にしておく

    ダウンロード

    NVIDIA Driver 今回使用:576.02

    https://www.nvidia.com/ja-jp/drivers

    CUDA Toolkit 今回使用:12.8

    https://developer.nvidia.com/cuda-downloads

    以下からOptiX 9.0をダウンロード・インストール

    OptiX

    https://developer.nvidia.com/designworks/optix/download

    サンプルビルド

    以下にインストールされている:

    C:/ProgramData/NVIDIA Corporation/OptiX SDK 9.0.0/SDK

    ここにCMakeLists.txtも入っているので、CMake-GUI で、Where is the source codeに指定。

    Where to build the binaries: にビルド用のディレクトリを入れる。

    インストールは行わないので、これでConfigure Generate Open Project する。

    VC++でALL_BUILDすると、D:\tmp\optixbuild\bin\Release にサンプルプログラムが入っている。

    C++、Fold expressionで可変引数テンプレート関数の引数を一括で計算する

    C++17でFold expressionという機能が追加されたらしい。

    なんでも

    (pack op ...)

    とすると、

    (val1 op val2 op val3 op)

    と展開される。

    #include <iostream>
    
    
    template<typename... Args>
    auto add1(Args... val) {
    
        // Fold expression
        // val1 + val2 + val3 + ...
    
        return (val + ...); 
    }
    

    template<int... Args>
    int add2() {
    
        // Fold expression
        // args1 + args2 + args3 + ...
    
        return (Args + ...);
    }
    
    
    int main()
    {
    
        auto ret1 = add1(1.0, 2.2, 3.f, 4, 5);
        std::cout << "Sum: " << ret1 << "\n";
    
        int ret2 = add2<1, 2, 3, 4, 5>();
        std::cout << "Sum: " << ret2 << "\n";
    
    }
    
    Sum: 15.2
    Sum: 15

    C++、可変引数テンプレート関数で、引数の型に応じた動作を定義する

    可変引数テンプレートもそうだが、if constexprやtype_traits、型推論に右辺参照もあるのでかなり簡単に書けるようになっている。

    #include <iostream>
    #include <type_traits>
    
    
    // 型TがArgs...に含まれているかどうかを判定するメタ関数
    template <typename T, typename... Args>
    constexpr bool is_contains_type = (std::is_same_v<T, Args> || ...);
    

    template<typename T, typename First, typename... Rest>
    decltype(auto) get_value(First&& first, Rest&&... rest) {
        if constexpr (std::is_same_v<T, std::decay_t<First> > == true) {
            return std::forward<First>(first);
        }
        // sizeof...(rest)で残りの引数の数をチェック
        else if constexpr (sizeof...(rest) > 0) {
    
            // 残りの引数restから T を探す
            return get_value<T>( std::forward<Rest>(rest)...);
        }
        else {
            static_assert(sizeof...(rest) > 0, "No matching type found in arguments.");
        }
    
    }
    

    template <class... Args>
    void print(Args&&... args) {
    
        if constexpr (is_contains_type<int, std::decay_t<Args>...>) {
            auto&& arg_int = get_value<int>( std::forward<Args>(args)... );
            std::cout << "int is " << arg_int << "\n";
        }
    
        if constexpr (is_contains_type<double, std::decay_t<Args>...>) {
            auto&& arg_double = get_value<double>(std::forward<Args>(args)... );
            std::cout << "double is "<< arg_double << "\n";
        }
    
        if constexpr (is_contains_type<float, std::decay_t<Args>...>) {
            auto&& arg_float = get_value<float>(std::forward<Args>(args)... );
            std::cout << "float is " << arg_float << "\n";
        }
    
    }
    
    int main()
    {
        print(1, 2.5, 5.f); // 引数が右辺値の場合
    
        int K = 10;
        print(K); // 引数が左辺値の場合
    
        std::cout << "K is " << K << "\n";
    }