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

相关文章

使用Redis快速实现共享Session登录的详细步骤

《使用Redis快速实现共享Session登录的详细步骤》在Web开发中,Session通常用于存储用户的会话信息,允许用户在多个页面之间保持登录状态,Redis是一个开源的高性能键值数据库,广泛用于... 目录前言实现原理:步骤:使用Redis实现共享Session登录1. 引入Redis依赖2. 配置R

SpringBoot实现RSA+AES自动接口解密的实战指南

《SpringBoot实现RSA+AES自动接口解密的实战指南》在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题,RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用,本... 目录一、项目依赖与环境准备1.1 Maven依赖配置1.2 密钥生成与配置二、加密工具类实现2.1

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统