public static int CreateExternalTexture_s(IntPtr l) { int result; try { int size; LuaObject.checkType(l, 1, out size); TextureFormat format; LuaObject.checkEnum <TextureFormat>(l, 2, out format); bool mipmap; LuaObject.checkType(l, 3, out mipmap); IntPtr nativeTex; LuaObject.checkType(l, 4, out nativeTex); Cubemap o = Cubemap.CreateExternalTexture(size, format, mipmap, nativeTex); LuaObject.pushValue(l, true); LuaObject.pushValue(l, o); result = 2; } catch (Exception e) { result = LuaObject.error(l, e); } return(result); }
/// <summary> /// Create a new <c>Cubemap</c> texture object with the given native texture object. /// </summary> /// <param name="textureDescriptor">The <c>XRTextureDescriptor</c> wrapping a native texture object. /// </param> /// <returns> /// The <c>Cubemap</c> object created from the given native texture object. /// </returns> Cubemap CreateEnvironmentTexture(XRTextureDescriptor textureDescriptor) { Debug.Assert(textureDescriptor.valid, "cannot create a cubemap with an invalid native texture object"); Cubemap cubemap = Cubemap.CreateExternalTexture(textureDescriptor.width, textureDescriptor.format, (textureDescriptor.mipmapCount != 0), textureDescriptor.nativeTexture); cubemap.filterMode = m_EnvironmentTextureFilterMode; return(cubemap); }
static void _ar_session_get_environment_texture_completion_handler(IntPtr callbackPtr, IntPtr texturePtr) { GCHandle handle = GCHandle.FromIntPtr(callbackPtr); var completionCallback = (Action <Cubemap>)handle.Target; if (texturePtr == IntPtr.Zero) { completionCallback(null); } else { completionCallback(Cubemap.CreateExternalTexture(0, TextureFormat.R8, false, texturePtr)); } handle.Free(); }
/// <summary> /// Create the texture object for the native texture wrapped by the valid descriptor. /// </summary> /// <param name="descriptor">The texture descriptor wrapping a native texture object.</param> /// <returns> /// If the descriptor is valid, the <c>Texture</c> object created from the texture descriptor. Otherwise, /// <c>null</c>. /// </returns> static Texture CreateTexture(XRTextureDescriptor descriptor) { if (!descriptor.valid) { return(null); } switch (descriptor.dimension) { #if UNITY_2020_2_OR_NEWER case TextureDimension.Tex3D: return(Texture3D.CreateExternalTexture(descriptor.width, descriptor.height, descriptor.depth, descriptor.format, (descriptor.mipmapCount != 0), descriptor.nativeTexture)); #endif case TextureDimension.Tex2D: var texture = Texture2D.CreateExternalTexture(descriptor.width, descriptor.height, descriptor.format, (descriptor.mipmapCount != 0), k_TextureHasLinearColorSpace, descriptor.nativeTexture); // NB: SetWrapMode needs to be the first call here, and the value passed // needs to be kTexWrapClamp - this is due to limitations of what // wrap modes are allowed for external textures in OpenGL (which are // used for ARCore), as Texture::ApplySettings will eventually hit // an assert about an invalid enum (see calls to glTexParameteri // towards the top of ApiGLES::TextureSampler) // reference: "3.7.14 External Textures" section of // https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image_external.txt // (it shouldn't ever matter what the wrap mode is set to normally, since // this is for a pass-through video texture, so we shouldn't ever need to // worry about the wrap mode as textures should never "wrap") texture.wrapMode = TextureWrapMode.Clamp; texture.filterMode = FilterMode.Bilinear; texture.hideFlags = HideFlags.HideAndDontSave; return(texture); case TextureDimension.Cube: return(Cubemap.CreateExternalTexture(descriptor.width, descriptor.format, (descriptor.mipmapCount != 0), descriptor.nativeTexture)); default: return(null); } }
public Cubemap GetReflectionCubemap(IntPtr sessionHandle, IntPtr lightEstimateHandle) { // Cubemap.CreateExternalTexture only exists in Unity 2017 above. #if UNITY_2017_2_OR_NEWER int textureId = 0; int size = 0; bool usingGLES3 = SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3; TextureFormat format = usingGLES3 ? TextureFormat.RGBAHalf : TextureFormat.RGBA32; if (!m_PluginInitialized) { ExternApi.ARCoreRenderingUtils_SetGLESContext(usingGLES3); m_PluginInitialized = true; } ExternApi.ARCoreRenderingUtils_GetCubemapTexture(ref textureId, ref size); if (textureId != 0) { if (m_HDRCubemap == null || textureId != m_CubemaptextureId) { m_HDRCubemap = Cubemap.CreateExternalTexture(size, format, true, new IntPtr(textureId)); } } long timestamp = GetTimestamp(sessionHandle, lightEstimateHandle); if (m_CubemapTimestamp != timestamp) { ExternApi.ARCoreRenderingUtils_SetARCoreLightEstimation(sessionHandle, lightEstimateHandle); m_CubemapTimestamp = timestamp; } // Issue plugin event to update cubemap texture. GL.IssuePluginEvent(ExternApi.ARCoreRenderingUtils_GetRenderEventFunc(), 1); return(m_HDRCubemap); #else return(null); #endif }
private bool CreateLayerTextures(bool useMipmaps, OVRPlugin.Sizei size, bool isHdr) { if (isExternalSurface) { if (externalSurfaceObject == System.IntPtr.Zero) { externalSurfaceObject = OVRPlugin.GetLayerAndroidSurfaceObject(layerId); if (externalSurfaceObject != System.IntPtr.Zero) { Debug.LogFormat("GetLayerAndroidSurfaceObject returns {0}", externalSurfaceObject); if (externalSurfaceObjectCreated != null) { externalSurfaceObjectCreated(); } } } return(false); } bool needsCopy = false; if (stageCount <= 0) { return(false); } // For newer SDKs, blit directly to the surface that will be used in compositing. if (layerTextures == null) { layerTextures = new LayerTexture[texturesPerStage]; } for (int eyeId = 0; eyeId < texturesPerStage; ++eyeId) { if (layerTextures[eyeId].swapChain == null) { layerTextures[eyeId].swapChain = new Texture[stageCount]; } if (layerTextures[eyeId].swapChainPtr == null) { layerTextures[eyeId].swapChainPtr = new IntPtr[stageCount]; } for (int stage = 0; stage < stageCount; ++stage) { Texture sc = layerTextures[eyeId].swapChain[stage]; IntPtr scPtr = layerTextures[eyeId].swapChainPtr[stage]; if (sc != null && scPtr != IntPtr.Zero && size.w == sc.width && size.h == sc.height) { continue; } if (scPtr == IntPtr.Zero) { scPtr = OVRPlugin.GetLayerTexture(layerId, stage, (OVRPlugin.Eye)eyeId); } if (scPtr == IntPtr.Zero) { continue; } var txFormat = (isHdr) ? TextureFormat.RGBAHalf : TextureFormat.RGBA32; if (currentOverlayShape != OverlayShape.Cubemap && currentOverlayShape != OverlayShape.OffcenterCubemap) { sc = Texture2D.CreateExternalTexture(size.w, size.h, txFormat, useMipmaps, true, scPtr); } #if UNITY_2017_1_OR_NEWER else { sc = Cubemap.CreateExternalTexture(size.w, txFormat, useMipmaps, scPtr); } #endif layerTextures[eyeId].swapChain[stage] = sc; layerTextures[eyeId].swapChainPtr[stage] = scPtr; needsCopy = true; } } return(needsCopy); }
public Cubemap GetReflectionCubemap(IntPtr sessionHandle, IntPtr lightEstimateHandle) { int size = 0; bool usingGammaWorkflow = QualitySettings.activeColorSpace == ColorSpace.Gamma; #if UNITY_2017_2_OR_NEWER // Cubemap.CreateExternalTexture only exists in Unity 2017 above. int textureId = 0; ApiTextureDataType dataType = SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3 ? ApiTextureDataType.Half : ApiTextureDataType.Byte; TextureFormat format = dataType == ApiTextureDataType.Half ? TextureFormat.RGBAHalf : TextureFormat.RGBA32; if (!m_PluginInitialized) { ExternApi.ARCoreRenderingUtils_SetTextureDataType(dataType, true); ExternApi.ARCoreRenderingUtils_SetActiveColorSpace(usingGammaWorkflow); m_PluginInitialized = true; } ExternApi.ARCoreRenderingUtils_GetCubemapTexture(ref textureId, ref size); if (textureId != 0 && (m_HDRCubemap == null || textureId != m_CubemapTextureId)) { m_HDRCubemap = Cubemap.CreateExternalTexture(size, format, true, new IntPtr(textureId)); m_CubemapTextureId = textureId; } long timestamp = GetTimestamp(sessionHandle, lightEstimateHandle); if (m_CubemapTimestamp != timestamp) { ExternApi.ARCoreRenderingUtils_SetARCoreLightEstimation(sessionHandle, lightEstimateHandle); m_CubemapTimestamp = timestamp; } // Issue plugin event to update cubemap texture. GL.IssuePluginEvent(ExternApi.ARCoreRenderingUtils_GetRenderEventFunc(), 1); #else // Gets raw color data from native plugin then update cubemap textures by // Cubemap.SetPixel(). // Note, no GL texture will be created in this scenario. if (!m_PluginInitialized) { ExternApi.ARCoreRenderingUtils_SetTextureDataType( ApiTextureDataType.Float, false); ExternApi.ARCoreRenderingUtils_SetActiveColorSpace(usingGammaWorkflow); m_PluginInitialized = true; } ExternApi.ARCoreRenderingUtils_GetCubemapTexture(ref m_CubemapTextureId, ref size); if (size > 0) { if (m_HDRCubemap == null) { m_HDRCubemap = new Cubemap(size, TextureFormat.RGBAHalf, true); } if (m_TempCubemapFacePixels.Length != size) { Array.Resize(ref m_TempCubemapFacePixels, size * size); } } long timestamp = GetTimestamp(sessionHandle, lightEstimateHandle); if (m_CubemapTimestamp != timestamp) { ExternApi.ARCoreRenderingUtils_SetARCoreLightEstimation(sessionHandle, lightEstimateHandle); m_CubemapTimestamp = timestamp; if (m_HDRCubemap != null) { for (int i = 0; i < 6; i++) { ExternApi.ARCoreRenderingUtils_GetCubemapRawColors(i, m_TempCubemapFacePixels); m_HDRCubemap.SetPixels(m_TempCubemapFacePixels, CubemapFace.PositiveX + i); } // This operation is very expensive, only update cubemap texture when // the light estimate is updated in this frame. m_HDRCubemap.Apply(); } } #endif return(m_HDRCubemap); }
void Awake() { Debug.Log("Overlay Awake"); if (premultiplyMaterial == null) { premultiplyMaterial = new Material(Shader.Find("Oculus/Alpha Premultiply")); } rend = GetComponent <Renderer>(); if (textures.Length == 0) { textures = new Texture[] { null } } ; // Backward compatibility if (rend != null && textures[0] == null) { textures[0] = rend.material.mainTexture; } if (textures[0] != null) { cachedTextures[0] = textures[0]; texNativePtrs[0] = textures[0].GetNativeTexturePtr(); } #if UNITY_ANDROID && !UNITY_EDITOR if (textures.Length == 2 && textures[1] != null) { layout = (isMultiviewEnabled) ? OVRPlugin.LayerLayout.Array : OVRPlugin.LayerLayout.Stereo; } texturesPerStage = (layout == OVRPlugin.LayerLayout.Stereo) ? 2 : 1; #endif } void OnEnable() { if (!OVRManager.isHmdPresent) { enabled = false; return; } OnDisable(); for (int i = 0; i < maxInstances; ++i) { if (instances[i] == null || instances[i] == this) { layerIndex = i; instances[i] = this; break; } } layerIdHandle = GCHandle.Alloc(layerId, GCHandleType.Pinned); layerIdPtr = layerIdHandle.AddrOfPinnedObject(); } void OnDisable() { if (layerIndex != -1) { // Turn off the overlay if it was on. OVRPlugin.EnqueueSubmitLayer(true, false, IntPtr.Zero, IntPtr.Zero, -1, 0, OVRPose.identity.ToPosef(), Vector3.one.ToVector3f(), layerIndex, (OVRPlugin.OverlayShape)_prevOverlayShape); instances[layerIndex] = null; } if (layerIdPtr != IntPtr.Zero) { OVRPlugin.EnqueueDestroyLayer(layerIdPtr); layerIdPtr = IntPtr.Zero; layerIdHandle.Free(); } layerIndex = -1; } int prevFrameIndex = -1; void OnRenderObject() { // The overlay must be specified every eye frame, because it is positioned relative to the // current head location. If frames are dropped, it will be time warped appropriately, // just like the eye buffers. if (!Camera.current.CompareTag("MainCamera") || Camera.current.cameraType != CameraType.Game || layerIndex == -1 || currentOverlayType == OverlayType.None || textures.Length < texturesPerStage) { return; } // Don't submit the same frame twice. if (Time.frameCount <= prevFrameIndex) { return; } prevFrameIndex = Time.frameCount; #if !UNITY_ANDROID || UNITY_EDITOR if (currentOverlayShape == OverlayShape.OffcenterCubemap) { Debug.LogWarning("Overlay shape " + currentOverlayShape + " is not supported on current platform"); } #endif for (int i = 0; i < texturesPerStage; ++i) { if (textures[i] != cachedTextures[i]) { cachedTextures[i] = textures[i]; if (cachedTextures[i] != null) { texNativePtrs[i] = cachedTextures[i].GetNativeTexturePtr(); } } if (currentOverlayShape == OverlayShape.Cubemap) { if (textures[i] != null && textures[i].GetType() != typeof(Cubemap)) { Debug.LogError("Need Cubemap texture for cube map overlay"); return; } } } if (cachedTextures[0] == null || texNativePtrs[0] == IntPtr.Zero) { return; } bool overlay = (currentOverlayType == OverlayType.Overlay); bool headLocked = false; for (var t = transform; t != null && !headLocked; t = t.parent) { headLocked |= (t == Camera.current.transform); } OVRPose pose = (headLocked) ? transform.ToHeadSpacePose() : transform.ToTrackingSpacePose(); Vector3 scale = transform.lossyScale; for (int i = 0; i < 3; ++i) { scale[i] /= Camera.current.transform.lossyScale[i]; } #if !UNITY_ANDROID if (currentOverlayShape == OverlayShape.Cubemap) { pose.position = Camera.current.transform.position; } #endif // Pack the offsetCenter directly into pose.position for offcenterCubemap if (currentOverlayShape == OverlayShape.OffcenterCubemap) { pose.position = transform.position; if (pose.position.magnitude > 1.0f) { Debug.LogWarning("your cube map center offset's magnitude is greater than 1, which will cause some cube map pixel always invisible ."); } } // Cylinder overlay sanity checking if (currentOverlayShape == OverlayShape.Cylinder) { float arcAngle = scale.x / scale.z / (float)Math.PI * 180.0f; if (arcAngle > 180.0f) { Debug.LogError("Cylinder overlay's arc angle has to be below 180 degree, current arc angle is " + arcAngle + " degree."); return; } } OVRPlugin.Sizei size = new OVRPlugin.Sizei() { w = textures[0].width, h = textures[0].height }; int flags = (int)OVRPlugin.LayerFlags.TextureOriginAtBottomLeft; int mipLevels = 1; int sampleCount = 1; TextureFormat txFormat = TextureFormat.BGRA32; OVRPlugin.EyeTextureFormat etFormat = OVRPlugin.EyeTextureFormat.B8G8R8A8_sRGB; RenderTextureFormat rtFormat = RenderTextureFormat.BGRA32; var tex2D = textures[0] as Texture2D; if (tex2D != null) { if (tex2D.format == TextureFormat.RGBAHalf || tex2D.format == TextureFormat.RGBAFloat) { txFormat = TextureFormat.RGBAHalf; etFormat = OVRPlugin.EyeTextureFormat.R16G16B16A16_FP; rtFormat = RenderTextureFormat.ARGBHalf; } } var rt = textures[0] as RenderTexture; if (rt != null) { sampleCount = rt.antiAliasing; if (rt.format == RenderTextureFormat.ARGBHalf) { txFormat = TextureFormat.RGBAHalf; etFormat = OVRPlugin.EyeTextureFormat.R16G16B16A16_FP; rtFormat = RenderTextureFormat.ARGBHalf; } } bool needsSetup = ( !layerDesc.TextureSize.Equals(size) || layerDesc.SampleCount != sampleCount || layerDesc.LayerFlags != flags || layerDesc.Shape != (OVRPlugin.OverlayShape)currentOverlayShape || layerDesc.Layout != layout || layerDesc.Format != etFormat); OVRPlugin.LayerDesc desc = new OVRPlugin.LayerDesc(); if (layerIdPtr != IntPtr.Zero && needsSetup) { if ((int)layerIdHandle.Target != 0) { OVRPlugin.EnqueueDestroyLayer(layerIdPtr); } desc = OVRPlugin.CalculateLayerDesc((OVRPlugin.OverlayShape)currentOverlayShape, layout, size, mipLevels, sampleCount, etFormat, flags); OVRPlugin.EnqueueSetupLayer(desc, layerIdPtr); layerId = (int)layerIdHandle.Target; if (layerId > 0) { layerDesc = desc; } } if (layerId > 0) { // For newer SDKs, blit directly to the surface that will be used in compositing. int stageCount = OVRPlugin.GetLayerTextureStageCount(layerId); if (externalTextures == null) { frameIndex = 0; externalTextures = new Texture[texturesPerStage][]; } for (int eyeId = 0; eyeId < texturesPerStage; ++eyeId) { if (externalTextures[eyeId] == null) { externalTextures[eyeId] = new Texture[stageCount]; } int stage = frameIndex % stageCount; IntPtr externalTex = OVRPlugin.GetLayerTexture(layerId, stage, (OVRPlugin.Eye)eyeId); if (externalTex == IntPtr.Zero) { continue; } bool needsCopy = isDynamic; Texture et = externalTextures[eyeId][stage]; if (et == null) { bool isSrgb = (etFormat == OVRPlugin.EyeTextureFormat.B8G8R8A8_sRGB || etFormat == OVRPlugin.EyeTextureFormat.R8G8B8A8_sRGB); if (currentOverlayShape != OverlayShape.Cubemap && currentOverlayShape != OverlayShape.OffcenterCubemap) { et = Texture2D.CreateExternalTexture(size.w, size.h, txFormat, mipLevels > 1, isSrgb, externalTex); } #if UNITY_2017_1_OR_NEWER else { //et = Cubemap.CreateExternalTexture(size.w, size.h, txFormat, mipLevels > 1, isSrgb, externalTex); et = Cubemap.CreateExternalTexture(size.w, txFormat, isSrgb, externalTex); } #endif externalTextures[eyeId][stage] = et; needsCopy = true; } if (needsCopy) { // The compositor uses premultiplied alpha, so multiply it here. if (currentOverlayShape != OverlayShape.Cubemap && currentOverlayShape != OverlayShape.OffcenterCubemap) { var tempRT = RenderTexture.GetTemporary(size.w, size.h, 0, rtFormat, RenderTextureReadWrite.Default, sampleCount); #if UNITY_ANDROID && !UNITY_EDITOR Graphics.Blit(textures[eyeId], tempRT); //Resolve, decompress, swizzle, etc not handled by simple CopyTexture. #else Graphics.Blit(textures[eyeId], tempRT, premultiplyMaterial); #endif Graphics.CopyTexture(tempRT, 0, 0, et, 0, 0); RenderTexture.ReleaseTemporary(tempRT); } #if UNITY_2017_1_OR_NEWER else { var tempRTSrc = RenderTexture.GetTemporary(size.w, size.h, 0, rtFormat, RenderTextureReadWrite.Default, sampleCount); var tempRTDst = RenderTexture.GetTemporary(size.w, size.h, 0, rtFormat, RenderTextureReadWrite.Default, sampleCount); for (int face = 0; face < 6; ++face) { //HACK: It would be much more efficient to blit directly from textures[eyeId] to et, but Unity's API doesn't support that. //Suggest using a native plugin to render directly to a cubemap layer for 360 video, etc. Graphics.CopyTexture(textures[eyeId], face, 0, tempRTSrc, 0, 0); Graphics.Blit(tempRTSrc, tempRTDst, premultiplyMaterial); Graphics.CopyTexture(tempRTDst, 0, 0, et, face, 0); } RenderTexture.ReleaseTemporary(tempRTSrc); RenderTexture.ReleaseTemporary(tempRTDst); } #endif } } bool isOverlayVisible = OVRPlugin.EnqueueSubmitLayer(overlay, headLocked, texNativePtrs[0], texNativePtrs[1], layerId, frameIndex, pose.flipZ().ToPosef(), scale.ToVector3f(), layerIndex, (OVRPlugin.OverlayShape)currentOverlayShape); if (isDynamic) { ++frameIndex; } _prevOverlayShape = currentOverlayShape; if (rend) { rend.enabled = !isOverlayVisible; } } } }