質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
DLL

DLL(Dynamic Link Library)とは、他のモジュールからも使用する事が出来る、関数とデータが格納されているモジュールのことです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

DirectX

DirectX(ダイレクトエックス)は、 マイクロソフトが開発したゲーム・マルチメディア処理用のAPIの集合です。

Q&A

解決済

1回答

2154閲覧

DirectXで描画しているdllから取り込んだRawDataがUnity上でRGB値がおかしくなる

Aya_program

総合スコア30

DLL

DLL(Dynamic Link Library)とは、他のモジュールからも使用する事が出来る、関数とデータが格納されているモジュールのことです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

DirectX

DirectX(ダイレクトエックス)は、 マイクロソフトが開発したゲーム・マルチメディア処理用のAPIの集合です。

0グッド

0クリップ

投稿2020/11/18 07:22

編集2020/11/18 10:24

DirectXで描画しているdllから取り込んだRawDataがUnity上でRGB値がおかしくなる

test.dllを作成しました
test.dllはD3D9を使用し描画を出力します

--やりたいこと--
Unity上からdllで描画したデータをバックバッファから取得し
RawImageとして変換してUnity上のUIとして出力したいです

--問題点--
それっぽい値は取れていてUnity上で描画することはできている
しかしながら、上下左右反転かつRGB値がおかしい
上下左右反転はUnity上のセットしているマテリアルの設定項目:TillingのYを-1とすることで対応しました

--聞きたいこと--
RGB値がおかしいのはdllの抽出している値とUnity上のセットしている型式に問題があるのか
それとも、マテリアルの設定がおかしいのかを知りたい
マテリアルはUnity上で作成してからTillingのYを-1とする以外の変更は加えていません

以下プログラムから抜粋

dllから一部抜粋
GetTex関数

C++

1 2 3 unsigned char* m_dest; 4 5 D3DLOCKED_RECT rect; 6 m_pDestTarget->LockRect(&rect, NULL, D3DLOCK_READONLY); 7 m_dest = static_cast<unsigned char*>(rect.pBits); 8 memcpy(data, dest, sizeof(unsigned char) * 720 * 720 * 4); 9 m_pDestTarget->UnlockRect(); 10 11 return data; 12 13

Unityから一部抜粋

C#

1 2 3using System; 4using System.Collections; 5using System.Collections.Generic; 6using System.Runtime.InteropServices; 7using UnityEngine; 8using UnityEngine.UI; 9 10public class GetAppWindow : MonoBehaviour 11{ 12 13 [SerializeField] 14 private Material mat2; 15 [SerializeField] 16 private Texture2D texRGBA; 17 private byte[] imageRawDataRGBA; 18 private IntPtr imageDataRGBA; 19 20 [SerializeField] 21 RawImage img; 22 23 // Use this for initialization 24 void Start() 25 { 26 this.texRGBA = new Texture2D(720, 720, TextureFormat.RGBA32, false); // RGBA画像 27 this.imageDataRGBA = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(byte)) * 720 * 720 * 4); 28 this.imageRawDataRGBA = new byte[720 * 720 * 4]; 29 30 } 31 32 // Update is called once per frame 33 void Update() 34 { 35 36 imageDataRGBA = GetTex(); 37 Marshal.Copy(imageDataRGBA, this.imageRawDataRGBA, 0, 720 * 720 * 4); 38 this.texRGBA.LoadRawTextureData(this.imageRawDataRGBA); 39 this.texRGBA.Apply(); 40 this.mat2.mainTexture = this.texRGBA; 41 this.img.texture = this.texRGBA; 42 43 } 44}

追記
現在RawImageのマテリアルに反映させていますがテクスチャに反映しようと試みてみもうまくいきません
this.img.texture = this.texRGBA;ここでRawImageにテクスチャでセットしていると思うのですが・・・
RawImageのコンポーネントのマテリアルにセットする場合はうまく描画されています
このマテリアルはUnity上で新規作成したものをD&Dしています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Bongo

2020/11/18 09:17

DirectXは経験がなくて的外れ、あるいは経験者にとっては当たり前なことをきいてしまうかもしれませんが、DLL側のバックバッファのフォーマットはどうなっているでしょうかね? といいますのも、検索してみたところ「ホイール欲しい ハンドル欲しい » OpenGL/DirectX のピクセル並びの順番」(https://wlog.flatlib.jp/item/1512 )との記事が引っかかりまして、「RGB値がおかしい」とおっしゃるのが「赤と青が逆転している」とかでしたらこういった事情が関係しているかもしれないと思ったのです。もしそうだとすると、DLL側とUnity側のフォーマットを合わせたり、あるいは自前で並べ替える必要があるかもしれませんね...
Aya_program

2020/11/18 09:45

回答ありがとうございます dll側ではD3DFMT_X8R8G8B8 Unity側ARGB32 となっています 試しにRGBA32に変更してみました ARGB32:RとBが入れ替わっている RGBA32:RとGが入れ替わっている となっていました destの中身を見てみるとdest[i*4] = 0となっているのでサイズ自体はあっているようですが・・・
Aya_program

2020/11/18 09:50

そもそもRawImageのTexutureに設定しても反映されないのはなぜなのでしょうか
Bongo

2020/11/18 10:05

では「BGRA32」だとどうなるでしょうか。それと、「this.img.texture = this.texRGBA;」だとうまくいかない件についてはちょっと可能性が思い当たりませんね...「Unityから一部抜粋」のコードの全文をお出しいただくことは可能でしょうか(字数制限だとかできついでしょうか)?
Aya_program

2020/11/18 10:26

Unity側の抜粋ですがdllを呼び出す関数の詳細が違うだけでほぼこのソースとなっています 「this.img.texture = this.texRGBA;」だとうまくいかないときのUnity上のアタッチは GetAppWindow スクリプトの mat2,texRGBAには何もアタッチせずに imgへRawImageコンポーネントをアタッチするだけで大丈夫でしょうか?
Aya_program

2020/11/18 10:30

BGRA32というのもあったのですね・・・ これにしたら色合いは完全に治りました ただ「this.img.texture = this.texRGBA;」だとうまくいかない件はちょっときになります
Bongo

2020/11/18 10:44

なるほど、フォーマットは「BGRA32」 で一致しそうですね。あいにく今はUnityをいじれる時間がなく、のちほど「this.img.texture = this.texRGBA;」がダメな可能性について検討してみようと思います。それにあたっておうかがいしたいのですが、コード中の「mat2」というのがRawImageにセットしてあるマテリアルということでいいでしょうか。そして、そのマテリアルのシェーダーはなにを使用していますでしょうか。もし独自のシェーダーを書いた場合、そのコードもご提示いただけるとヒントになるかもしれません。
guest

回答1

0

ベストアンサー

追記依頼欄で申し上げたようにDirect3Dのことに疎いため、認識が間違っているかもしれませんのでご注意願います。

まずRGBの狂いについてはフォーマットの違いということで説明できそうですね。D3DFORMAT (D3D9Types.h) - Win32 apps | Microsoft Docsによると...

All formats are listed from left to right, most-significant bit to least-significant bit. For example, D3DFORMAT_ARGB is ordered from the most-significant bit channel A (alpha), to the least-significant bit channel B (blue). When traversing surface data, the data is stored in memory from least-significant bit to most-significant bit, which means that the channel order in memory is from least-significant bit (blue) to most-significant bit (alpha).

とのことで、D3DFMT_X8R8G8B8ならばメモリ上のデータは「B G R X B G R X ...」となっているはずであり、データのサイズとRGBの並びがTextureFormat.BGRA32と同じになっていると言えそうです。

同じくリファレンスのUnsigned Formatsの節によると、D3DFMT_X8R8G8B8

32-bit RGB pixel format, where 8 bits are reserved for each color.

とのことでした。「X8」の8ビットについては何か意味のある役割があるのか、0で埋められているのか、あるいはどんな値が入っているかは不定なのか...といったことは、すみませんが知識不足につきわかりませんでした(まあ、多分使っていないんでしょう)。

データをTextureFormat.BGRA32形式のテクスチャに詰めた場合、この8ビットのXはアルファチャンネルと見なされるはずです。
ご質問者さんが「現在RawImageのマテリアルに反映させていますがテクスチャに反映しようと試みてみもうまくいきません」とおっしゃる現象のうち、「テクスチャに反映」の方...つまりthis.img.texture = this.texRGBA;を試したときの状況についてうかがいますが、もしかしてこのときにはRaw Imageのマテリアルを「None」にしていたんじゃないでしょうか?
仮にそうだとすれば、テクスチャは半透明に対応したデフォルトのシェーダーでレンダリングされるはずですから、Xが0ならピクセルは消えてしまうでしょうし、変な値が入っていればそれに応じて半透明に見えるでしょう。

また「現在RawImageのマテリアルに反映させていますが」のときのマテリアルでは、「Unlit/Texture」のようなアルファチャンネルを使用しないタイプのシェーダーを使っていたのではないでしょうか?
そうであれば、マテリアルにテクスチャをセットしたときにはアルファチャンネルが無視されてうまく描画された...と説明できそうです。

上記のような心当たりがありましたら、Raw Imageのマテリアルとして最初から「現在RawImageのマテリアルに反映させていますが」のときのマテリアルをセットしておけばthis.img.texture = this.texRGBA;でもうまく描画されるんじゃないかと思います(ちなみに、テクスチャオブジェクト自体を生成しなおしたりはせず中身のデータを更新するだけであれば、最初に一度だけthis.img.texture = this.texRGBA;でテクスチャをセットしてやれば十分なはずです)。
それだとマスクだとかが効かなくて困る...といった事情がありましたら、組み込みのUI用シェーダーをベースに下記のようなアルファチャンネルを強制的に1にしてしまうマテリアルを作るのがいいかと思います。

ShaderLab

1// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt) 2 3Shader "UI/IgnoreAlpha" 4{ 5 Properties 6 { 7 [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} 8 _Color ("Tint", Color) = (1,1,1,1) 9 _StencilComp ("Stencil Comparison", Float) = 8 10 _Stencil ("Stencil ID", Float) = 0 11 _StencilOp ("Stencil Operation", Float) = 0 12 _StencilWriteMask ("Stencil Write Mask", Float) = 255 13 _StencilReadMask ("Stencil Read Mask", Float) = 255 14 _ColorMask ("Color Mask", Float) = 15 15 } 16 17 SubShader 18 { 19 Tags 20 { 21 "Queue"="Transparent" 22 "IgnoreProjector"="True" 23 "RenderType"="Transparent" 24 "PreviewType"="Plane" 25 "CanUseSpriteAtlas"="True" 26 } 27 28 Stencil 29 { 30 Ref [_Stencil] 31 Comp [_StencilComp] 32 Pass [_StencilOp] 33 ReadMask [_StencilReadMask] 34 WriteMask [_StencilWriteMask] 35 } 36 37 Cull Off 38 Lighting Off 39 ZWrite Off 40 ZTest [unity_GUIZTestMode] 41 Blend One Zero 42 ColorMask [_ColorMask] 43 44 Pass 45 { 46 Name "Default" 47 CGPROGRAM 48 #pragma vertex vert 49 #pragma fragment frag 50 #pragma target 2.0 51 52 #include "UnityCG.cginc" 53 #include "UnityUI.cginc" 54 55 #pragma multi_compile_local _ UNITY_UI_CLIP_RECT 56 57 struct appdata_t 58 { 59 float4 vertex : POSITION; 60 float4 color : COLOR; 61 float2 texcoord : TEXCOORD0; 62 UNITY_VERTEX_INPUT_INSTANCE_ID 63 }; 64 65 struct v2f 66 { 67 float4 vertex : SV_POSITION; 68 fixed4 color : COLOR; 69 float2 texcoord : TEXCOORD0; 70 float4 worldPosition : TEXCOORD1; 71 half4 mask : TEXCOORD2; 72 UNITY_VERTEX_OUTPUT_STEREO 73 }; 74 75 sampler2D _MainTex; 76 fixed4 _Color; 77 fixed4 _TextureSampleAdd; 78 float4 _ClipRect; 79 float4 _MainTex_ST; 80 float _MaskSoftnessX; 81 float _MaskSoftnessY; 82 83 v2f vert(appdata_t v) 84 { 85 v2f OUT; 86 UNITY_SETUP_INSTANCE_ID(v); 87 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); 88 float4 vPosition = UnityObjectToClipPos(v.vertex); 89 OUT.worldPosition = v.vertex; 90 OUT.vertex = vPosition; 91 float2 pixelSize = vPosition.w; 92 pixelSize /= float2(1, 1) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy)); 93 float4 clampedRect = clamp(_ClipRect, -2e10, 2e10); 94 float2 maskUV = (v.vertex.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy); 95 OUT.texcoord = float4(v.texcoord.x, v.texcoord.y, maskUV.x, maskUV.y); 96 OUT.mask = half4(v.vertex.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_MaskSoftnessX, _MaskSoftnessY) + abs(pixelSize.xy))); 97 OUT.color = v.color * _Color; 98 return OUT; 99 } 100 101 fixed4 frag(v2f IN) : SV_Target 102 { 103 half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color; 104 color.a = 1.0; 105 #ifdef UNITY_UI_CLIP_RECT 106 half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(IN.mask.xy)) * IN.mask.zw); 107 color.a *= m.x * m.y; 108 #endif 109 clip(color.a - 0.5); 110 111 return color; 112 } 113 ENDCG 114 } 115 } 116}

テクスチャの上下が逆転してしまう件については、Tilingの設定で問題なければそれでかまわないと思います。おそらく座標系の違いに起因するのでしょう。
Texture Coordinates (Direct3D 9) - Win32 apps | Microsoft Docsの図を見ますに、Direct3Dでは原点が左上なんでしょうね。プラットフォーム特有のレンダリングの違い - Unity マニュアルにも環境による差異や、それを吸収するための考慮事項が載っていました。

投稿2020/11/18 20:47

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Aya_program

2020/11/19 01:11

おそくなりました 詳しい解説ありがとうございます まさしくアルファ値が0になっておりそれを反映した結果描画されていないという状態でした とても分かりやすい回答で細かい解説が本当に助かりました ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問