トップページ > 記事閲覧
ジオメトリシェーダーのサンプル作成
名前:名無三 日時: 2024/06/17 23:19

お疲れ様です。現在ジオメトリシェーダーの使用を試みています。 marupeke296.com/DX10_No6_GeometryShader.html こちらのものを基にDXLIB向けに変更したつもりでしたが、現状上手くいっておりません… 頂点→ジオメトリ→ピクセルシェーダの順で動くのでそれに合わせてGS_INPUTを間に挟んでみていますがそもそも考え方が間違っているように感じます。 すいません、よろしければヒントを頂けますと幸いです ファイル類です。サンプルプロジェクトに上書きしていただくと動くようにしております。 drive.google.com/file/d/1oHwkTKtgD2EX6Wcetz145fgqD6uMO5g8/view?usp=sharing
メンテ

Page: 1 |

Re: ジオメトリシェーダーのサンプル作成 ( No.1 )
名前:名無三 日時:2024/06/17 23:20

以下コード類です ----------------------頂点シェーダー---------------------- // 頂点シェーダーの入力 struct VS_INPUT { float3 Position : POSITION ; // 座標( ローカル空間 ) float3 Normal : NORMAL ; // 法線( ローカル空間 ) float4 Diffuse : COLOR0 ; // ディフューズカラー float4 Specular : COLOR1 ; // スペキュラカラー float4 TexCoords0 : TEXCOORD0 ; // テクスチャ座標 float4 TexCoords1 : TEXCOORD1 ; // サブテクスチャ座標 } ; struct GS_INPUT { float4 pos : SV_POSITION; float3 norm : TEXCOORD0; }; // 頂点シェーダ GS_INPUT main(VS_INPUT VSInput) { // ローカル位置をそのままジオメトリシェーダへ GS_INPUT GSOutput; GSOutput.pos = float4(VSInput.Position, 1.0); GSOutput.norm = VSInput.Normal; return GSOutput; } ----------------------ジオメトリシェーダー---------------------- // 立方体の面法線 float3 sqFaceNorm[6] = { float3(0.0, 0.0, -1.0), float3(1.0, 0.0, 0.0), float3(0.0, 0.0, 1.0), float3(-1.0, 0.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, -1.0, 0.0) }; // 立方体の頂点座標 float3 sqVtx[8] = { float3(-1.0, -1.0, -1.0), float3(1.0, -1.0, -1.0), float3(-1.0, 1.0, -1.0), float3(1.0, 1.0, -1.0), float3(-1.0, -1.0, 1.0), float3(1.0, -1.0, 1.0), float3(-1.0, 1.0, 1.0), float3(1.0, 1.0, 1.0) }; // 立方体のインデックス int sqIdx[36] = { 0, 2, 1, 1, 2, 3, 1, 3, 5, 5, 3, 7, 5, 7, 4, 4, 7, 6, 4, 6, 0, 0, 6, 2, 2, 6, 3, 3, 6, 7, 0, 1, 5, 0, 5, 4 }; struct GS_INPUT { float4 pos : SV_POSITION; float3 norm : TEXCOORD0; }; struct PS_INPUT { float4 pos : SV_POSITION; float3 norm : TEXCOORD0; }; struct LIGHTCAMERA_MATRIX { matrix WorldMatrix; matrix ViewMatrix; matrix ProjectionMatrix; }; // 基本パラメータ cbuffer cbD3D11_LIGHTCAMERA_MATRIX : register(b4) { LIGHTCAMERA_MATRIX g_Base; }; // ジオメトリシェーダ [MaxVertexCount(108)] void main(triangle GS_INPUT In[3], inout TriangleStream<PS_INPUT> triStream) { // 各頂点に配置する立方体の大きさを何となく算出 float L01 = length(In[1].pos.xyz - In[0].pos.xyz); float L12 = length(In[2].pos.xyz - In[1].pos.xyz); float L02 = length(In[0].pos.xyz - In[2].pos.xyz); float sqScale[3] = { min(L01, L02), min(L01, L12), min(L12, L02) }; float4 lLocalPosition; float4 lWorldPosition; float4 lViewPosition; float3 lWorldNrm; float3 lViewNrm; float4 LPPosition; // ライトからみた座標( xとyはライトの射影座標、zはビュー座標 ) float4 lLViewPosition; // 頂点の位置に立方体を配置しWVP変換を // 法線はWVで int faceId = 0; for (int v = 0; v < 3; ++v) { for (int p = 0; p < 12; ++p) { faceId = p / 2; for (int i = 0; i < 3; ++i) { PS_INPUT Out; int idx = sqIdx[p * 3 + i]; float3 localP = sqVtx[idx] * sqScale[v] * 1.f + In[v].pos.xyz; // ローカル座標のセット lLocalPosition.xyz = localP; lLocalPosition.w = 1.0f; lWorldPosition = mul(g_Base.WorldMatrix, lLocalPosition); lViewPosition = mul(g_Base.ViewMatrix, lWorldPosition); Out.pos = mul(g_Base.ProjectionMatrix, lViewPosition); // 法線をビュー空間の角度に変換 =========================================( 開始 ) // ローカルベクトルをワールドベクトルに変換 lWorldNrm = mul(g_Base.WorldMatrix, sqFaceNorm[faceId]); // ワールドベクトルをビューベクトルに変換 Out.norm = mul(g_Base.ViewMatrix, lWorldNrm); // 法線をビュー空間の角度に変換 =========================================( 終了 ) triStream.Append(Out); } triStream.RestartStrip(); } } }
メンテ
Re: ジオメトリシェーダーのサンプル作成 ( No.2 )
名前:名無三 日時:2024/06/17 23:24

以下コード類です2 ----------------------ピクセルシェーダー---------------------- struct PS_INPUT { float4 pos : SV_POSITION; float3 norm : TEXCOORD0; }; // ピクセルシェーダーの出力 struct PS_OUTPUT { float4 Color0 : SV_TARGET0 ; // 色 } ; // ピクセルシェーダ PS_OUTPUT main(PS_INPUT PSInput) { PS_OUTPUT PSOutput; //PSOutput.Color0 = float4(float3(0.8, 0.8, 0.8) * (-normalize(PSInput.norm).z), 1.0); PSOutput.Color0 = float4(1.f, 1.f, 1.f, 1.f); return PSOutput; } ----------------------CPP---------------------- #include "DxLib.h" #include<functional> //シェーダーを使用する際の補助クラス class ShaderUseClass { private: //シェーダーハンドル int m_VertexShaderhandle{ -1 }; int m_PixelShaderhandle{ -1 }; int m_GeometryShaderhandle{ -1 }; // int m_GeometryShaderMatcbhandle{-1}; //シェーダーに渡す追加パラメーターを配するハンドル struct LIGHTCAMERA_MATRIX { MATRIX WorldMatrix; MATRIX ViewMatrix; MATRIX ProjectionMatrix; }; public: ShaderUseClass() { //シェーダーハンドル m_VertexShaderhandle = -1; m_PixelShaderhandle = -1; m_GeometryShaderhandle = -1; } ~ShaderUseClass() { Dispose(); } public: //初期化 void Init(const char* VertexShader, const char* PixelShader) noexcept { if (GetUseDirect3DVersion() != DX_DIRECT3D_11) { return; } this->m_VertexShaderhandle = LoadVertexShader(VertexShader); // 頂点シェーダーバイナリコードの読み込み this->m_PixelShaderhandle = LoadPixelShader(PixelShader); // ピクセルシェーダーバイナリコードの読み込み } void AddGeometryShader(const char* GeometryShader) noexcept { if (GetUseDirect3DVersion() != DX_DIRECT3D_11) { return; } this->m_GeometryShaderMatcbhandle = CreateShaderConstantBuffer(sizeof(LIGHTCAMERA_MATRIX)); this->m_GeometryShaderhandle = LoadGeometryShader(GeometryShader); } //後始末 void Dispose() noexcept { if (GetUseDirect3DVersion() != DX_DIRECT3D_11) { return; } DeleteShader(this->m_VertexShaderhandle); DeleteShader(this->m_PixelShaderhandle); DeleteShaderConstantBuffer(this->m_GeometryShaderMatcbhandle); DeleteShader(this->m_GeometryShaderhandle); } public: //シェーダ―のSlot番目のレジスタに情報をセット(Slot>=4) void SetGeometryCameraMatrix(int Slot, const MATRIX& World, const MATRIX& View, const MATRIX& Projection) noexcept { if (GetUseDirect3DVersion() != DX_DIRECT3D_11) { return; } LIGHTCAMERA_MATRIX* LightCameraMatrixConst = (LIGHTCAMERA_MATRIX*)GetBufferShaderConstantBuffer(this->m_GeometryShaderMatcbhandle); LightCameraMatrixConst->WorldMatrix = World; LightCameraMatrixConst->ViewMatrix = View; LightCameraMatrixConst->ProjectionMatrix = Projection; UpdateShaderConstantBuffer(this->m_GeometryShaderMatcbhandle); SetShaderConstantBuffer(this->m_GeometryShaderMatcbhandle, DX_SHADERTYPE_GEOMETRY, Slot); // 影用深度記録画像を描画したときのカメラのビュー行列と射影行列を定数に設定する } //3D空間に適用する場合の関数(引数に3D描画のラムダ式を代入) void Draw_lamda(std::function<void()> doing) noexcept { if (GetUseDirect3DVersion() != DX_DIRECT3D_11) { doing(); return; } SetUseVertexShader(this->m_VertexShaderhandle); // 使用する頂点シェーダーをセット SetUsePixelShader(this->m_PixelShaderhandle); // 使用するピクセルシェーダーをセット SetUseGeometryShader(this->m_GeometryShaderhandle); // 使用するジオメトリシェーダーをセット MV1SetUseOrigShader(TRUE); doing(); MV1SetUseOrigShader(FALSE); SetUseVertexShader(-1); SetUsePixelShader(-1); SetUseGeometryShader(-1); } }; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { ShaderUseClass m_Shader; int ModelHandle = -1; float RotateAngle = 0.f; ChangeWindowMode(TRUE); if (DxLib_Init() < 0) { return -1; } //シェーダー m_Shader.Init("NormalMesh_NoLight/NormalMesh_NoLightVS.vso", "NormalMesh_NoLight/NormalMesh_NoLightPS.pso"); m_Shader.AddGeometryShader("NormalMesh_NoLight/TestGS.pso"); //モデル ModelHandle = MV1LoadModel("NormalMesh_NoLight/NormalBox.mqo"); // ESCキーが押されるまでループ while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0) { MV1SetPosition(ModelHandle, VGet(320.0f, 240.0f, 0.0f)); RotateAngle += 0.02f; MV1SetRotationXYZ(ModelHandle, VGet(0.0f, RotateAngle, 0.0f)); SetDrawScreen(DX_SCREEN_BACK); ClearDrawScreen(); { DrawBox(0, 0, 640, 480, GetColor(255, 255, 255), TRUE); m_Shader.Draw_lamda([&]() { m_Shader.SetGeometryCameraMatrix(4, MV1GetLocalWorldMatrix(ModelHandle), GetCameraViewMatrix(), GetCameraProjectionMatrix()); MV1DrawModel(ModelHandle); }); } ScreenFlip(); } MV1DeleteModel(ModelHandle); m_Shader.Dispose(); DxLib_End(); return 0; }
メンテ
Re: ジオメトリシェーダーのサンプル作成 ( No.3 )
名前:管理人 日時:2024/06/18 00:20

ジオメトリシェーダーは使用したことが無いのでこちらのコードが正しいのかどうかの判断はできないのですが 最初に試すコードとしては少し複雑なのではないでしょうか? まずは頂点シェーダーから受け取った頂点データをそのままピクセルシェーダーに流すような コードで動作確認をしてからより複雑なコードを試してみるのが良いかと思います m(_ _)m
メンテ
Re: ジオメトリシェーダーのサンプル作成 ( No.4 )
名前:名無三 日時:2024/06/18 20:32

ありがとうございます。そのまま出力で試したところ確かに表示されました! ただ、そこからジオメトリシェーダー側を触ってみたところ、SetUseGeometryShaderで囲っているDrawModelではなくスクリーン座標に効果が適用されてしまいました… 無論ジオメトリシェーダーにワールドビュープロジェクションの演算を移した場合はそもそも画面にスクリーンが映らなくなるような状態です。 スクリーンのポリゴンではなくモデルのポリゴンに対してジオメトリシェーダーを適用する方法はありますでしょうか…?
メンテ
Re: ジオメトリシェーダーのサンプル作成 ( No.5 )
名前:名無三 日時:2024/06/19 23:33

試行後のものです。 ・頂点演算を頂点シェーダーに戻しました ・以下の形でもう1枚ポリゴンを出すようにGSを変更しました ・(あとから)頂点、ピクセルシェーダーの使用モデルを4_0に修正 SetUseGeometryShaderを行うタイミングが違う等でしょうか… drive.google.com/file/d/1JgxMOQHlp2va4YELxOiNVzHUwXKxffyN/view?usp=sharing [maxvertexcount(6)] // ジオメトリシェーダーで出力する最大頂点数 // ジオメトリシェーダー void main(triangle GS_INPUT In[3], // トライアングル リストを構成する頂点配列の入力情報 inout TriangleStream<PS_INPUT> TriStream // 頂点情報を追加するためのストリームオブジェクト ) { PS_INPUT Out; int i; // もとの頂点を出力 for (i = 0; i < 3; i++) { // ローカル座標のセット Out.pos = In[i].Position; Out.norm = In[i].norm; // 頂点を追加する TriStream.Append(Out); } TriStream.RestartStrip(); // もとの頂点を出力 for (i = 0; i < 3; i++) { // ローカル座標のセット Out.pos = In[i].Position+1.f; Out.norm = In[i].norm; // 頂点を追加する TriStream.Append(Out); } // 現在のストリップを終了し、新しいストリップを開始する。 TriStream.RestartStrip(); }
メンテ
Re: ジオメトリシェーダーのサンプル作成 ( No.6 )
名前:管理人 日時:2024/06/19 23:47

ソースファイルをアップして頂きありがとうございます すみません、ジオメトリシェーダーを使用した MV1DrawModel による描画の後に2Dの描画処理を何も行わずに ScreenFlip を実行すると ScreenFlip の処理にもジオメトリシェーダーが適用されてしまうというバグがありました 修正版をアップしましたので、お手数で申し訳ありませんがよろしければお試しください m(_ _;m https://dxlib.xsrv.jp/temp/DxLibVCTest.zip // Windows版 VisualC++ 用
メンテ
Re: ジオメトリシェーダーのサンプル作成 ( No.7 )
名前:名無三(解決) 日時:2024/06/20 00:15

ありがとうございます、モデルの方にてGSのポリゴン追加が動作しました! 後々になりますがファーシェーダーなどのサンプルを作成させていただきます
メンテ
Re: ジオメトリシェーダーのサンプル作成 ( No.8 )
名前:名無三(解決) 日時:2024/06/23 20:27

こちらシェル法によるジオメトリシェーダーを使用したファーシェーダーのサンプルができましたので共有いたします。 drive.google.com/file/d/1CG01dC-WXnl3Sk8Id5Z9S_Up5mwvaX2_/view?usp=sharing
メンテ
Re: ジオメトリシェーダーのサンプル作成 ( No.9 )
名前:管理人(解決) 日時:2024/06/25 01:35

サンプルの共有ありがとうございます! 拝見してみましたが見事にファーシェーダーが実現できていますね… GSは本当に最低限の機能しかないのに使いこなされていて凄いです (・・;;
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存