Unity&Shader案例篇—声纳光波效果

后处理 逐像素的光波扩散效果 废话不多说先上效果图: 实现原理: 获取深度图 根据深度值计算出像素的NDC坐标,将结果与VP矩阵的逆矩阵相乘即可获取像素的世界坐标 再将像素的世界坐标与指定的坐标进行距离(或点乘,点乘出来的结果波纹是直线)运算 再通过时间 间隔 速度 等参数进行计算,处理上一步获取到的距离(点积)参数,进行强化 再与原始画面叠加 C#代码: using UnityEngine; publi... 阅读详情

原文:http://www.manew.com/thread-98405-1-1.html

一、前言

睡前再来一篇吧,明天周一了,加油吧!废话不多说了,先上效果图如图所示,前面两个的效果图是两种模式下的:
这里写图片描述

这里写图片描述

这里写图片描述

不同效果,最后一章图片是在其中一种模式下,场景进行了精心布置后的效果图。

看效果图会不自觉的认为实现这个效果是不是要在场景中的物体中进行绘制,如果真是要这样做的话那是在是太耗性能了(毕竟都工作了,本人毕业了就不想在搞那些不实用的)。

其实,这个是通过控制摄像机的最后渲染来实现的效果的,后面我会给出这个案例的工程文件下载地址。

读者在运行模式的Scene视图里将看到场景的物体(立方体)并没有被额外渲染,有了这个思路对于后面理解代码的实现原理会很有帮助。

这里写图片描述


二、原理

1、Shader部分—光照计算

这里用到的光照计算都比较简单,光照模式我使用了最简单的漫反射模式,代码如下:

//光照计算

float4x4 modelMatrix = _Object2World;
float4x4 modelMatrixInverse = _World2Object;

float3 normalDirection = normalize(
        mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);
float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);

float3 diffuseReflection = _LightColor0.rgb * max(0.0, dot(normalDirection, lightDirection));

output.col = float4(diffuseReflection, 1.0);
output.pos = mul(UNITY_MATRIX_MVP, input.vertex);

如图所示为漫反射的示意图,它的计算公式为:
这里写图片描述
这里写图片描述

2、Shader部分—声纳光波的计算

Shader代码如下:

//声纳光波计算
#ifdef SONAR_DIRECTIONAL
                                float w = dot(output.pos.xyz, _SonarWaveVector);
#else
                                float w = length(output.pos.xyz - _SonarWaveVector);
#endif
                                // Moving wave.
                                w -= _Time.y * _SonarWaveParams.w;

                                // Get modulo (w % params.z / params.z)
                                w /= _SonarWaveParams.z;
                                w = w - floor(w);

                                // Make the gradient steeper.
                                float p = _SonarWaveParams.y;
                                w = (pow(w, p) + pow(1 - w, p * 4)) * 0.5;

                                // Amplify.
                                w *= _SonarWaveParams.x;

                                fixed3 col = _SonarWaveColor * w + _SonarAddColor;

代码中使用了预编译命令,是考虑了前面说的效果图中的两种模式的切换。为此,还必须在前面添加预编译命令

#pragma multi_compile SONAR_DIRECTIONAL SONAR_SPHERICAL

这个命令的大概意思就是说可以将这两个模式的Shader一起编译,然后就可以在C#代码里通过

Shader.DisableKeyword("SONAR_SPHERICAL");

或者

Shader.EnableKeyword("SONAR_SPHERICAL");

来进行切换。

完整顶点片段Shader代码如下:

Shader "CgInUnity/SonarFxVF"
{
        Properties
        {
                _SonarBaseColor("Base Color",  Color) = (0.1, 0.1, 0.1, 0)
                _SonarWaveColor("Wave Color",  Color) = (1.0, 0.1, 0.1, 0)
                _SonarWaveParams("Wave Params", Vector) = (1, 20, 20, 10)
                _SonarWaveVector("Wave Vector", Vector) = (0, 0, 1, 0)
                _SonarAddColor("Add Color",   Color) = (0, 0, 0, 0)
        }
        SubShader
        {
                Tags{ "LightMode" = "ForwardBase" }
                // make sure that all uniforms are correctly set

                Pass
                {
                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                        #pragma multi_compile SONAR_DIRECTIONAL SONAR_SPHERICAL

                        #include "UnityCG.cginc"

                        struct vertexInput
                        {
                                float4 vertex : POSITION;
                                float3 normal:NORMAL;
                        };

                        struct vertexOutput
                        {
                                float4 pos:SV_POSITION;
                                float4 col:COLOR;
                        };

                        float3 _SonarBaseColor;
                        float3 _SonarWaveColor;
                        float4 _SonarWaveParams; // Amp, Exp, Interval, Speed
                        float3 _SonarWaveVector;
                        float3 _SonarAddColor;
                        uniform float4 _LightColor0;

                        vertexOutput vert (vertexInput input)
                        {
                                vertexOutput output;

                                //光照计算

                                float4x4 modelMatrix = _Object2World;
                                float4x4 modelMatrixInverse = _World2Object;

                                float3 normalDirection = normalize(
                                        mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);
                                float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);

                                float3 diffuseReflection = _LightColor0.rgb * max(0.0, dot(normalDirection, lightDirection));

                                output.col = float4(diffuseReflection, 1.0);
                                output.pos = mul(UNITY_MATRIX_MVP, input.vertex);

                                //声纳光波计算
#ifdef SONAR_DIRECTIONAL
                                float w = dot(output.pos.xyz, _SonarWaveVector);
#else
                                float w = length(output.pos.xyz - _SonarWaveVector);
#endif
                                // Moving wave.
                                w -= _Time.y * _SonarWaveParams.w;

                                // Get modulo (w % params.z / params.z)
                                w /= _SonarWaveParams.z;
                                w = w - floor(w);

                                // Make the gradient steeper.
                                float p = _SonarWaveParams.y;
                                w = (pow(w, p) + pow(1 - w, p * 4)) * 0.5;

                                // Amplify.
                                w *= _SonarWaveParams.x;

                                fixed3 col = _SonarWaveColor * w + _SonarAddColor;

                                output.col += float4(col, 1);

                                return output;
                        }

                        float4 frag (vertexOutput input) : COLOR
                        {

                                return  input.col;
                        }
                        ENDCG
                }
        }
}

喜欢用简洁的Surface Shader代码的童鞋可以用如下代码替换:

Shader "CgInUnity/SonarFxSurf"
{
    Properties
    {
        _SonarBaseColor  ("Base Color",  Color)  = (0.1, 0.1, 0.1, 0)
        _SonarWaveColor  ("Wave Color",  Color)  = (1.0, 0.1, 0.1, 0)
        _SonarWaveParams ("Wave Params", Vector) = (1, 20, 20, 10)
        _SonarWaveVector ("Wave Vector", Vector) = (0, 0, 1, 0)
        _SonarAddColor   ("Add Color",   Color)  = (0, 0, 0, 0)
    }
    SubShader
    {
        Tags { "RenderType" = "Opaque" }

        CGPROGRAM

        #pragma surface surf Lambert
        #pragma multi_compile SONAR_DIRECTIONAL SONAR_SPHERICAL

        struct Input
        {
            float3 worldPos;
        };

        float3 _SonarBaseColor;
        float3 _SonarWaveColor;
        float4 _SonarWaveParams; // Amp, Exp, Interval, Speed
        float3 _SonarWaveVector;
        float3 _SonarAddColor;

        void surf(Input IN, inout SurfaceOutput o)
        {
#ifdef SONAR_DIRECTIONAL
            float w = dot(IN.worldPos, _SonarWaveVector);
#else
            float w = length(IN.worldPos - _SonarWaveVector);
#endif

            // Moving wave.
            w -= _Time.y * _SonarWaveParams.w;

            // Get modulo (w % params.z / params.z)
            w /= _SonarWaveParams.z;
            w = w - floor(w);

            // Make the gradient steeper.
            float p = _SonarWaveParams.y;
            w = (pow(w, p) + pow(1 - w, p * 4)) * 0.5;

            // Amplify.
            w *= _SonarWaveParams.x;

            // Apply to the surface.
            o.Albedo = _SonarBaseColor;
            o.Emission = _SonarWaveColor * w + _SonarAddColor;
        }

        ENDCG
    } 
    Fallback "Diffuse"
}

这个代码看似简单,但是对于处在学习基础原理阶段的童鞋,我的建议还是多动手写写顶点片段Shader,实现简单的光照模式、顶点变换等等对于学习Shader会非常有帮助的。

3、C#脚本部分
脚本部分最关键的就是使用上述的Shader去渲染摄像机,这个需要通过如下的代码来实现吗,这段代码的意思是替换成这个Shader来渲染摄像机

GetComponent<Camera>().SetReplacementShader(shader, null);

其他的功能就是出传递参数给Shader来实现最终随时间变换的效果,完整的代码如下:

using UnityEngine;

[RequireComponent(typeof(Camera))]
public class SonarFxControl : MonoBehaviour
{
    // 声纳的模式
    public enum SonarMode { Directional, Spherical }
    [SerializeField] SonarMode _mode = SonarMode.Directional;
    public SonarMode mode { get { return _mode; } set { _mode = value; } }

    // 声纳波的方向(仅仅在Directional模式下)
    [SerializeField] Vector3 _direction = Vector3.forward;
    public Vector3 direction { get { return _direction; } set { _direction = value; } }

    // 声纳波区域(仅仅在Spherical模式下)
    [SerializeField] Vector3 _origin = Vector3.zero;
    public Vector3 origin { get { return _origin; } set { _origin = value; } }

    // 背景颜色(Surfface Shader下有用)
    [SerializeField] Color _baseColor = new Color(0.2f, 0.2f, 0.2f, 0);
    public Color baseColor { get { return _baseColor; } set { _baseColor = value; } }

    // 声纳波的颜色
    [SerializeField] Color _waveColor = new Color(1.0f, 0.2f, 0.2f, 0);
    public Color waveColor { get { return _waveColor; } set { _waveColor = value; } }

    // 波的高度\振幅
    [SerializeField] float _waveAmplitude = 2.0f;
    public float waveAmplitude { get { return _waveAmplitude; } set { _waveAmplitude = value; } }

    // 波的颜色指数
    [SerializeField] float _waveExponent = 22.0f;
    public float waveExponent { get { return _waveExponent; } set { _waveExponent = value; } }

    // 波的时间间隔
    [SerializeField] float _waveInterval = 20.0f;
    public float waveInterval { get { return _waveInterval; } set { _waveInterval = value; } }

    // 波的速度
    [SerializeField] float _waveSpeed = 10.0f;
    public float waveSpeed { get { return _waveSpeed; } set { _waveSpeed = value; } }

    // 额外的颜色
    [SerializeField] Color _addColor = Color.black;
    public Color addColor { get { return _addColor; } set { _addColor = value; } }


    [SerializeField] Shader shader;

    int baseColorID;
    int waveColorID;
    int waveParamsID;
    int waveVectorID;
    int addColorID;

    void Awake()
    {
        baseColorID = Shader.PropertyToID("_SonarBaseColor");
        waveColorID = Shader.PropertyToID("_SonarWaveColor");
        waveParamsID = Shader.PropertyToID("_SonarWaveParams");
        waveVectorID = Shader.PropertyToID("_SonarWaveVector");
        addColorID = Shader.PropertyToID("_SonarAddColor");
    }

    void OnEnable()
    {
        GetComponent<Camera>().SetReplacementShader(shader, null);
        Update();
    }

    void OnDisable()
    {
        GetComponent<Camera>().ResetReplacementShader();
    }

    void Update()
    {
        Shader.SetGlobalColor(baseColorID, _baseColor);
        Shader.SetGlobalColor(waveColorID, _waveColor);
        Shader.SetGlobalColor(addColorID, _addColor);

        var param = new Vector4(_waveAmplitude, _waveExponent, _waveInterval, _waveSpeed);
        Shader.SetGlobalVector(waveParamsID, param);

        if (_mode == SonarMode.Directional)
        {
            Shader.DisableKeyword("SONAR_SPHERICAL");
            Shader.SetGlobalVector(waveVectorID, _direction.normalized);
        }
        else
        {
            Shader.EnableKeyword("SONAR_SPHERICAL");
            Shader.SetGlobalVector(waveVectorID, _origin);
        }
    }
}

三、结语

最后可以看看这种方式实现的声纳波效果的性能消耗如何,我们可以在运行的时候打开state看到如图所示的统计图,瞬间有没有觉得这个效果其实还蛮有实用价值的。
这里写图片描述

好了,感谢原作者的分享.

每天进步一点点!!!

AirSim+UE与Unity3D水下仿真平台对比:如何根据实验需求精准选择 本文对比了AirSim+UE与Unity3D在水下仿真平台中的优劣,帮助用户根据实验需求精准选择。AirSim+UE在物理精度和传感器仿真方面表现优异,适合算法验证;而Unity3D在开发效率和跨平台部署上更具优势,适合快速原型开发。文章还提供了五步匹配法,帮助用户根据核心需求、数据管线、极限工况、扩展性和生态兼容性做出决策。 阅读详情

相关推荐

ShaderJoy —— 一些特效作品展示

ShaderJoy -水墨晕染转场ShaderJoy -- 爱的节奏ShaderJoy -- Little StarsShaderjoy -- ∞ neonShaderJoy --♡の烟花ShaderJoy --Dancing ♡ShaderJoy -- ♡の烟花ShaderJoy —— 💗声波纹ShaderJoy--❤随乐动ShaderJoy ——💗の声纹ShaderJoy —— ❤ 气泡音频特效Shader 特效 —— 基于 OpenGL 的音频可视化(仿 ShaderToy).mp4ShaderJ

ShaderJoy 的兴趣技术杂货铺 6313

样本仿真结合迁移学习的声呐图像水雷检测

样本仿真结合迁移学习的侧扫声呐图像水雷目标检测与识别方法

xcy2014117129的博客 1479

Unity音频可视化==》音波

实时获取设备的麦克风接收的音频,并将音频可视化成音波的形式。 后面大家需要的话可以可以将音频转成类卡拉OK的文件分享出来。

声波Shader

最近需求需要做一个声波Shader…网上找不到能用的的,只好自己写了一个。 这里分享给大家,代码本身有注释,这里就不做介绍了,上图。 这里面用到了幕运算,对性能消耗会比较大,有更好的方法欢迎指教。 QQ:262319244 代码如下: Shader "GaiziShader/SoundWave" { Properties { //角度 _Angle("Angle",Range(1,10))...

盖子的博客 871

Unity 雷达效果实现

Unity3D的粒子效果系列,各类丰富的插件,丰富的粒子效果,雷达效果实现

基于Unity3D引擎的三维可视化技术在煤炭地震勘探中的应用

为满足地震勘探报告三维可视化的需要,以Unity3D引擎为开发平台,利用GIS 3D分析及3DS max三维建模,研究应用煤炭地震勘探三维可视化技术,实现三维地质数据体、地质层位(包括断层面)以及复杂地质模型等的三维可视化,实现对三维地质模型的平移、旋转、缩放,以及各种综合立体显示,建立三维环境漫游和三维可视化交互平台,并以动画形式表现出来,形成具有灵活方便使用的可视化系统。

HoloOcean:逼真的声纳模拟

Sonar sensors play an integral part in underwater robotic perception by providing imagery at long distances where standard optical cameras cannot. They have proven to be an important part in various robotic algorithms including localization, mapping, and s

czy940115的博客 4689

基于声纳的水下机器人同时定位与地图构建技术研究

基于声纳的水下机器人同时定位与地图构建技术研究

在Unity3D中构建3D模拟

欢迎来到这个由三部分组成的关于Unity 3D的博客系列的最后一篇文章。 在本系列中,我们将在Unity3D中使用丰富的控件创建一个简单的3D游戏。 第一部分介绍了如何设置Unity3D ,第二部分介绍了如何 使用C#控制Unity3D 。 在本系列的最后一篇文章中,我们将深入研究如何使用Unity3D将代码实际制作成一个简单的游戏。 让我们开始吧 让我们建立一些关卡,进行更多类似游...

danpu0978的博客 923

基于UNITY3D的水下机器人视景仿真方法.pdf

#资源达人分享计划#

Python画好看的雷达图,全网开源代码最好看的

【代码】Python画好看的雷达图,全网开源代码最好看的。

大模型天花板 2270

猫都能学会的Unity3D Shader入门指南(一)(转)

猫都能学会的Unity3D Shader入门指南(一) PS:转自  https://onevcat.com/2013/07/shader-tutorial-1/ 动机 自己使用Unity3D也有一段时间了,但是很多时候是流于表面,更多地是把这个引擎简单地用作脚本控制,而对更深入一些的层次几乎没有了解。虽然说Unity引擎设计的初衷就是创建简单的不需要开发者操心的谁都能用的3

474

从零开始:用君正T23ZN打造智能门锁双摄系统(含代码示例与调试技巧)

本文详细介绍了基于君正T23ZN视频处理芯片构建智能门锁双摄系统的完整实战方案。内容涵盖硬件选型与核心电路设计、软件开发环境搭建、双摄驱动框架、图像信号处理(ISP)调优、人脸识别算法集成与性能优化,以及系统调试与稳定性保障。文章提供了丰富的代码示例和调试技巧,旨在帮助嵌入式开发者高效实现具备人脸识别与监控功能的低功耗智能门锁视觉系统。

opencv7vision的博客 711

Unity光波扩散Shader(纯记录防遗失)

shader 代码(shader放一张图片,图片需要与要显示模型上材质球上图片一致,不放没有效果,)c#代码(本脚本挂到摄像机上)

qq_37524903的博客 1607

从零开始使用CubeMX配置STM32使用lwip实现httpd服务器以及使用vscode编辑阅读keil代码(三)

使用stm32搭载lwip实现HTTPd服务器

qq_30623327的博客 5924

图像配准方法之灰度信息法

这系列文章是5年前的,也是从自己的QQ(632846506)日志中移过来的。https://user.qzone.qq.com/632846506/infocenter。      图像配准的方法主要有三种:基于灰度信息方法;基于空间变换域方法;基于图像特征的方法。 一、灰度信息法。     灰度信息法直接利用两幅图像之间灰度度量的相似性,以图像内部的信息为依据,采用搜索方法寻找相似度最大或

月秀明竹的专栏 1万+

将声纳数据从旧的声纳版本迁移到新的声纳版本

在我当前的项目中,我们正在建立一个新的构建服务器。 我们要做的事情之一是将运行在H2之上的旧声纳实现迁移到运行在Oracle上的新版本。 问题在于,当您从H2开始时,以及当版本与我们的案例相距甚远时,仅迁移数据几乎是不可能的。 在进行一些研究时,我们偶然发现了以下迁移Gist页面,其中显示了可能的迁移路径: https : //gist.github.com/aslakknutsen/242...

danpu0978的博客 173

Unity物理驱动3D汽车实现:从刚体控制到参数调优

在游戏开发中,刚体物理是实现真实物体运动与交互的核心技术。通过Unity的物理引擎,开发者可以模拟重力、碰撞、摩擦力等物理行为,为游戏世界注入真实感。其技术价值在于能够以符合物理规律的方式驱动游戏对象,避免穿墙、无视惯性等问题,从而提升游戏体验的真实性和沉浸感。这一原理广泛应用于角色控制、车辆模拟、物体破坏等场景。本文以3D小汽车为例,详细解析了如何通过Rigidbody组件施加力与扭矩,并利用C#脚本实现玩家输入逻辑,完成一辆可操控、能碰撞的物理驱动汽车。文中重点探讨了AddForce与角速度控制两种方案

weixin_34380948的博客 493

Unity用Shader实现波浪效果

实现的原理:让顶点的Y轴按正弦变化(余弦变化也可以),核心代码就一句 i.uv.y += (_Amplitude * sin(_AngularVelocity * i.uv.x + _Speed * _Time.y));  Shader "Custom/Wave" { Properties { _MainTex ("Albedo (RGB)", 2D) = "white" {} _

l_jinxiong的专栏 7048

新华DCS系统仿真测试方法详细介绍

新华DCS ICAN3.1系统是应用广泛并且功能非常强大的国产DCS系统。具有管理虚拟CPU并仿真运行的功能。并且上位机画面可以与虚拟DPU数据实时同步仿真。具体仿真方法如下所示: 1、 需要设备及软件: 2、步骤如下: 2.1硬件步骤: 1)电脑开机。 2)交换机连接电脑网卡。 3)交换机上电运行。 2.2软件步骤: 1)设置电脑IP 一般配置IP为A网工程站IP。 222.222.221.201/255.255.255.0 2)建立虚拟DPU 登录 D:\iCAN\Program\Vxcu 文件夹。

lw_waston的博客 6872

Swin Transformer 与 CNN 结合实现图像分类

Swin Transformer 与 CNN 结合实现图像分类。(含swin transformer 结构讲解,cnn网络搭建,代码)

这里是Mae。 5022

unity-特效-雷达扫描效果

unity 全局扫描

weixin_38527697的博客 862

面向企业架构师的 SAP BTP 全景实践:多云、账户、运行时与端到端开发路径

摘要:SAP BTP为企业提供多云、多运行时(Cloud Foundry/Kyma/ABAP Cloud)的数字化转型平台,支持快速构建扩展应用。关键选择包括:1)根据合规与性能选择区域;2)区分Trial(90天限制)与Free Tier(无期限)方案;3)按场景选择运行时(CF适合微服务/Kyma适合云原生/ABAP Cloud适合S/4HANA扩展)。建议优先使用Free Tier进行POC,并通过BTP Cockpit统一管理,实现从验证到生产的平滑过渡。(150字)

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 246

Unity雷达扫描特效的制作

unity雷达扫描特效的制作 效果要求: 应该是要做成第一个图的样子,emmm,怎么做呢,表示一脸懵逼。(第二个效果图是我从网上荡下来的)。以下是我的思路: 雷达特效=同心圆+两条垂直线+扫描效果。嗯,没错,就这么干。同心圆还不简单 ,几个linerenender就搞定了,positions的数据呢?写段代码跑个数据txt就完事了。然后再unity里面,新建一个物体,添加一个lineren...

m0_46195138的博客 3528

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Unity Shader - Bloom(光晕、泛光)

前言 Bloom(光晕)是一种计算机图形效果,用于视频游戏,演示和高动态范围渲染(HDRR)中,以再现真实相机的成像伪像。该效果会产生从图像中明亮区域的边界延伸的条纹(或羽毛),从而造成超亮的光使摄像机或眼睛捕捉场景的幻觉。 效果对比如下: 左边是原图, 右边Bloom处理后的 原理: Bloom的实现原理非常简单,大致分为三步: 对需要处理的图像经过亮度提取, 并且通过一个阙值来控制亮度 对经过亮度提取后的图像进行模糊处理(这里是采用高斯模糊) 最后再叠加原图和模糊处理后的图像,输出即可 实现 下面

长生但酒狂的博客 6703

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

上一篇: Unity&Shader案例篇—绘制雪花
下一篇: Unity&Shader案例篇—膨胀效果
阿童木yss
博客等级 码龄10年 35粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值