OvrAvatarSkinnedMeshRenderPBSV2Component.cs 15.7 KB
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;
    }
}