我一直在尝试将 Seefront 3D API 与 XNA 一起使用。Seefront 向 f.ex 提供 3D 面板。索尼提供裸眼3D。这些面板会折射光线,一束光射入您的一只眼睛,另一束射入另一只眼睛。
这基本上是如何工作的,API 中的眼动追踪软件会计算出你两只眼睛的位置。然后 API 调用接管渲染:对 sfdx_setTextures 的调用然后采用 2 个 IDirect3DTexture9* 纹理,然后由 API 中的像素着色器处理。
在较早的 C++ 项目中,我向 MPC-HC 添加了功能,正是这样做的:https ://github.com/atlaste/mpc-hc/tree/master/src/filters/renderer/VideoRenderers 。
现在我正试图用 XNA 做一些新奇的事情,结果遇到了告密者。不幸的是,我无法共享 Seefront DLL;他们不是我要放弃的......代码必须做(我在这里删除了检查等)。
DLL 首先使用 LoadLibrary 加载,并通过一些无聊的调用来启用互操作。
this.dllHandle = Win32NativeMethods.LoadLibrary(@"C:\Program Files (x86)\Sony\SeeFront3D\seefront_ilace_dx.dll");
// Initialize; LoadFunction basically calls GetProcAddress
this.CreateInstance = LoadFunction<CreateInstanceFunc>(dllHandle, "sfdx_createInstance");
this.StartTrackerUpdate = LoadFunction<StartTrackerUpdateFunc>(dllHandle, "sfdx_startTrackerUpdate");
this.SetTextures = LoadFunction<SetTexturesFunc>(dllHandle, "sfdx_setTextures");
this.SetTextureSize = LoadFunction<SetTextureSizeFunc>(dllHandle, "sfdx_setTextureSize");
// etc...
结果是一堆封装在委托中的调用。通过使用 IDirect3DDevice9* 和 StartTrackerUpdate 调用 CreateInstance 来进行初始化。这是 XNA 没有给我们需要的第一点,所以 API 初始化如下:
// Get pComPtr from device
var ptr = device.GetType().GetField("pComPtr", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var d3ddevice = (Pointer)ptr.GetValue(device);
var ptrValue = Pointer.Unbox(d3ddevice);
// Create seefront instance
this.instance = CreateInstance((IDirect3DDevice9*)ptrValue);
StartTrackerUpdate(instance);
调用这两个后,摄像头被启用,这表明它是活着的。这留下了最后一件事:对 SetTexture 的调用。因为它是传递给 API 并且可能未复制的指针数组,所以我在堆上分配了一些指针(使用 IDisposable 处理),并通过凌乱的 GetComPtr 调用再次获取 IDirect3DTexture9* 指针:
// initialization:
realTextures = (IDirect3DTexture9**)Marshal.AllocHGlobal(IntPtr.Size * 2);
// ...
private IDirect3DTexture9** realTextures;
public void RenderFrame(Texture texture1, Texture texture2)
{
MethodInfo textureMethod = typeof(Texture).GetMethod("GetComPtr", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var ptr = (Pointer)textureMethod.Invoke(texture1, null);
realTextures[0] = (IDirect3DTexture9*)Pointer.Unbox(ptr);
ptr = (Pointer)textureMethod.Invoke(texture2, null);
realTextures[1] = (IDirect3DTexture9*)Pointer.Unbox(ptr);
SetTextures(instance, realTextures, 2, 0, 0, 1, 1);
Render(instance);
Sync(instance);
}
上面所有的混乱都包含在一个名为 SeeFront3D 的小类中,该类从 XNA 应用程序中调用。
接下来是在 XNA 中渲染一些东西。因为 API 接受两个纹理,所以我基本上使用http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series3/Render_to_texture.php中描述的方法在“游戏”的绘制阶段创建这些纹理。
此代码如下所示:
private SeeFront3D sf3d;
private RenderTarget2D[] eyeTextures;
private int currentEyeTexture = 0;
protected override void LoadContent()
{
InitializeModel();
InitializeEffect();
if (EnableSeefront3D)
{
sf3d = new SeeFront3D(GraphicsDevice, Window);
}
eyeTextures = new RenderTarget2D[4];
for (int i = 0; i < 4; ++i)
{
eyeTextures[i] = new RenderTarget2D(GraphicsDevice, 1980, 1080, true, GraphicsDevice.DisplayMode.Format, DepthFormat.Depth24Stencil8);
}
}
// ...
protected override void Draw(GameTime gameTime)
{
// render right eye; normally you render both eyes, but this is for testing.
GraphicsDevice.SetRenderTarget(rightEye);
GraphicsDevice.Clear(Color.CornflowerBlue);
Render();
GraphicsDevice.SetRenderTarget(null);
GraphicsDevice.Clear(Color.CornflowerBlue);
if (EnableSeefront3D)
{
sf3d.SetTextureDimensions(1980, 1080);
sf3d.RenderFrame(rightEye, rightEye);
// Thread.Sleep(TimeSpan.FromSeconds(1.0)); // used for debugging
}
else
{
GraphicsDevice.Clear(Color.CornflowerBlue);
using (SpriteBatch sprite = new SpriteBatch(GraphicsDevice))
{
sprite.Begin();
sprite.Draw(rightEye, new Vector2(0, 0), null, Color.White, 0, new Vector2(0, 0), 0.4f, SpriteEffects.None, 1);
sprite.End();
}
}
base.Draw(gameTime);
}
private void Render()
{
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
}
GraphicsDevice.Indices = indexBuffer;
GraphicsDevice.SetVertexBuffer(vertexBuffer);
graphics.GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList, 0, 0, this.vertexBuffer.VertexCount, 0, this.indexBuffer.IndexCount / 3);
}
当然,我尝试过不同的变体,例如在左眼用一种颜色调用“清晰”,在右眼用另一种颜色调用,等等。
会发生以下情况:
- 清除似乎工作正常。如果你用两种颜色填充两只眼睛,你就会得到完全正确的结果。
- 如果你改变颜色,它仍然可以正常工作。
- 你可以看到 Seefront 的像素着色器在做他们的工作。如果你改变位置,屏幕上的像素也会改变位置。
- 如果将 EnableSeefront3D 标志设置为“false”,则可以看到渲染正常
但是(问题):
- 绘制循环的第一次迭代,你会得到一个“灰色”屏幕。
- 3D 模型仅在绘制循环的第二次迭代中呈现(我通过 'sleep' 调用解决了这个问题)
- 在绘制循环的第 2 次迭代之后,仅渲染背景(来自 'clear');3D模型不见了。
我个人认为第一帧是 SeeFront 库中的一个小错误,绝对是我可以忍受的。
如果启动应用程序,它看起来像这样:
从乱码看,可以清楚的看到调用了Seefront库;3D 模型在第一帧之后也明显消失了。
有什么建议会出什么问题 cq 如何解决这个问题?