【Unity3D】激光灯、碰撞特效

news2024/12/23 14:50:47

1 需求描述

        本文将模拟激光灯(或碰撞)特效,详细需求如下:

  • 从鼠标位置发射屏幕射线,检测是否与物体发生碰撞
  • 当与物体发生碰撞时,在物体表面覆盖一层激光灯(或碰撞)特效

        本文代码见→激光灯、碰撞特效

2 原理

        获取屏幕射线与物体的碰撞点,并在 shader 中计算顶点与碰撞点的距离(记为 dist),通过以下衰减函数计算顶点对应的透明度,透明度随碰撞点的距离增大逐渐减小,激光灯(或碰撞)效果逐渐减弱。

alpha = pow(exp(-dist), 4)

        为使特效更加逼真,激光灯(或碰撞)特效的红色分量由以下漫反射公式控制。其中,red 为红色分量值,λ 为漫反射因子,值越大,漫反射效果越强,本文 λ = 0.1;lightDir 为顶点光源向量,normalDir 为顶点法线向量。

red = λ * dot(lightDir, normalDir) + (1 - λ)

3 需求实现

        SelectController.cs

using UnityEngine;
 
public class SelectController : MonoBehaviour { // 单击选中控制
    private Transform target; // 选中的目标
    private RaycastHit hit; // 碰撞信息
 
    private void Update() {
        if (Input.GetMouseButtonUp(0)) {
            Transform temp = GetHitTrans();
            if (temp != target) {
                DrawEffect(target, temp);
                target = temp;
            }
        }
    }

    private void DrawEffect(Transform old, Transform now) { // 绘制特效
        DrawEffect(old, false);
        DrawEffect(now, true);
    }

    private void DrawEffect(Transform trans, bool enable) { // 绘制特效
        if (trans != null) {
            foreach(Transform child in trans.transform.GetComponents<Transform>()) {
                if (child.GetComponent<ColliderEffect>() == null) {
                    if (enable) {
                        child.gameObject.AddComponent<ColliderEffect>();
                    }
                }
                else {
                    child.GetComponent<ColliderEffect>().enabled = enable;
                }
            }
        }
    }
 
    private Transform GetHitTrans() { // 获取屏幕射线碰撞的物体
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out hit)) {
            return hit.transform;
        }
        return null;
    }
}

        ColliderEffect.cs

using System.Collections.Generic;
using System.Linq;
using UnityEngine;

[DisallowMultipleComponent]
public class ColliderEffect : MonoBehaviour { // 激光灯(或碰撞)特效
    private Renderer[] renderers; // 当前对象及其子对象的渲染器
    private Material colliderMaterial; // 激光灯(碰撞)材质
    private Vector4 hitPos; // 碰撞点
    private RaycastHit hit; // 碰撞信息

    private void Awake() {
        renderers = GetComponentsInChildren<Renderer>();
        colliderMaterial = new Material(Shader.Find("MyShader/ColliderEffect"));
        hitPos = Vector4.zero;
    }

    private void OnEnable() {
        hitPos = GetHitPoint();
        colliderMaterial.SetVector("_HitPos", hitPos);
        foreach (var renderer in renderers) {
            List<Material> materials = renderer.sharedMaterials.ToList();
            materials.Add(colliderMaterial);
            renderer.sharedMaterials = materials.ToArray();
        }
    }

    private void Update() {
        hitPos = GetHitPoint();
        if (!hitPos.Equals(Vector4.zero)) {
            colliderMaterial.SetInt("_Enable", 1);
            colliderMaterial.SetVector("_HitPos", hitPos);
        } else {
            colliderMaterial.SetInt("_Enable", 0);
        }
    }

    private void OnDisable() {
        foreach (var renderer in renderers) {
            List<Material> materials = renderer.sharedMaterials.ToList();
            materials.Remove(colliderMaterial);
            renderer.sharedMaterials = materials.ToArray();
        }
    }

    private Vector4 GetHitPoint() {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out hit, 1000) && hit.transform == transform) {
            return hit.point;
        }
        return Vector4.zero;
    }
}

        ColliderEffect.shader

Shader "MyShader/ColliderEffect" {
    Properties {
        _HitPos ("HitPos", Vector) = (0, 0, 0, 0) // 屏幕射线碰撞位置
        _Enable ("Enable", Int) = 0 // 是否开启特效
    }

    SubShader {
        Pass {
            Blend SrcAlpha OneMinusSrcAlpha // 混合测试, 与背后的物体颜色混合

            CGPROGRAM
            #include "UnityCG.cginc"

            #pragma vertex vert
            #pragma fragment frag

            uniform int _Enable;
            uniform float4 _HitPos;
   
            struct appdata {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f {
                float4 posInWorld : TEXCOORD0;
                float4 position : SV_POSITION;
                half3 normal : Normal;
            };

            v2f vert(appdata input) {
                v2f output;
                output.posInWorld = mul(unity_ObjectToWorld, input.vertex);
                output.posInWorld.w = 0;
                output.position = UnityObjectToClipPos(input.vertex);
                output.normal = mul(half4(input.normal, 1), unity_WorldToObject).xyz;
                return output;
            }

            fixed4 frag(v2f input) : SV_Target {
                float3 lightDir = normalize(_WorldSpaceLightPos0); // 光源照射方向向量, 由顶点指向光源
                float3 normalDir = normalize(input.normal);
                float dist = distance(input.posInWorld, _HitPos);
                if(_Enable == 1)
				{
                    float diffuse = 0.1 * dot(lightDir, normalDir) + 0.9; // 漫反射颜色
                    float alpha = pow(exp(-dist), 4); // 透明度(随距离衰减)
                    return float4(diffuse , 0, 0, alpha);
				}
				else
				{
					return float4(0, 0, 0, 0);
				}
            }

            ENDCG
        }
    }
}

4 运行效果

5 推荐阅读

  •  渲染管线
  • 固定管线着色器一
  • 固定管线着色器二
  • 表面着色器
  • 顶点和片段着色器
  • 选中物体描边特效
  • 基于模板测试和顶点膨胀的描边方法
  • 水波特效
  • 半球卷屏特效
  • 卷轴特效

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/190325.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

振弦采集模块VMTool 配置工具的传感器数据读取

振弦采集模块VMTool 配置工具的传感器数据读取 连接传感器 将振弦传感器两根线圈引线分别连接到 VM 模块模块的 SEN和 SEN-两个管脚。 通常不分正负极&#xff0c;任意连接即可。 连接模块电源 使用 5V~12V 直流电源连接到 VM 模块的 VIN 和 GND&#xff0c;电源正极连接到 VIN…

【数据结构基础】树 - 平衡二叉树(AVL)

平衡二叉树&#xff08;Balanced Binary Tree&#xff09;具有以下性质&#xff1a;它是一棵空树或它的左右两个子树的高度差的绝对值不超过1&#xff0c;并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。 最小二叉平…

数学建模与数据分析 || 1. 数学建模简介

数学建模简介 文章目录数学建模简介1. 数学建模比赛的理解2. 一般数据分析的流程3. 机器学习与统计数据分析4. 各种编程软件仅仅是工具&#xff0c;对问题的观察视角和解决问题的策略才是关键2.1 数学建模的特点2.2 以 python&#xff08;jupyter notebook工作界面&#xff09;…

JSR303校验(表单参数校验)

1、maven坐标<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>3.0.1</version> </dependency>2、校验规则3、定义好校验规则还需要开启校验&#…

用户区网络缓冲区

用户区网络缓冲区 为什么要有用户层缓冲区 TCP内核协议栈&#xff0c;每个连接都有一个接收缓冲区和一个发送缓冲区&#xff0c;为啥用户层也要有&#xff1a; 为啥要有接收缓冲区 生产者速度大于消费者速度&#xff1a;客户端发送地太快&#xff0c;服务器处理不过来&#…

SpringWebflux 执行流程和核心 API

SpringWebflux 基于 Reactor&#xff0c;默认使用容器是 Netty&#xff0c;Netty 是高性能的 NIO 框架&#xff0c;异步非阻 塞的框架 Netty_百度百科 (baidu.com)BIO、NIO、AIO_y_凉介的博客-CSDN博客_bin nio &#xff08;1&#xff09;Netty BIO 每一个请求过来会占用一个…

【系列05】类与对象 面向对象 封装继承多态 类 内部类

面向对象&#x1f601; 文章为本人随课程记录笔记形成 跟随老师"秦疆&#xff08;遇见狂神说)" 非常欢迎大家在文章下面留言评论互相交流,也欢迎大家有问题可以联系本人或者本人公众号 &#x1f609;学思则安 参考课程https://www.kuangstudy.com/course?cid1 有问…

Vue3通透教程【一】Vue3现状—必然趋势?

文章目录&#x1f31f; 专栏介绍&#x1f31f; Vue默认版本&#x1f31f; 拥抱Vue3的UI&#x1f31f; Vue3显著优势&#x1f31f; 专栏介绍 凉哥作为 Vue 的忠诚粉丝输出过大量的 Vue 文章&#xff0c;应粉丝要求开始更新 Vue3 的相关技术文章&#xff0c;Vue 框架目前的地位大…

现在什么款式运动无线耳机好、最适合运动的无线蓝牙耳机推荐

随着经济越来越好&#xff0c;人们的生活质量提高&#xff0c;我们对健康也是更加重视了。越来越多人开始“动起来”。健康运动&#xff0c;自然少不了专业的运动耳机。一副适合的运动耳机对我们锻炼身体有着事半功倍的作用&#xff0c;那么有哪些品牌值得推荐呢&#xff1f;小…

论文笔记(1):Large Language Models are few(1)-shot Table Reasoners

文章目录AbstractIntroductionRelated worksMethodExperimentdatasetbaselinesresultsmain resultsanalysisLimitationAbstract 已有研究表明&#xff0c;大型语言模型(LLM)在文本的少样本推理中表现excellent&#xff0c;本文证明LLM在表结构的f复杂少样本推理中表现也很comp…

【数据结构基础】树 - 二叉搜索树(BST)

本文主要介绍 二叉树中最基本的二叉查找树&#xff08;Binary Search Tree&#xff09;&#xff0c;&#xff08;又&#xff1a;二叉搜索树&#xff0c;二叉排序树&#xff09;它或者是一棵空树&#xff0c;或者是具有下列性质的二叉树&#xff1a; 若它的左子树不空&#xff0…

入门力扣自学笔记233 C++ (题目编号:2319)

2319. 判断矩阵是否是一个 X 矩阵 题目&#xff1a; 如果一个正方形矩阵满足下述 全部 条件&#xff0c;则称之为一个 X 矩阵 &#xff1a; 矩阵对角线上的所有元素都 不是 0 矩阵中所有其他元素都是 0 给你一个大小为 n x n 的二维整数数组 grid &#xff0c;表示一个正方形…

GitHub2022年十大热门编程语言榜单(上)

全球知名代码托管平台 GitHub发布的2022年GitHub Octoverse年度报告公布了全球最流行的十大编程语言&#xff0c;其中JavaScript蝉联第一&#xff0c;Python位列次席。 编程是技术革新的核心&#xff0c;对于所有的编程开发人员来说&#xff0c;对世界范围内编程语言发展和趋势…

搭WIFI拓扑有感

搭拓扑有感 人类革命&#xff0c;一场N*N的MIMO 关键技术&#xff1a;男女搭配 结婚生子 男女搭配&#xff1a;以搭档为单位调度&#xff0c;节省整体开资&#xff0c;克服短时间的寂寞 CP沟通&#xff1a;在说话间加一个保护间隔&#xff0c;不给对方太大的压力 结婚生子 …

Live800:影响在线客服系统稳定性的因素,有哪些?

稳定性的在线客服系统对企业来说是至关重要的&#xff0c;可以说是企业选择在线客服系统时首要考量的一个因素。一个不稳定的在线客服系统&#xff0c;即使价格再便宜&#xff0c;恐怕也无法满足企业搭建在线客服系统的初衷。想象一下当客户正在咨询问题时&#xff0c;客服系统…

十三、表数据的增、删、改操作

文章目录一、插入数据1.1 使用 INSERT…VALUES 语句插入数据1.2 使用 INSERT…SET 语句插入数据1.3 使用 INSERT...SELECT 语句插入查询结果二、修改(更新)数据三、删除数据3.1 通过 DELETE 语句删除数据3.2 通过 TRUNCATE TABLE 语句删除数据3.3 DELETE 语句和 TRUNCATE TABLE…

爬虫实例(二)—— 爬取高清4K图片

大家好&#xff0c;我是 Enovo飞鱼&#xff0c;今天继续分享一个爬虫案例&#xff0c;爬取高清4K图片&#xff0c;加油&#x1f4aa;。 目录 前言 增加异常处理 增加代码灵活性 基本环境配置 爬取目标网站 分析网站页面 具体代码实现 图片下载示例 感谢支持&#x1f6…

ABB机器人设置有效载荷的2种方法具体步骤(直接输入法+自动识别推算法1)

ABB机器人设置有效载荷的2种方法具体步骤(直接输入法+自动识别推算法1) 为什么要设置有效载荷Loaddata? 对于搬运应用的机器人只有设定正确的工具和载荷数据,机器人才能正确的工作; 对于搬运比较重的产品,或工具的重量也比较重,需要设置工具及搬运对象的重心和重量; 对…

如何用ChatGPT高效完成工作

如何用ChatGPT高效完成工作 过完年刚开工&#xff0c;很多人还没有从假期综合症中走出来&#xff0c;不想上班&#xff0c;总想摸鱼&#xff0c;可是手上的工作还是要完成的。都2023年了&#xff0c;是时候让ChatGPT来帮我们完成工作了&#xff01;本文将教你如何用ChatGPT高效…

Unity-Tcp-网络聊天功能(二): 登录与注册

5.客户端实现注册与登录接口创建好UI接下来定义发给客户端的协议等public class MessageHelper {//发送登录的消息给服务器 1002public void SendLoginMsg(string account, string pwd){LoginMsgC2S msg new LoginMsgC2S();msg.account account;msg.password pwd;var str J…