Unity3D实现指示灯亮灭效果

2023-12-20 17:18

本文主要是介绍Unity3D实现指示灯亮灭效果,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这周有个需求是实现控制指示灯亮灭的效果。实现起来很简单,但是找到这个方法还费了点时间。
先看效果。
最终效果
原理是利用了标准着色器中的自发光属性,通过开关自发光属性来控制灯的亮灭。
具体看步骤:
1.创建一个自发光的材质球,合理设置主要颜色与自发光颜色,金属度Metallic与平滑度Smoothness自己看需求设置
创建自发光材质球
2.再创建一个无自发光的材质球
无自发光材质球
3.如何用代码控制自发光的开关内?
若不想了解从哪儿找到控制的地方的,这一段可以跳过,直接看工程。
既然在编辑器能够勾选自发光,那一定有一个编辑器脚本可以控制这部分。那么这个编辑器脚本在哪儿呢?你需要从unity官网下载你对应版本的内置着色器源码,下载回来的文件夹中Editor文件夹下的StandardShaderGUI.cs即是标准着色器编辑器的源码。

// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)using System;
using UnityEngine;namespace UnityEditor
{internal class StandardShaderGUI : ShaderGUI{private enum WorkflowMode{Specular,Metallic,Dielectric}public enum BlendMode{Opaque,Cutout,Fade,   // Old school alpha-blending mode, fresnel does not affect amount of transparencyTransparent // Physically plausible transparency mode, implemented as alpha pre-multiply}public enum SmoothnessMapChannel{SpecularMetallicAlpha,AlbedoAlpha,}private static class Styles{public static GUIContent uvSetLabel = new GUIContent("UV Set");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", "Smoothness value");public static GUIContent smoothnessScaleText = new GUIContent("Smoothness", "Smoothness scale factor");public static GUIContent smoothnessMapChannelText = new GUIContent("Source", "Smoothness texture and channel");public static GUIContent highlightsText = new GUIContent("Specular Highlights", "Specular Highlights");public static GUIContent reflectionsText = new GUIContent("Reflections", "Glossy Reflections");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("Color", "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 primaryMapsText = "Main Maps";public static string secondaryMapsText = "Secondary Maps";public static string forwardText = "Forward Rendering Options";public static string renderingMode = "Rendering Mode";public static string advancedText = "Advanced Options";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 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 smoothnessScale = null;MaterialProperty smoothnessMapChannel = null;MaterialProperty highlights = null;MaterialProperty reflections = null;MaterialProperty bumpScale = null;MaterialProperty bumpMap = null;MaterialProperty occlusionStrength = null;MaterialProperty occlusionMap = null;MaterialProperty heigtMapScale = null;MaterialProperty heightMap = 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;ColorPickerHDRConfig m_ColorPickerHDRConfig = new ColorPickerHDRConfig(0f, 99f, 1 / 99f, 3f);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;elsem_WorkflowMode = WorkflowMode.Dielectric;smoothness = FindProperty("_Glossiness", props);smoothnessScale = FindProperty("_GlossMapScale", props, false);smoothnessMapChannel = FindProperty("_SmoothnessTextureChannel", props, false);highlights = FindProperty("_SpecularHighlights", props, false);reflections = FindProperty("_GlossyReflections", props, false);bumpScale = FindProperty("_BumpScale", props);bumpMap = FindProperty("_BumpMap", props);heigtMapScale = FindProperty("_Parallax", props);heightMap = FindProperty("_ParallaxMap", props);occlusionStrength = FindProperty("_OcclusionStrength", props);occlusionMap = FindProperty("_OcclusionMap", 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 correctlym_MaterialEditor = materialEditor;Material material = materialEditor.target as Material;// Make sure that needed setup (ie keywords/renderqueue) are set up if we're switching some existing// material to a standard shader.// Do this before any GUI code has been issued to prevent layout issues in subsequent GUILayout statements (case 780071)if (m_FirstTimeApply){MaterialChanged(material, m_WorkflowMode);m_FirstTimeApply = false;}ShaderPropertiesGUI(material);}public void ShaderPropertiesGUI(Material material){// Use default labelWidthEditorGUIUtility.labelWidth = 0f;// Detect any changes to the materialEditorGUI.BeginChangeCheck();{BlendModePopup();// Primary propertiesGUILayout.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);m_MaterialEditor.TexturePropertySingleLine(Styles.detailMaskText, detailMask);DoEmissionArea(material);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 sakeEditorGUILayout.Space();// Secondary propertiesGUILayout.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);// Third propertiesGUILayout.Label(Styles.forwardText, EditorStyles.boldLabel);if (highlights != null)m_MaterialEditor.ShaderProperty(highlights, Styles.highlightsText);if (reflections != null)m_MaterialEditor.ShaderProperty(reflections, Styles.reflectionsText);}if (EditorGUI.EndChangeCheck()){foreach (var obj in blendMode.targets)MaterialChanged((Material)obj, m_WorkflowMode);}EditorGUILayout.Space();GUILayout.Label(Styles.advancedText, EditorStyles.boldLabel);m_MaterialEditor.RenderQueueField();m_MaterialEditor.EnableInstancingField();}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;elsem_WorkflowMode = WorkflowMode.Dielectric;}public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader){// _Emission property is lost after assigning Standard shader to the material// thus transfer it before assigning the new shaderif (material.HasProperty("_Emission")){material.SetColor("_EmissionColor", material.GetColor("_Emission"));}base.AssignNewShaderToMaterial(material, oldShader, newShader);if (oldShader == null || !oldShader.name.Contains("Legacy Shaders/")){SetupMaterialWithBlendMode(material, (BlendMode)material.GetFloat("_Mode"));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 modeblendMode = BlendMode.Fade;}material.SetFloat("_Mode", (float)blendMode);DetermineWorkflow(MaterialEditor.GetMaterialProperties(new Material[] { material }));MaterialChanged(material, m_WorkflowMode);}void BlendModePopup(){EditorGUI.showMixedValue = 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 = (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){// Emission for GI?if (m_MaterialEditor.EmissionEnabledProperty()){bool hadEmissionTexture = emissionMap.textureValue != null;// Texture and HDR color controlsm_MaterialEditor.TexturePropertyWithHDRColor(Styles.emissionText, emissionMap, emissionColorForRendering, m_ColorPickerHDRConfig, false);// If texture was assigned and color was black set color to whitefloat brightness = emissionColorForRendering.colorValue.maxColorComponent;if (emissionMap.textureValue != null && !hadEmissionTexture && brightness <= 0f)emissionColorForRendering.colorValue = Color.white;// change the GI flag and fix it up with emissive as black if necessarym_MaterialEditor.LightmapEmissionFlagsProperty(MaterialEditor.kMiniTextureFieldLabelIndentLevel, true);}}void DoSpecularMetallicArea(){bool hasGlossMap = false;if (m_WorkflowMode == WorkflowMode.Specular){hasGlossMap = specularMap.textureValue != null;m_MaterialEditor.TexturePropertySingleLine(Styles.specularMapText, specularMap, hasGlossMap ? null : specularColor);}else if (m_WorkflowMode == WorkflowMode.Metallic){hasGlossMap = metallicMap.textureValue != null;m_MaterialEditor.TexturePropertySingleLine(Styles.metallicMapText, metallicMap, hasGlossMap ? null : metallic);}bool showSmoothnessScale = hasGlossMap;if (smoothnessMapChannel != null){int smoothnessChannel = (int)smoothnessMapChannel.floatValue;if (smoothnessChannel == (int)SmoothnessMapChannel.AlbedoAlpha)showSmoothnessScale = true;}int indentation = 2; // align with labels of texture propertiesm_MaterialEditor.ShaderProperty(showSmoothnessScale ? smoothnessScale : smoothness, showSmoothnessScale ? Styles.smoothnessScaleText : Styles.smoothnessText, indentation);++indentation;if (smoothnessMapChannel != null)m_MaterialEditor.ShaderProperty(smoothnessMapChannel, Styles.smoothnessMapChannelText, indentation);}public static void SetupMaterialWithBlendMode(Material material, BlendMode blendMode){switch (blendMode){case BlendMode.Opaque:material.SetOverrideTag("RenderType", "");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.SetOverrideTag("RenderType", "TransparentCutout");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 = (int)UnityEngine.Rendering.RenderQueue.AlphaTest;break;case BlendMode.Fade:material.SetOverrideTag("RenderType", "Transparent");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 = (int)UnityEngine.Rendering.RenderQueue.Transparent;break;case BlendMode.Transparent:material.SetOverrideTag("RenderType", "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 = (int)UnityEngine.Rendering.RenderQueue.Transparent;break;}}static SmoothnessMapChannel GetSmoothnessMapChannel(Material material){int ch = (int)material.GetFloat("_SmoothnessTextureChannel");if (ch == (int)SmoothnessMapChannel.AlbedoAlpha)return SmoothnessMapChannel.AlbedoAlpha;elsereturn SmoothnessMapChannel.SpecularMetallicAlpha;}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"));// A material's GI flag internally keeps track of whether emission is enabled at all, it's enabled but has no effect// or is enabled and may be modified at runtime. This state depends on the values of the current flag and emissive color.// The fixup routine makes sure that the material is in the correct state if/when changes are made to the mode or color.MaterialEditor.FixupEmissiveFlag(material);bool shouldEmissionBeEnabled = (material.globalIlluminationFlags & MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0;SetKeyword(material, "_EMISSION", shouldEmissionBeEnabled);if (material.HasProperty("_SmoothnessTextureChannel")){SetKeyword(material, "_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A", GetSmoothnessMapChannel(material) == SmoothnessMapChannel.AlbedoAlpha);}}static void MaterialChanged(Material material, WorkflowMode workflowMode){SetupMaterialWithBlendMode(material, (BlendMode)material.GetFloat("_Mode"));SetMaterialKeywords(material, workflowMode);}static void SetKeyword(Material m, string keyword, bool state){if (state)m.EnableKeyword(keyword);elsem.DisableKeyword(keyword);}}
} // namespace UnityEditor

定位到上述脚本的393行(不同版本的脚本可能不太一样,看具体情况),即是设置自发光是否开启的部分。
在这里插入图片描述
其实就是使用material的EnableKeyword和DisableKeyword来控制_EMISSION属性的开关,知道原理之后写代码就简单了。

using UnityEngine;/// <summary>
/// 指示灯.
/// </summary>
public class HightLED : MonoBehaviour
{private Material mat;private void Awake(){mat = GetComponent<MeshRenderer>().material;}private void Update(){if (Input.GetKeyDown(KeyCode.F1)){SetEmission(mat, true);}if (Input.GetKeyDown(KeyCode.F2)){SetEmission(mat, false);}}private void SetEmission(Material mat, bool emissionOn){if (emissionOn){mat.EnableKeyword("_EMISSION");}else{mat.DisableKeyword("_EMISSION");}}
}

4.建议测试时把场景中内置的天空盒给删除掉,内置天空盒给的光太多,看不出效果。具体步骤见下图。
在这里插入图片描述

在这里插入图片描述
源码上传到GitHub了,见03.HightLight场景。

这篇关于Unity3D实现指示灯亮灭效果的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/516821

相关文章

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal

Nexus安装和启动的实现教程

《Nexus安装和启动的实现教程》:本文主要介绍Nexus安装和启动的实现教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Nexus下载二、Nexus安装和启动三、关闭Nexus总结一、Nexus下载官方下载链接:DownloadWindows系统根

SpringBoot集成LiteFlow实现轻量级工作流引擎的详细过程

《SpringBoot集成LiteFlow实现轻量级工作流引擎的详细过程》LiteFlow是一款专注于逻辑驱动流程编排的轻量级框架,它以组件化方式快速构建和执行业务流程,有效解耦复杂业务逻辑,下面给大... 目录一、基础概念1.1 组件(Component)1.2 规则(Rule)1.3 上下文(Conte

MySQL 横向衍生表(Lateral Derived Tables)的实现

《MySQL横向衍生表(LateralDerivedTables)的实现》横向衍生表适用于在需要通过子查询获取中间结果集的场景,相对于普通衍生表,横向衍生表可以引用在其之前出现过的表名,本文就来... 目录一、横向衍生表用法示例1.1 用法示例1.2 使用建议前面我们介绍过mysql中的衍生表(From子句