动态改变StandardShader的RenderingMode让模型透明

如何用脚本动态的改变Unity5中标准材质的渲染模式,让模型透明?

先上代码:

SetMaterialRenderingMode.cs

using UnityEngine;
using System.Collections;

//设置材质的渲染模式
public class SetMaterialRenderingMode : MonoBehaviour {

    public Material mat;

	void Start () {
        setMaterialRenderingMode(mat, RenderingMode.Fade);
	}

    public enum RenderingMode{
        Opaque,
        Cutout,
        Fade,
        Transparent
    }

    //设置材质的渲染模式
    private void setMaterialRenderingMode(Material material, RenderingMode renderingMode){
        switch (renderingMode){
            case RenderingMode.Opaque:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = -1;
                break;
            case RenderingMode.Cutout:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.EnableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 2450;
                break;
            case RenderingMode.Fade:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.EnableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
            case RenderingMode.Transparent:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
        }
    }
	
}

最近在做项目的时候遇到了一个需要动态切换模型透明、不透明效果的功能。unity4.x的时候是切换材质的shader,但是现在unity5的标准材质已经可以切换渲染模式了,那么肯定有方法在不更换shader的前提下直接切换材质的透明、不透明效果。自己花了不少时间,尝试设置Material和Shader的属性,发现都没有实现效果,很是挠头啊,肯定是有哪些地方没有弄明白导致失败,因为在编辑模式下,Inspector面板中标准材质已经提供了一个切换渲染模式的功能按钮,Rendering Mode,可以实现透明和不透明之间的切换,而且有4种模式。那么答案肯定就在这个UI的源代码里。在网上查了不少资料,发现标准材质的UI脚本叫做StandardShaderGUI.cs,又经过一番搜索终于在一个外国论坛帖子的回复中找到了外国同行分享的标准材质GUI的源代码,这个源代码已经被外国友人改过了,所以有些地方可能和官方源代码有些出入,不过大部分应该相同,先上代码:

CustomStandardShaderGUI.cs

using System;
using UnityEngine;
 
namespace UnityEditor
{
    internal class CustomStandardShaderGUI : ShaderGUI
{
    private enum WorkflowMode
    {
        Specular,
        Metallic,
        Dielectric
    }
 
    public enum BlendMode
    {
        Opaque,
        Cutout,
        Fade,        // Old school alpha-blending mode, fresnel does not affect amount of transparency
        Transparent // Physically plausible transparency mode, implemented as alpha pre-multiply
    }
 
    private static class Styles
    {
        public static GUIStyle optionsButton = "PaneOptions";
        public static GUIContent uvSetLabel = new GUIContent("UV Set");
        public static GUIContent[] uvSetOptions = new GUIContent[] { new GUIContent("UV channel 0"), new GUIContent("UV channel 1") };
 
        public static string emptyTootip = "";
        public static GUIContent albedoText = new GUIContent("Albedo", "Albedo (RGB) and Transparency (A)");
        public static GUIContent alphaCutoffText = new GUIContent("Alpha Cutoff", "Threshold for alpha cutoff");
        public static GUIContent specularMapText = new GUIContent("Specular", "Specular (RGB) and Smoothness (A)");
        public static GUIContent metallicMapText = new GUIContent("Metallic", "Metallic (R) and Smoothness (A)");
        public static GUIContent smoothnessText = new GUIContent("Smoothness", "");
        public static GUIContent normalMapText = new GUIContent("Normal Map", "Normal Map");
        public static GUIContent heightMapText = new GUIContent("Height Map", "Height Map (G)");
        public static GUIContent occlusionText = new GUIContent("Occlusion", "Occlusion (G)");
        public static GUIContent emissionText = new GUIContent("Emission", "Emission (RGB)");
        public static GUIContent detailMaskText = new GUIContent("Detail Mask", "Mask for Secondary Maps (A)");
        public static GUIContent detailAlbedoText = new GUIContent("Detail Albedo x2", "Albedo (RGB) multiplied by 2");
        public static GUIContent detailNormalMapText = new GUIContent("Normal Map", "Normal Map");
 
        public static string whiteSpaceString = " ";
        public static string primaryMapsText = "Main Maps";
        public static string secondaryMapsText = "Secondary Maps";
        public static string renderingMode = "Rendering Mode";
        public static GUIContent emissiveWarning = new GUIContent ("Emissive value is animated but the material has not been configured to support emissive. Please make sure the material itself has some amount of emissive.");
        public static GUIContent emissiveColorWarning = new GUIContent ("Ensure emissive color is non-black for emission to have effect.");
        public static readonly string[] blendNames = Enum.GetNames (typeof (BlendMode));
    }
 
    MaterialProperty blendMode = null;
    MaterialProperty albedoMap = null;
    MaterialProperty albedoColor = null;
    MaterialProperty alphaCutoff = null;
    MaterialProperty specularMap = null;
    MaterialProperty specularColor = null;
    MaterialProperty metallicMap = null;
    MaterialProperty metallic = null;
    MaterialProperty smoothness = null;
    MaterialProperty bumpScale = null;
    MaterialProperty bumpMap = null;
    MaterialProperty occlusionStrength = null;
    MaterialProperty occlusionMap = null;
    MaterialProperty heigtMapScale = null;
    MaterialProperty heightMap = null;
    MaterialProperty emissionScaleUI = null;
    MaterialProperty emissionColorUI = null;
    MaterialProperty emissionColorForRendering = null;
    MaterialProperty emissionMap = null;
    MaterialProperty detailMask = null;
    MaterialProperty detailAlbedoMap = null;
    MaterialProperty detailNormalMapScale = null;
    MaterialProperty detailNormalMap = null;
    MaterialProperty uvSetSecondary = null;
 
    MaterialEditor m_MaterialEditor;
    WorkflowMode m_WorkflowMode = WorkflowMode.Specular;
 
    bool m_FirstTimeApply = true;
 
    public void FindProperties (MaterialProperty[] props)
    {
        blendMode = FindProperty ("_Mode", props);
        albedoMap = FindProperty ("_MainTex", props);
        albedoColor = FindProperty ("_Color", props);
        alphaCutoff = FindProperty ("_Cutoff", props);
        specularMap = FindProperty ("_SpecGlossMap", props, false);
        specularColor = FindProperty ("_SpecColor", props, false);
        metallicMap = FindProperty ("_MetallicGlossMap", props, false);
        metallic = FindProperty ("_Metallic", props, false);
        if (specularMap != null && specularColor != null)
            m_WorkflowMode = WorkflowMode.Specular;
        else if (metallicMap != null && metallic != null)
            m_WorkflowMode = WorkflowMode.Metallic;
        else
            m_WorkflowMode = WorkflowMode.Dielectric;
        smoothness = FindProperty ("_Glossiness", props);
        bumpScale = FindProperty ("_BumpScale", props);
        bumpMap = FindProperty ("_BumpMap", props);
        heigtMapScale = FindProperty ("_Parallax", props);
        heightMap = FindProperty("_ParallaxMap", props);
        occlusionStrength = FindProperty ("_OcclusionStrength", props);
        occlusionMap = FindProperty ("_OcclusionMap", props);
        emissionScaleUI = FindProperty ("_EmissionScaleUI", props);
        emissionColorUI = FindProperty ("_EmissionColorUI", props);
        emissionColorForRendering = FindProperty ("_EmissionColor", props);
        emissionMap = FindProperty ("_EmissionMap", props);
        detailMask = FindProperty ("_DetailMask", props);
        detailAlbedoMap = FindProperty ("_DetailAlbedoMap", props);
        detailNormalMapScale = FindProperty ("_DetailNormalMapScale", props);
        detailNormalMap = FindProperty ("_DetailNormalMap", props);
        uvSetSecondary = FindProperty ("_UVSec", props);
    }
 
    public override void OnGUI (MaterialEditor materialEditor, MaterialProperty[] props)
    {
        FindProperties (props); // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly
        m_MaterialEditor = materialEditor;
        Material material = materialEditor.target as Material;
 
        ShaderPropertiesGUI (material);
 
        // Make sure that needed keywords are set up if we're switching some existing
        // material to a standard shader.
        if (m_FirstTimeApply)
        {
            SetMaterialKeywords (material, m_WorkflowMode);
            m_FirstTimeApply = false;
        }
    }
 
    public void ShaderPropertiesGUI (Material material)
    {
        // Use default labelWidth
        EditorGUIUtility.labelWidth = 0f;
 
        // Detect any changes to the material
        EditorGUI.BeginChangeCheck();
        {
            BlendModePopup();
 
            // Primary properties
            GUILayout.Label (Styles.primaryMapsText, EditorStyles.boldLabel);
            DoAlbedoArea(material);
            DoSpecularMetallicArea();
            m_MaterialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap, bumpMap.textureValue != null ? bumpScale : null);
            m_MaterialEditor.TexturePropertySingleLine(Styles.heightMapText, heightMap, heightMap.textureValue != null ? heigtMapScale : null);
            m_MaterialEditor.TexturePropertySingleLine(Styles.occlusionText, occlusionMap, occlusionMap.textureValue != null ? occlusionStrength : null);
            DoEmissionArea(material);
            m_MaterialEditor.TexturePropertySingleLine(Styles.detailMaskText, detailMask);
            EditorGUI.BeginChangeCheck();
            m_MaterialEditor.TextureScaleOffsetProperty(albedoMap);
            if (EditorGUI.EndChangeCheck())
                emissionMap.textureScaleAndOffset = albedoMap.textureScaleAndOffset; // Apply the main texture scale and offset to the emission texture as well, for Enlighten's sake
 
            EditorGUILayout.Space();
 
            // Secondary properties
            GUILayout.Label(Styles.secondaryMapsText, EditorStyles.boldLabel);
            m_MaterialEditor.TexturePropertySingleLine(Styles.detailAlbedoText, detailAlbedoMap);
            m_MaterialEditor.TexturePropertySingleLine(Styles.detailNormalMapText, detailNormalMap, detailNormalMapScale);
            m_MaterialEditor.TextureScaleOffsetProperty(detailAlbedoMap);
            m_MaterialEditor.ShaderProperty(uvSetSecondary, Styles.uvSetLabel.text);
 
            EditorGUILayout.Space();
 
        }
        if (EditorGUI.EndChangeCheck())
        {
            foreach (var obj in blendMode.targets)
                MaterialChanged((Material)obj, m_WorkflowMode);
        }
    }
 
    internal void DetermineWorkflow(MaterialProperty[] props)
    {
        if (FindProperty("_SpecGlossMap", props, false) != null && FindProperty("_SpecColor", props, false) != null)
            m_WorkflowMode = WorkflowMode.Specular;
        else if (FindProperty("_MetallicGlossMap", props, false) != null && FindProperty("_Metallic", props, false) != null)
            m_WorkflowMode = WorkflowMode.Metallic;
        else
            m_WorkflowMode = WorkflowMode.Dielectric;
    }
 
    public override void AssignNewShaderToMaterial (Material material, Shader oldShader, Shader newShader)
    {
        base.AssignNewShaderToMaterial(material, oldShader, newShader);
 
        if (oldShader == null || !oldShader.name.Contains("Legacy Shaders/"))
            return;
 
        BlendMode blendMode = BlendMode.Opaque;
        if (oldShader.name.Contains("/Transparent/Cutout/"))
        {
            blendMode = BlendMode.Cutout;
        }
        else if (oldShader.name.Contains("/Transparent/"))
        {
            // NOTE: legacy shaders did not provide physically based transparency
            // therefore Fade mode
            blendMode = BlendMode.Fade;
        }
        material.SetFloat("_Mode", (float)blendMode);
 
        //DetermineWorkflow( ShaderUtil.GetMaterialProperties(new Material[] { material }) );
        MaterialChanged(material, m_WorkflowMode);
    }
 
    void BlendModePopup()
    {
        EditorGUI.showMixedValue = http://blog.youkuaiyun.com/zhangyukof/article/details/blendMode.hasMixedValue;
        var mode = (BlendMode)blendMode.floatValue;
        EditorGUI.BeginChangeCheck();
        mode = (BlendMode)EditorGUILayout.Popup(Styles.renderingMode, (int)mode, Styles.blendNames);
        if (EditorGUI.EndChangeCheck())
        {
            m_MaterialEditor.RegisterPropertyChangeUndo("Rendering Mode");
            blendMode.floatValue = http://blog.youkuaiyun.com/zhangyukof/article/details/(float)mode;
        }
 
        EditorGUI.showMixedValue = false;
    }
 
    void DoAlbedoArea(Material material)
    {
        m_MaterialEditor.TexturePropertySingleLine(Styles.albedoText, albedoMap, albedoColor);
        if (((BlendMode)material.GetFloat("_Mode") == BlendMode.Cutout))
        {
            m_MaterialEditor.ShaderProperty(alphaCutoff, Styles.alphaCutoffText.text, MaterialEditor.kMiniTextureFieldLabelIndentLevel+1);
        }
    }
 
    void DoEmissionArea(Material material)
    {
        bool showEmissionColorAndGIControls = emissionScaleUI.floatValue > 0f;
        bool hadEmissionTexture = emissionMap.textureValue != null;
 
        // Do controls
        m_MaterialEditor.TexturePropertySingleLine(Styles.emissionText, emissionMap, showEmissionColorAndGIControls ? emissionColorUI : null, emissionScaleUI);
 
        // Set default emissionScaleUI if texture was assigned
        if (emissionMap.textureValue != null && !hadEmissionTexture && emissionScaleUI.floatValue <= 0f)
            emissionScaleUI.floatValue = http://blog.youkuaiyun.com/zhangyukof/article/details/1.0f;
 
        // Dynamic Lightmapping mode
        if (showEmissionColorAndGIControls)
        {
            bool shouldEmissionBeEnabled = ShouldEmissionBeEnabled(EvalFinalEmissionColor(material));
            EditorGUI.BeginDisabledGroup(!shouldEmissionBeEnabled);
 
            m_MaterialEditor.LightmapEmissionProperty (MaterialEditor.kMiniTextureFieldLabelIndentLevel + 1);
 
            EditorGUI.EndDisabledGroup();
        }
 
        if (!HasValidEmissiveKeyword(material))
        {
            EditorGUILayout.HelpBox(Styles.emissiveWarning.text, MessageType.Warning);
        }
 
    }
 
    void DoSpecularMetallicArea()
    {
        if (m_WorkflowMode == WorkflowMode.Specular)
        {
            if (specularMap.textureValue == null)
                m_MaterialEditor.TexturePropertyTwoLines(Styles.specularMapText, specularMap, specularColor, Styles.smoothnessText, smoothness);
            else
                m_MaterialEditor.TexturePropertySingleLine(Styles.specularMapText, specularMap);
 
        }
        else if (m_WorkflowMode == WorkflowMode.Metallic)
        {
            if (metallicMap.textureValue == null)
                m_MaterialEditor.TexturePropertyTwoLines(Styles.metallicMapText, metallicMap, metallic, Styles.smoothnessText, smoothness);
            else
                m_MaterialEditor.TexturePropertySingleLine(Styles.metallicMapText, metallicMap);
        }
    }
 
    public static void SetupMaterialWithBlendMode(Material material, BlendMode blendMode)
    {
        switch (blendMode)
        {
            case BlendMode.Opaque:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = -1;
                break;
            case BlendMode.Cutout:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.EnableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 2450;
                break;
            case BlendMode.Fade:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.EnableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
            case BlendMode.Transparent:
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
        }
    }
 
    // Calculate final HDR _EmissionColor (gamma space) from _EmissionColorUI (LDR, gamma) & _EmissionScaleUI (gamma)
    static Color EvalFinalEmissionColor(Material material)
    {
        return material.GetColor("_EmissionColorUI") * material.GetFloat("_EmissionScaleUI");
    }
 
    static bool ShouldEmissionBeEnabled (Color color)
    {
        return color.grayscale > (0.1f / 255.0f);
    }
 
    static void SetMaterialKeywords(Material material, WorkflowMode workflowMode)
    {
        // Note: keywords must be based on Material value not on MaterialProperty due to multi-edit & material animation
        // (MaterialProperty value might come from renderer material property block)
        SetKeyword (material, "_NORMALMAP", material.GetTexture ("_BumpMap") || material.GetTexture ("_DetailNormalMap"));
        if (workflowMode == WorkflowMode.Specular)
            SetKeyword (material, "_SPECGLOSSMAP", material.GetTexture ("_SpecGlossMap"));
        else if (workflowMode == WorkflowMode.Metallic)
            SetKeyword (material, "_METALLICGLOSSMAP", material.GetTexture ("_MetallicGlossMap"));
        SetKeyword (material, "_PARALLAXMAP", material.GetTexture ("_ParallaxMap"));
        SetKeyword (material, "_DETAIL_MULX2", material.GetTexture ("_DetailAlbedoMap") || material.GetTexture ("_DetailNormalMap"));
 
        bool shouldEmissionBeEnabled = ShouldEmissionBeEnabled (material.GetColor("_EmissionColor"));
        SetKeyword (material, "_EMISSION", shouldEmissionBeEnabled);
 
        // Setup lightmap emissive flags
        MaterialGlobalIlluminationFlags flags = material.globalIlluminationFlags;
        if ((flags & (MaterialGlobalIlluminationFlags.BakedEmissive | MaterialGlobalIlluminationFlags.RealtimeEmissive)) != 0)
        {
            flags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack;
            if (!shouldEmissionBeEnabled)
                flags |= MaterialGlobalIlluminationFlags.EmissiveIsBlack;
 
            material.globalIlluminationFlags = flags;
        }
    }
 
    bool HasValidEmissiveKeyword (Material material)
    {
        // Material animation might be out of sync with the material keyword.
        // So if the emission support is disabled on the material, but the property blocks have a value that requires it, then we need to show a warning.
        // (note: (Renderer MaterialPropertyBlock applies its values to emissionColorForRendering))
        bool hasEmissionKeyword = material.IsKeywordEnabled ("_EMISSION");
        if (!hasEmissionKeyword && ShouldEmissionBeEnabled (emissionColorForRendering.colorValue))
            return false;
        else
            return true;
    }
 
    static void MaterialChanged(Material material, WorkflowMode workflowMode)
    {
        // Clamp EmissionScale to always positive
        if (material.GetFloat("_EmissionScaleUI") < 0.0f)
            material.SetFloat("_EmissionScaleUI", 0.0f);
 
        // Apply combined emission value
        Color emissionColorOut = EvalFinalEmissionColor (material);
        material.SetColor("_EmissionColor", emissionColorOut);
 
        // Handle Blending modes
        SetupMaterialWithBlendMode(material, (BlendMode)material.GetFloat("_Mode"));
 
        SetMaterialKeywords(material, workflowMode);
    }
 
    static void SetKeyword(Material m, string keyword, bool state)
    {
        if (state)
            m.EnableKeyword (keyword);
        else
            m.DisableKeyword (keyword);
    }
}
 
} // namespace UnityEditor

搜索了一下RenderingMode的相关能容,在代码的283行找到了SetupMaterialWithBlendMode方法,这个方法中的内容就是我们切换渲染模式用到的代码了,整理后代码就是文章最上方的setMaterialRenderingMode方法了,有两个参数,第一个是材质,二个是渲染模式。

OK,问题解决。

<think>我们正在处理一个关于Unity中渲染顺序的问题,用户希望让模型位于特效(粒子)的上层。根据引用[3]的内容,我们知道在Unity中控制渲染顺序的几种方式,包括Camera的Depth、Sorting LayerOrder in Layer、RenderQueue等。结合用户的需求引用中的信息,我们可以提供以下解决方案: 1. **使用不同的摄像机渲染模型特效**:通过调整摄像机的Depth值,让渲染模型的摄像机在渲染特效的摄像机之后渲染,这样后渲染的模型就会覆盖在先渲染的特效之上[^3]。 2. **使用Sorting LayerOrder in Layer**:如果模型特效都是使用2D渲染器(比如SpriteRenderer),那么可以通过设置Sorting LayerOrder in Layer来控制渲染顺序。将模型的Sorting Layer设置为比特效更高的层,或者在同一层中设置更高的Order in Layer值。 3. **调整Shader的RenderQueue**:通过修改模型特效所用材质的RenderQueue值,将模型的RenderQueue设置得比特效大,这样模型就会在特效之后渲染,从而显示在上层[^2][^3]。注意,在Unity中,透明物体的渲染顺序是从后往前,不透明物体是从前往后,因此需要确保两者都是透明物体或者使用相同的渲染队列类型。 4. **利用NGUI/UGUI的Panel Depth**:如果特效模型需要在UI中显示,可以借助NGUI或UGUI的Panel Depth来控制。将模型放在一个Depth值更大的Panel中,这样该Panel中的内容就会渲染在Depth值较小的Panel(包含特效)之上[^2]。 具体选择哪种方法取决于项目的具体情况(例如使用的是2D还是3D,是否使用UI系统等)。 下面提供一些具体的操作步骤: ### 方法1:使用摄像机深度(Camera Depth) 1. 创建两个摄像机:一个用于渲染特效(粒子系统),另一个用于渲染模型。 2. 将特效所在层(Layer)设置为只被特效摄像机渲染,模型所在层设置为只被模型摄像机渲染。 3. 设置模型摄像机的Depth值大于特效摄像机的Depth值(因为摄像机按照Depth从小到大顺序渲染)。 ### 方法2:使用Sorting Layer(适用于2D或Sprite) 1. 在Unity的Tags & Layers设置中创建两个Sorting Layer,例如"Effect""Model",确保"Model"在"Effect"上方(通过拖拽调整顺序)。 2. 将粒子系统(特效)的Renderer组件中的Sorting Layer设置为"Effect",模型的Renderer组件(如SpriteRenderer)中的Sorting Layer设置为"Model"。 3. 如果需要更细粒度的控制,可以调整Order in Layer。 ### 方法3:调整RenderQueue(通过材质) 1. 选择模型使用的材质,在材质的Inspector面板中,可以找到RenderQueue(可能需要将材质的Shader换成支持RenderQueue调整的,如Standard Shader)。 2. 将模型的材质的RenderQueue设置成一个比特效材质更大的值。例如,默认不透明物体是2000,透明物体是3000。如果特效的RenderQueue是3000,那么将模型的RenderQueue设置为3001(注意:这个值必须在透明物体的范围内,即大于2500)。 3. 注意:如果使用自定义Shader,可以在Shader中直接设置`Tags { "Queue"="Transparent+1" }`,这样就会在默认透明物体之后渲染。 ### 方法4:使用UI Panel(适用于NGUI/UGUI) 1. 如果模型特效需要作为UI元素显示,可以将它们放在不同的UIPanel(NGUI)或Canvas(UGUI)中。 2. 调整Panel/Canvas的Depth(NGUI)或Sort Order(UGUI)值,使模型所在的Panel/Canvas的Depth值大于特效所在的Panel/Canvas。 3. 在UGUI中,还可以通过设置Canvas的Sorting LayerOrder in Layer来控制。 ### 注意事项 - 如果模型特效都是3D物体,方法1(摄像机深度)方法3(RenderQueue)比较常用。 - 如果特效是粒子系统,注意粒子系统默认使用透明材质,所以需要确保模型的材质也在透明队列(Transparent Queue)中,否则可能无法正确覆盖。 - 在调整RenderQueue时,如果模型原来是不透明物体,改为透明队列后可能需要修改Shader以支持透明混合。 根据引用[2]中提到的Automatic模式,在NGUI中,我们可以通过调整UIPanel的Depth来间接控制RenderQueue,但这种方法主要适用于UI元素。对于3D模型特效,更直接的方法是调整材质的RenderQueue或使用多个摄像机。 希望以上方法能够解决您的问题。 §§相关问题§§ 1. 如何在Unity中调整多个摄像机的渲染顺序? 2. 如何使用Sorting Layer控制2D精灵的显示层次? 3. 如何修改Unity材质的RenderQueue? 4. 在UGUI中,如何控制3D模型与UI元素的层级关系? </think>### 让模型位于特效上层的解决方案 在Unity中实现模型(3D物体)位于粒子特效上层,本质是通过调整渲染顺序(Render Order)来控制层级关系。以下是四种常用方法,结合引用[3]的原理说明: #### 1. **修改摄像机深度(推荐)** [^3] ```csharp // 创建专用摄像机渲染模型(Depth值需 > 特效摄像机) Camera modelCam = gameObject.AddComponent<Camera>(); modelCam.depth = 1; // 数值大于特效摄像机 modelCam.cullingMask = LayerMask.GetMask("ModelLayer"); // 仅渲染模型层 ``` - **原理**:Unity按摄像机`Depth`值从小到大渲染,深度值大的后渲染会覆盖前面的内容 - **步骤**: 1. 创建独立摄像机渲染模型,设置更高`Depth` 2. 特效使用默认摄像机(Depth=0) 3. 将模型分配到专属Layer(如"ModelLayer") #### 2. **调整材质的渲染队列(Render Queue)** [^2][^3] ```csharp // 模型材质设置更高的RenderQueue material.renderQueue = 3001; // 默认特效RenderQueue为3000 ``` - **原理**:Unity按渲染队列值升序绘制,值越大越晚渲染(上层) - **操作**: - 粒子特效材质默认队列:`Transparent (3000)` - 设置模型材质队列为`3001-3100`区间 - **注意**:需使用支持透明队列的Shader(如Standard的`Rendering Mode = Transparent`) #### 3. **Sorting Layer分层控制(适用UI系统)** [^2] ```csharp // UGUI Canvas设置 canvas.sortingLayerName = "Foreground"; canvas.sortingOrder = 10; // 数值 > 特效Canvas ``` - **适用场景**:当模型作为UI元素嵌入时(如角色展示) - **步骤**: 1. 创建模型专用的Canvas 2. 设置比特效更高的`sortingOrder` 3. 将Canvas的`Render Mode`改为`Screen Space - Camera` #### 4. **Shader深度写入控制(进阶方案)** ```hlsl // 模型Shader中添加 ZWrite Off ZTest Always // 强制通过深度测试 ``` - **原理**:关闭深度写入使模型始终通过深度检测,显示在最前 - **风险**:可能引起画面穿透,需配合Stencil Buffer使用 ### 方案选择建议 | 场景 | 推荐方案 | 优势 | |------|----------|------| | 全屏特效覆盖 | 摄像机分层 | 隔离性好,性能稳定 | | 局部特效交互 | 材质队列调整 | 无需额外摄像机 | | UI界面嵌入模型 | Sorting Layer | 与UI系统无缝集成 | > **关键提示**:粒子系统材质必须使用`Transparent`队列(非`AlphaTest`),否则渲染顺序可能异常[^3]。测试时建议开启Frame Debugger查看实际绘制顺序。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值