using UnityEngine; using System.Collections.Generic; using System; using Oculus.Avatar; public class OvrAvatarSkinnedMeshPBSV2RenderComponent : OvrAvatarRenderComponent { private OvrAvatarMaterialManager avatarMaterialManager; private bool previouslyActive = false; private bool isCombinedMaterial = false; private ovrAvatarExpressiveParameters ExpressiveParameters; private bool EnableExpressive = false; private int blendShapeCount = 0; private ovrAvatarBlendShapeParams blendShapeParams; private const string MAIN_MATERIAL_NAME = "main_material"; private const string EYE_MATERIAL_NAME = "eye_material"; private const string DEFAULT_MATERIAL_NAME = "_material"; internal void Initialize( IntPtr renderPart, ovrAvatarRenderPart_SkinnedMeshRenderPBS_V2 skinnedMeshRender, OvrAvatarMaterialManager materialManager, int thirdPersonLayer, int firstPersonLayer, bool combinedMesh, ovrAvatarAssetLevelOfDetail lod, bool assignExpressiveParams, OvrAvatar avatar, bool isControllerModel) { avatarMaterialManager = materialManager; isCombinedMaterial = combinedMesh; mesh = CreateSkinnedMesh( skinnedMeshRender.meshAssetID, skinnedMeshRender.visibilityMask, thirdPersonLayer, firstPersonLayer); EnableExpressive = assignExpressiveParams; #if UNITY_ANDROID var singleComponentShader = EnableExpressive ? avatar.Skinshaded_Expressive_VertFrag_SingleComponent : avatar.Skinshaded_VertFrag_SingleComponent; #else var singleComponentShader = EnableExpressive ? avatar.Skinshaded_Expressive_SurfaceShader_SingleComponent : avatar.Skinshaded_SurfaceShader_SingleComponent; #endif var combinedComponentShader = EnableExpressive ? avatar.Skinshaded_Expressive_VertFrag_CombinedMesh : avatar.Skinshaded_VertFrag_CombinedMesh; var mainShader = isCombinedMaterial ? combinedComponentShader : singleComponentShader; if (isControllerModel) { mainShader = avatar.ControllerShader; } AvatarLogger.Log("OvrAvatarSkinnedMeshPBSV2RenderComponent Shader is: " + mainShader != null ? mainShader.name : "null"); if (EnableExpressive) { ExpressiveParameters = CAPI.ovrAvatar_GetExpressiveParameters(avatar.sdkAvatar); var eyeShader = avatar.EyeLens; Material[] matArray = new Material[2]; matArray[0] = CreateAvatarMaterial(gameObject.name + MAIN_MATERIAL_NAME, mainShader); matArray[1] = CreateAvatarMaterial(gameObject.name + EYE_MATERIAL_NAME, eyeShader); if (avatar.UseTransparentRenderQueue) { SetMaterialTransparent(matArray[0]); } else { SetMaterialOpaque(matArray[0]); } // Eye lens shader queue is transparent and set from shader matArray[1].renderQueue = -1; mesh.materials = matArray; } else { mesh.sharedMaterial = CreateAvatarMaterial(gameObject.name + DEFAULT_MATERIAL_NAME, mainShader); if (avatar.UseTransparentRenderQueue && !isControllerModel) { SetMaterialTransparent(mesh.sharedMaterial); } else { SetMaterialOpaque(mesh.sharedMaterial); } } bones = mesh.bones; if (isCombinedMaterial) { avatarMaterialManager.SetRenderer(mesh); InitializeCombinedMaterial(renderPart, (int)lod); avatarMaterialManager.OnCombinedMeshReady(); } blendShapeParams = new ovrAvatarBlendShapeParams(); blendShapeParams.blendShapeParamCount = 0; blendShapeParams.blendShapeParams = new float[64]; blendShapeCount = mesh.sharedMesh.blendShapeCount; } public void UpdateSkinnedMeshRender( OvrAvatarComponent component, OvrAvatar avatar, IntPtr renderPart) { ovrAvatarVisibilityFlags visibilityMask = CAPI.ovrAvatarSkinnedMeshRenderPBSV2_GetVisibilityMask(renderPart); ovrAvatarTransform localTransform = CAPI.ovrAvatarSkinnedMeshRenderPBSV2_GetTransform(renderPart); UpdateSkinnedMesh(avatar, bones, localTransform, visibilityMask, renderPart); bool isActive = gameObject.activeSelf; if (mesh != null && !previouslyActive && isActive) { if (!isCombinedMaterial) { InitializeSingleComponentMaterial(renderPart, (int)avatar.LevelOfDetail - 1); } } if (blendShapeCount > 0) { const float BLEND_MULTIPLIER = 100.0f; CAPI.ovrAvatarSkinnedMeshRender_GetBlendShapeParams(renderPart, ref blendShapeParams); for (uint i = 0; i < blendShapeParams.blendShapeParamCount && i < blendShapeCount; i++) { float value = blendShapeParams.blendShapeParams[i]; mesh.SetBlendShapeWeight((int)i, value * BLEND_MULTIPLIER); } } previouslyActive = isActive; } private void InitializeSingleComponentMaterial(IntPtr renderPart, int lodIndex) { ovrAvatarPBSMaterialState materialState = CAPI.ovrAvatarSkinnedMeshRenderPBSV2_GetPBSMaterialState(renderPart); int componentType = (int)OvrAvatarMaterialManager.GetComponentType(gameObject.name); Texture2D diffuseTexture = OvrAvatarComponent.GetLoadedTexture(materialState.albedoTextureID); Texture2D normalTexture = OvrAvatarComponent.GetLoadedTexture(materialState.normalTextureID); Texture2D metallicTexture = OvrAvatarComponent.GetLoadedTexture(materialState.metallicnessTextureID); if (diffuseTexture != null) { avatarMaterialManager.AddTextureIDToTextureManager(materialState.albedoTextureID, true); } else { diffuseTexture = OvrAvatarSDKManager.Instance.GetTextureCopyManager().FallbackTextureSets[lodIndex].DiffuseRoughness; } diffuseTexture.anisoLevel = 4; if (normalTexture != null) { avatarMaterialManager.AddTextureIDToTextureManager(materialState.normalTextureID, true); } else { normalTexture = OvrAvatarSDKManager.Instance.GetTextureCopyManager().FallbackTextureSets[lodIndex].Normal; } normalTexture.anisoLevel = 4; if (metallicTexture != null) { avatarMaterialManager.AddTextureIDToTextureManager(materialState.metallicnessTextureID, true); } else { metallicTexture = OvrAvatarSDKManager.Instance.GetTextureCopyManager().FallbackTextureSets[lodIndex].DiffuseRoughness; } metallicTexture.anisoLevel = 16; mesh.materials[0].SetTexture(OvrAvatarMaterialManager.AVATAR_SHADER_MAINTEX, diffuseTexture); mesh.materials[0].SetTexture(OvrAvatarMaterialManager.AVATAR_SHADER_NORMALMAP, normalTexture); mesh.materials[0].SetTexture(OvrAvatarMaterialManager.AVATAR_SHADER_ROUGHNESSMAP, metallicTexture); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_COLOR, materialState.albedoMultiplier); mesh.materials[0].SetFloat(OvrAvatarMaterialManager.AVATAR_SHADER_DIFFUSEINTENSITY, OvrAvatarMaterialManager.DiffuseIntensities[componentType]); mesh.materials[0].SetFloat(OvrAvatarMaterialManager.AVATAR_SHADER_RIMINTENSITY, OvrAvatarMaterialManager.RimIntensities[componentType]); mesh.materials[0].SetFloat(OvrAvatarMaterialManager.AVATAR_SHADER_REFLECTIONINTENSITY, OvrAvatarMaterialManager.ReflectionIntensities[componentType]); mesh.GetClosestReflectionProbes(avatarMaterialManager.ReflectionProbes); if (avatarMaterialManager.ReflectionProbes != null && avatarMaterialManager.ReflectionProbes.Count > 0) { mesh.materials[0].SetTexture(OvrAvatarMaterialManager.AVATAR_SHADER_CUBEMAP, avatarMaterialManager.ReflectionProbes[0].probe.texture); } if (EnableExpressive) { mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_IRIS_COLOR, ExpressiveParameters.irisColor); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_LIP_COLOR, ExpressiveParameters.lipColor); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_BROW_COLOR, ExpressiveParameters.browColor); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_LASH_COLOR, ExpressiveParameters.lashColor); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_SCLERA_COLOR, ExpressiveParameters.scleraColor); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_GUM_COLOR, ExpressiveParameters.gumColor); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_TEETH_COLOR, ExpressiveParameters.teethColor); mesh.materials[0].SetFloat(OvrAvatarMaterialManager.AVATAR_SHADER_LIP_SMOOTHNESS, ExpressiveParameters.lipSmoothness); } } private void InitializeCombinedMaterial(IntPtr renderPart, int lodIndex) { ovrAvatarPBSMaterialState[] materialStates = CAPI.ovrAvatar_GetBodyPBSMaterialStates(renderPart); if (materialStates.Length == (int)ovrAvatarBodyPartType.Count) { avatarMaterialManager.CreateTextureArrays(); var localProperties = avatarMaterialManager.LocalAvatarConfig.ComponentMaterialProperties; AvatarLogger.Log("InitializeCombinedMaterial - Loading Material States"); for (int i = 0; i < materialStates.Length; i++) { localProperties[i].TypeIndex = (ovrAvatarBodyPartType)i; localProperties[i].Color = materialStates[i].albedoMultiplier; localProperties[i].DiffuseIntensity = OvrAvatarMaterialManager.DiffuseIntensities[i]; localProperties[i].RimIntensity = OvrAvatarMaterialManager.RimIntensities[i]; localProperties[i].ReflectionIntensity = OvrAvatarMaterialManager.ReflectionIntensities[i]; var diffuse = OvrAvatarComponent.GetLoadedTexture(materialStates[i].albedoTextureID); var normal = OvrAvatarComponent.GetLoadedTexture(materialStates[i].normalTextureID); var roughness = OvrAvatarComponent.GetLoadedTexture(materialStates[i].metallicnessTextureID); if (diffuse != null) { localProperties[i].Textures[(int)OvrAvatarMaterialManager.TextureType.DiffuseTextures] = diffuse; avatarMaterialManager.AddTextureIDToTextureManager(materialStates[i].albedoTextureID, false); } else { localProperties[i].Textures[(int)OvrAvatarMaterialManager.TextureType.DiffuseTextures] = OvrAvatarSDKManager.Instance.GetTextureCopyManager().FallbackTextureSets[lodIndex].DiffuseRoughness; } localProperties[i].Textures[(int)OvrAvatarMaterialManager.TextureType.DiffuseTextures].anisoLevel = 4; if (normal != null) { localProperties[i].Textures[(int)OvrAvatarMaterialManager.TextureType.NormalMaps] = normal; avatarMaterialManager.AddTextureIDToTextureManager(materialStates[i].normalTextureID, false); } else { localProperties[i].Textures[(int)OvrAvatarMaterialManager.TextureType.NormalMaps] = OvrAvatarSDKManager.Instance.GetTextureCopyManager().FallbackTextureSets[lodIndex].Normal; } localProperties[i].Textures[(int)OvrAvatarMaterialManager.TextureType.NormalMaps].anisoLevel = 4; if (roughness != null) { localProperties[i].Textures[(int)OvrAvatarMaterialManager.TextureType.RoughnessMaps] = roughness; avatarMaterialManager.AddTextureIDToTextureManager(materialStates[i].metallicnessTextureID, false); } else { localProperties[i].Textures[(int)OvrAvatarMaterialManager.TextureType.RoughnessMaps] = OvrAvatarSDKManager.Instance.GetTextureCopyManager().FallbackTextureSets[lodIndex].DiffuseRoughness; } localProperties[i].Textures[(int)OvrAvatarMaterialManager.TextureType.RoughnessMaps].anisoLevel = 16; AvatarLogger.Log(localProperties[i].TypeIndex.ToString()); AvatarLogger.Log(AvatarLogger.Tab + "Diffuse: " + materialStates[i].albedoTextureID); AvatarLogger.Log(AvatarLogger.Tab + "Normal: " + materialStates[i].normalTextureID); AvatarLogger.Log(AvatarLogger.Tab + "Metallic: " + materialStates[i].metallicnessTextureID); } if (EnableExpressive) { mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_IRIS_COLOR, ExpressiveParameters.irisColor); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_LIP_COLOR, ExpressiveParameters.lipColor); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_BROW_COLOR, ExpressiveParameters.browColor); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_LASH_COLOR, ExpressiveParameters.lashColor); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_SCLERA_COLOR, ExpressiveParameters.scleraColor); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_GUM_COLOR, ExpressiveParameters.gumColor); mesh.materials[0].SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_TEETH_COLOR, ExpressiveParameters.teethColor); mesh.materials[0].SetFloat(OvrAvatarMaterialManager.AVATAR_SHADER_LIP_SMOOTHNESS, ExpressiveParameters.lipSmoothness); } avatarMaterialManager.ValidateTextures(materialStates); } } private void SetMaterialTransparent(Material mat) { // Initialize shader to use transparent render queue with alpha blending mat.SetOverrideTag("Queue", "Transparent"); mat.SetOverrideTag("RenderType", "Transparent"); mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); mat.EnableKeyword("_ALPHATEST_ON"); mat.EnableKeyword("_ALPHABLEND_ON"); mat.EnableKeyword("_ALPHAPREMULTIPLY_ON"); mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent; } private void SetMaterialOpaque(Material mat) { // Initialize shader to use geometry render queue with no blending mat.SetOverrideTag("Queue", "Geometry"); mat.SetOverrideTag("RenderType", "Opaque"); mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); mat.DisableKeyword("_ALPHATEST_ON"); mat.DisableKeyword("_ALPHABLEND_ON"); mat.DisableKeyword("_ALPHAPREMULTIPLY_ON"); mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry; } }