快速摘要:
我正在研究VR应用程序,我们希望在VR场景中的3D空间中渲染网站,最好是在纹理上.在桌面(PC / Mac)上有很多种方法可以实现这一点,但在Android设备上却没有.
细节:
我们在Windows上有一个依赖于Zen Fulcrum Embedded Browser plugin的工作原型,但我们希望支持Android设备,如Google DayDream,Gear VR,以及最终将在明年发布的基于Android的独立耳机.
这是我到目前为止找到的所有Unity网页渲染解决方案的列表:
> Embedded Browser by Zen Fulcrum – 支持Windows和OSX
> UniWebView by Yumigi – 他们do not support渲染网页到纹理.网页呈现在图形引擎渲染之上的平面图层上.
> In-App Web Browser by Piotr Zmudzinski – 似乎也有同样的限制
> Webkit for iOS by Chestnut Games – 仅适用于iOS,其公司网站似乎不起作用.
> HTML Engine for NGUI & Unity GUI by ZHing – 似乎不是真正的网络浏览器.看起来有人制作了一些将HTML转换为UI元素的脚本.
> EasyWebViewTexture For Android by JaeYunLee – 我知道有些开发人员使用了这个,但这个项目被神秘地拆除并停止了.
> Awesomium for Unity by Khrona Software – 他们对于Unity的维基文章在他们的wiki site和GitHub都是神秘的空白.entire awesomium website也被关闭了,Krhona Software公司的网站也是如此.他们有一个GitHub Repo用于他们的Unity集成,但他们的自述文件说它只支持Windows&苹果电脑.
> uWebKit3由Mythos Labs提供 – 不再可用.他们的原始网站不再存在.以前版本的uWebKit声称支持Android.关于他们倒闭的Unity论坛上的Their announcement是非常神秘和突然的.我在GitHub发现了一些声称是uWebKit3的东西,但自述文件声称只支持PC和Mac.
> Unreal Engine 4’s Web Browser Widget – 这是一个内置于UE4中的实验性小部件,在桌面上,它在3D世界中呈现网页几乎没有问题.不幸的是,即使它声称支持Android,当你实际部署到一个设备时,你会发现浏览器只是在游戏引擎渲染之上变得平坦,而不是在3D世界中.
我真的找不到任何关于为什么以前在Android上不再支持它的信息了.也许在Android堆栈上有些变化?如果我自己尝试弄乱Chromium并让它在Android上运行,那么我是否会遇到所有这些项目被杀死的死胡同?
Android SDK提供了原生的WebView组件,它被渲染为一个独立的屏幕元素,我们无法真正接触到它.谷歌刚刚发布了Chrome VR browser in Daydream的预览版,但它还处于早期开发阶段,我真的不认为他们计划为VR开发者提供一个即将使用的解决方案. Oculus拥有实验性的Carmel Browser,但似乎更专注于渲染WebVR,而不是为VR开发人员提供工具.我一直与Oculus Web Browser团队的某个人(在PAX遇到他,lol)保持联系,他们计划发布一项功能,让开发人员更容易启动在Gear VR的内置Oculus Web浏览器中打开的网页.但这是一个应用切换方案,它不允许您在自己的3D场景中渲染网页.
我正在考虑探索的一种可能性:如果我们有一台服务器为用户呈现网页并将这些内容作为纹理数据流回设备,该怎么办?它有点像OnLive用电子游戏做的,除了你有时可以容忍更多的延迟.它可以使用Selenium(或其他一些webdev视觉回归测试工具)来处理渲染……呃,这听起来像是一种痛苦,但是,不确定我们公司是否能够花费数月时间来完成这样的事情. -_-
有什么建议?谢谢!
最佳答案 我不确定这个问题是否重复,或者
newer是否重复,但
this是我做的回购,希望我们可以实现一个漂亮的游戏内浏览器.这有点儿/有点慢但它有效(大部分时间).
它使用一个Java插件,通过覆盖视图的Draw方法将Android WebView呈现为Bitmap,将其转换为png并将其传递给统一的RawImage.有很多工作要做,所以随时改进它!
如何使用它:
在repo中,您可以找到需要导入到Assets / Plugins / Android /和BrowserView.cs以及UnityThread.cs的插件(unitylibrary-debug.aar),您可以使用它将Android WebView转换为Unity的RawImage可以使用的纹理显示.适当填写BrowserView.cs的公共字段.确保Unity的播放器设置中的API级别设置为25.
代码示例
这里重写了WebView的Draw方法来创建位图和PNG,并初始化您需要的变量:
public class BitmapWebView extends WebView{
private void init(){
stream = new ByteArrayOutputStream();
array = new ReadData(new byte[]{});
bm = Bitmap.createBitmap(outputWindowWidth,
outputWindowHeight, Bitmap.Config.ARGB_8888);
bmCanvas = new Canvas(bm);
}
@Override
public void draw( Canvas ){
// draw onto a new canvas
super.draw(bmCanvas);
bm.compress(Bitmap.CompressFormat.PNG, 100, stream);
array.Buffer = stream.toByteArray();
UnityBitmapCallback.onFrameUpdate(array,
bm.getWidth(),
bm.getHeight(),
canGoBack,
canGoForward );
stream.reset();
}
}
// you need this class to communicate properly with unity
public class ReadData {
public byte[] Buffer;
public ReadData(byte[] buffer) {
Buffer=buffer;
}
}
然后我们将png传递给统一的RawImage.
这是Unity接收方:
// class used for the callback with the texture
class AndroidBitmapPluginCallback : AndroidJavaProxy
{
public AndroidBitmapPluginCallback() : base("com.unityexport.ian.unitylibrary.PluginInterfaceBitmap") { }
public BrowserView BrowserView;
public void onFrameUpdate(AndroidJavaObject jo, int width, int height, bool canGoBack, bool canGoForward)
{
AndroidJavaObject bufferObject = jo.Get<AndroidJavaObject>("Buffer");
byte[] bytes = AndroidJNIHelper.ConvertFromJNIArray<byte[]>(bufferObject.GetRawObject());
if (bytes == null)
return;
if (BrowserView != null)
{
UnityThread.executeInUpdate(()=> BrowserView.SetTexture(bytes,width,height,canGoBack,canGoForward));
}
else
Debug.Log("TestAndroidPlugin is not set");
}
}
public class BrowserView : MonoBehaviour {
// Browser view needs a RawImage component to display webpages
void Start () {
_imageTexture2D = new Texture2D(Screen.width, Screen.height, TextureFormat.ARGB32, false);
_rawImage = gameObject.GetComponent<RawImage>();
_rawImage.texture = _imageTexture2D;
#if !UNITY_EDITOR && UNITY_ANDROID
// Get your Java class and create a new instance
var tempAjc = new AndroidJavaClass("YOUR_LIBRARY.YOUR_CLASS")
_ajc = tempAjc.CallStatic<AndroidJavaObject>("CreateInstance");
// send the callback object to java to get frame updates
AndroidBitmapPluginCallback androidPluginCallback = new AndroidBitmapPluginCallback {BrowserView = this};
_ajc.Call("SetUnityBitmapCallback", androidPluginCallback);
#endif
}
// Android callback to change our browser view texture
public void SetTexture( byte[] bytes, int width, int height, bool canGoBack, bool canGoForward)
{
if (width != _imageTexture2D.width || height != _imageTexture2D.height)
_imageTexture2D = new Texture2D(width, height, TextureFormat.ARGB32, false);
_imageTexture2D.LoadImage(bytes);
_imageTexture2D.Apply();
_rawImage.texture = _imageTexture2D;
}
}