Unity中Shader面片一直面向摄像机(个性化修改及适配BRP)

news2024/9/27 21:26:52

文章目录

  • 前言
  • 一、个性化修改面向摄像机效果
    • 1、把上一篇文章中求的 Z轴基向量 投影到 XoZ平面上
    • 2、其余步骤和之前的一致
    • 3、在属性面板定义一个变量,控制面片面向摄像机的类型
    • 4、效果
  • 二、适配BRP
  • 三、最终代码


前言

在上一篇文章中,我们用Shader实现了面片一直面向摄像机的效果。

  • Unity中Shader面片一直面向摄像机

在这篇文章中,我们对其进行个性化修改 及 BRP下的适配。


一、个性化修改面向摄像机效果

  • 在很多时候,我们并不需要面片在上下方向跟随摄像机旋转
  • 我们只需要面片跟随摄像机的左右旋转。
  • 那么,我们就需要对上一篇文章中实现的效果进行修改

1、把上一篇文章中求的 Z轴基向量 投影到 XoZ平面上

  • 最简单的办法就是,先把摄像机坐标转化到模型本地坐标
  • 让 y 值为0后,再归一化

float3 viewDir = mul(GetWorldToObjectMatrix(),float4(_WorldSpaceCameraPos,1)).xyz;
viewDir = float3(viewDir.x,0,viewDir.z);
viewDir = normalize(viewDir);

2、其余步骤和之前的一致

  • 假设Y轴基向量
  • 求X轴基向量
  • 求Y轴基向量

3、在属性面板定义一个变量,控制面片面向摄像机的类型

  • 属性面板

[Enum(Billboard,1,VerticalBillboard,0)]_BillboardType(“BillboardType”,int) = 1

  • 在顶点着色器

float3 viewDir = mul(GetWorldToObjectMatrix(),float4(_WorldSpaceCameraPos,1)).xyz;
viewDir.y *= _BillboardType;
viewDir = normalize(viewDir);

4、效果

在这里插入图片描述
请添加图片描述


二、适配BRP

SubShader
    {
        Tags
        {
            //渲染类型
            "RenderType"="Transparent"
            //渲染队列
            "Queue"="Transparent"
        }
        Blend [_SrcFactor] [_DstFactor]
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            #include "UnityCG.cginc"

            struct appdata
            {
                float3 vertexOS : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertexCS : SV_POSITION;
                float2 uv : TEXCOORD1;
                UNITY_FOG_COORDS(2)
            };


            float4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            half4 _Sequence;
            half _BillboardType;

            v2f vert(appdata v)
            {
                v2f o;

                //Z轴基向量
                float3 viewDir = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz;
                viewDir.y *= _BillboardType;
                viewDir = normalize(viewDir);
                //假设Y轴基向量
                float3 upDir = float3(0,1,0);
                //X轴基向量(左手坐标系、逆时针叉乘)
                float3 rightDir = normalize(cross(viewDir,upDir));
                //Y轴基向量(左手坐标系、逆时针叉乘)
                upDir = normalize(cross(rightDir,viewDir));
                //顶点应用旋转
                //法一:向量乘法
                float3 newVertexOS = rightDir * v.vertexOS.x + upDir * v.vertexOS.y + viewDir * v.vertexOS.z;
                //法二:矩阵乘法
                /*float4x4 M = float4x4
                    (
                        rightDir.x,upDir.x,viewDir.x,0,
                        rightDir.y,upDir.y,viewDir.y,0,
                        rightDir.z,upDir.z,viewDir.z,0,
                        0,0,0,1
                    );
                float3 newVertexOS = mul(M,v.vertexOS).xyz;*/

                
                o.vertexCS = UnityObjectToClipPos(newVertexOS);
                o.uv = float2(v.uv.x / _Sequence.y, v.uv.y / _Sequence.x + (_Sequence.x - 1) / _Sequence.x);
                o.uv.x += frac(floor(_Time.y * _Sequence.y * _Sequence.z) / _Sequence.y);
                o.uv.y -= frac(floor(_Time.y * _Sequence.y * _Sequence.z / _Sequence.y) / _Sequence.x);
                //o.uv.x += floor(_Time.y);
                //o.uv = float2(v.uv.x/4,v.uv.y/4);
                //o.uv = TRANSFORM_TEX(v.uv,_MainTex);
                UNITY_TRANSFER_FOG(o, o.vertex)
                return o;
            }

            half4 frag(v2f i) : SV_Target
            {
                float4 mainTex = tex2D(_MainTex, i.uv);
                float4 col = mainTex * _Color;
                UNITY_APPLY_FOG(i.fogCoord, col)
                col.rgb = col.rgb * col.a;
                return col;
            }
            ENDCG
        }
    }

三、最终代码

Shader "MyShader/URP/P3_10_5"
{
    Properties
    {
        [Enum(UnityEngine.Rendering.BlendMode)]_SrcFactor("SrcFactor",int) = 0
        [Enum(UnityEngine.Rendering.BlendMode)]_DstFactor("DstFactor",int) = 0
        _Color("Color",Color) = (1,1,1,1)
        _MainTex("MainTex",2D) = "white"{}
        _Sequence("Row(X) Column(Y) Speed(Z)",Vector) = (1,1,1,1)
        [Enum(Billboard,1,VerticalBillboard,0)]_BillboardType("BillboardType",int) = 1
    }
    SubShader
    {
        Tags
        {
            //告诉引擎,该Shader只用于 URP 渲染管线
            "RenderPipeline"="UniversalPipeline"
            //渲染类型
            "RenderType"="Transparent"
            //渲染队列
            "Queue"="Transparent"
        }
        Blend [_SrcFactor] [_DstFactor]
        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            struct Attribute
            {
                float4 vertexOS : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct Varying
            {
                float4 vertexCS : SV_POSITION;
                float2 uv : TEXCOORD1;
                float fogCoord : TEXCOORD2;
            };

            CBUFFER_START(UnityPerMaterial)
                float4 _Color;
                float4 _MainTex_ST;
                half4 _Sequence;
                half _BillboardType;
            CBUFFER_END

            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);

            Varying vert(Attribute v)
            {
                Varying o;
                //Z轴基向量
                float3 viewDir = mul(GetWorldToObjectMatrix(),float4(_WorldSpaceCameraPos,1)).xyz;
                viewDir.y *= _BillboardType;
                viewDir = normalize(viewDir);
                //假设Y轴基向量
                float3 upDir = float3(0,1,0);
                //X轴基向量(左手坐标系、逆时针叉乘)
                float3 rightDir = normalize(cross(viewDir,upDir));
                //Y轴基向量(左手坐标系、逆时针叉乘)
                upDir = normalize(cross(rightDir,viewDir));
                //顶点应用旋转
                //法一:向量乘法
                float3 newVertexOS = rightDir * v.vertexOS.x + upDir * v.vertexOS.y + viewDir * v.vertexOS.z;
                //法二:矩阵乘法
                /*float4x4 M = float4x4
                    (
                        rightDir.x,upDir.x,viewDir.x,0,
                        rightDir.y,upDir.y,viewDir.y,0,
                        rightDir.z,upDir.z,viewDir.z,0,
                        0,0,0,1
                    );
                float3 newVertexOS = mul(M,v.vertexOS).xyz;*/

                
                o.vertexCS = TransformObjectToHClip(newVertexOS);
                o.uv = float2(v.uv.x / _Sequence.y, v.uv.y / _Sequence.x + (_Sequence.x - 1) / _Sequence.x);
                o.uv.x += frac(floor(_Time.y * _Sequence.y * _Sequence.z) / _Sequence.y);
                o.uv.y -= frac(floor(_Time.y * _Sequence.y * _Sequence.z / _Sequence.y) / _Sequence.x);
                //o.uv.x += floor(_Time.y);
                //o.uv = float2(v.uv.x/4,v.uv.y/4);
                //o.uv = TRANSFORM_TEX(v.uv,_MainTex);
                o.fogCoord = ComputeFogFactor(o.vertexCS.z);
                return o;
            }

            half4 frag(Varying i) : SV_Target
            {
                float4 mainTex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
                float4 col = mainTex * _Color;
                col.rgb = MixFog(col.rgb, i.fogCoord);
                col.rgb = col.rgb * col.a;
                return col;
            }
            ENDHLSL
        }
    }
    SubShader
    {
        Tags
        {
            //渲染类型
            "RenderType"="Transparent"
            //渲染队列
            "Queue"="Transparent"
        }
        Blend [_SrcFactor] [_DstFactor]
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            #include "UnityCG.cginc"

            struct appdata
            {
                float3 vertexOS : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertexCS : SV_POSITION;
                float2 uv : TEXCOORD1;
                UNITY_FOG_COORDS(2)
            };


            float4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            half4 _Sequence;
            half _BillboardType;

            v2f vert(appdata v)
            {
                v2f o;

                //Z轴基向量
                float3 viewDir = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz;
                viewDir.y *= _BillboardType;
                viewDir = normalize(viewDir);
                //假设Y轴基向量
                float3 upDir = float3(0,1,0);
                //X轴基向量(左手坐标系、逆时针叉乘)
                float3 rightDir = normalize(cross(viewDir,upDir));
                //Y轴基向量(左手坐标系、逆时针叉乘)
                upDir = normalize(cross(rightDir,viewDir));
                //顶点应用旋转
                //法一:向量乘法
                float3 newVertexOS = rightDir * v.vertexOS.x + upDir * v.vertexOS.y + viewDir * v.vertexOS.z;
                //法二:矩阵乘法
                /*float4x4 M = float4x4
                    (
                        rightDir.x,upDir.x,viewDir.x,0,
                        rightDir.y,upDir.y,viewDir.y,0,
                        rightDir.z,upDir.z,viewDir.z,0,
                        0,0,0,1
                    );
                float3 newVertexOS = mul(M,v.vertexOS).xyz;*/

                
                o.vertexCS = UnityObjectToClipPos(newVertexOS);
                o.uv = float2(v.uv.x / _Sequence.y, v.uv.y / _Sequence.x + (_Sequence.x - 1) / _Sequence.x);
                o.uv.x += frac(floor(_Time.y * _Sequence.y * _Sequence.z) / _Sequence.y);
                o.uv.y -= frac(floor(_Time.y * _Sequence.y * _Sequence.z / _Sequence.y) / _Sequence.x);
                //o.uv.x += floor(_Time.y);
                //o.uv = float2(v.uv.x/4,v.uv.y/4);
                //o.uv = TRANSFORM_TEX(v.uv,_MainTex);
                UNITY_TRANSFER_FOG(o, o.vertex)
                return o;
            }

            half4 frag(v2f i) : SV_Target
            {
                float4 mainTex = tex2D(_MainTex, i.uv);
                float4 col = mainTex * _Color;
                UNITY_APPLY_FOG(i.fogCoord, col)
                col.rgb = col.rgb * col.a;
                return col;
            }
            ENDCG
        }
    }
}

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

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

相关文章

Cannot resolve property ‘driverClassName‘

已解决 Cannot resolve property 错误 最近在学习spring时遇到了下面的问题: spring读取不到property的name属性,报红,编译不通过,上网查到了两种解决方案,如下: 1、重新加载spring文件就可以解决问题了&a…

1870_使用flx来增强counsel-M-x的模糊匹配功能

Grey 全部学习内容汇总: https://github.com/GreyZhang/editors_skills 1870_使用flx来增强counsel-M-x的模糊匹配功能 这一次算是趁热打铁,把之前优化掉了的counsel-M-x的匹配功能再推进一步。虽然还是没有达到spacemacs中的乱序匹配效果&#xff0c…

Mybatis入门源码二:sql执行

后面开始分析sql执行的源码流程也就是这一部分 一、factory.openSession() 重点关注configuration.newExecutor这个方法,获取事务处理器比较简单,就是获取一个jdbc的事务管理器。 这个方法通过传入的执行器类型来创建不同的执行器,有simp…

学习笔记——C++中数据的输入 cin

作用:用于从键盘中获取数据 关键字:cin 语法:cin>>变量 类型:C中数据的输入主要包含:整形(int)浮点型(float,double float),字符型&…

[C#]使用DlibDotNet人脸检测人脸68特征点识别人脸5特征点识别人脸对齐人脸比对FaceMesh

【官方框架地址】 https://github.com/takuya-takeuchi/DlibDotNet 【算法介绍】 DlibDotNet是一个开源的.NET库,用于实现机器学习和计算机视觉应用。它基于C库dlib,通过C/CLI封装了dlib的所有功能,为.NET开发者提供了简单易用的API。以下是…

爬虫网易易盾滑块案例:某乎

声明: 该文章为学习使用,严禁用于商业用途和非法用途,违者后果自负,由此产生的一切后果均与作者无关 一、滑块初步分析 js运行 atob(‘aHR0cHM6Ly93d3cuemhpaHUuY29tL3NpZ25pbg’) 拿到网址,浏览器打开网站&#xff0…

Android学习(一):Android Studio安装与配置

Android学习(一):Android Studio安装与配置 一、安装 下载地址 下载zip文件,免安装。 二、下载资源 启动后,出现该弹框,点击Cancel。 点击Next 默认,点击Next。 点击Next。 点击Finish 开始…

liunx 巡检命令

top 查看cup使用率 - top 查看cup使用率 退出输入q 第一行top 1.当前系统时间 2.up 运行时间 3.users当前连接的终端数量 4.load average 负载的平均值 第二行 tasks 任务 1. 128 total #为当前系统进程总数 2. 1 running #为当前系统进程总…

前端--基础 常用标签-超链接标签 外部链接( herf 和 target)

目录 超链接标签 &#xff1a; 超链接的语法格式 &#xff1a; 超链接的属性 &#xff1a; 超链接的分类 &#xff1a; 外部链接 &#xff1a; 超链接标签 &#xff1a; # 在 HTML 标签中&#xff0c;<a> 标签用于定义超链接&#xff0c;作用是从一个页面…

屏幕截图--Snagit

Snagit是一款优秀的屏幕、文本和视频捕获、编辑与转换软件。它不仅可以捕获静止的图像&#xff0c;还能获得动态的图像和声音。软件界面干净清爽&#xff0c;功能板块一目了然&#xff0c;为用户提供专业的屏幕录制方案。可以根据自己的需求调整录制视频的分辨率、帧数、输出格…

HNU-数据库系统-讨论课2

第二次小班讨论课安排如下: 主题: 数据库系统设计与应用开发。 目的&#xff1a;让学生通过练习和讨论充分掌握数据库系统的设计与应用开发。 内容: 设计和实现一个数据库及应用系统。设计内容包括系统分析、系统设计、 数据库设计&#xff08;需求分析、概念结构设计、逻辑…

图神经网络|9.3 邻接矩阵的变换

由于邻接矩阵中一般不会&#xff08;i,i&#xff09;等于1&#xff0c;除非第i个点上有自环。 而如果用邻接矩阵去乘上特征矩阵&#xff0c;那么将丢失自身向自身的贡献。 此时可以再邻接矩阵的基础上&#xff0c;再加上一个单位阵&#xff0c;从而使得最终的结果包含自身对整体…

P4994 终于结束的起点————C

目录 终于结束的起点题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示样例 1 解释数据范围提示 解题思路Code运行结果 终于结束的起点 题目背景 终于结束的起点 终于写下句点 终于我们告别 终于我们又回到原点 …… 一个个…

RK3399平台入门到精通系列讲解(实验篇)lseek 函数进行读写位置的调整

🚀返回总目录 文章目录 一、lseek 函数的使用二、信号驱动 IO 实验源码2.1、Makefile2.2、驱动部分代码2.3、测试应用代码lseek() 是一个用于文件定位的系统调用函数,用于在文件中移动读写位置指针。在 Linux 中,它常常被用来修改文件读写的位置。lseek() 可以被用于随机存…

[嵌入式C][入门篇] 快速掌握基础4 (普通函数,递归函数,函数指针,弱函数)

开发环境&#xff1a; 网页版&#xff1a;跳转本地开发(Vscode)&#xff1a;跳转 文章目录 一、简介二、普通函数&#xff08;1&#xff09;定义函数&#xff08;2&#xff09;调用函数1. 传值调用2. 传地址调用 三、递归函数&#xff08;套娃&#xff09;(1) 示例代码 四、函…

记.backward()报错

最近我在模型训练损失里加入了LPIPS深度感知损失&#xff0c;训练的时候就出现了如上的报错&#xff0c;具体解释为&#xff1a;调用梯度反向传播loss.backward()时&#xff0c;我们计算梯度&#xff0c;需要一个标量的loss(即该loss张量的维度为1,只包含一个元素&#xff09;&…

计算机科学速成课【学习笔记】(2)——电子计算机

本集课程B站链接 2. 电子计算机-Electronic Computing_哔哩哔哩_bilibili2. 电子计算机-Electronic Computing是【计算机科学速成课】[40集全/精校] - Crash Course Computer Science的第2集视频&#xff0c;该合集共计40集&#xff0c;视频收藏或关注UP主&#xff0c;及时了…

lombok注解 @Data使用在继承类上时出现警告解决

一、警告问题 1、Data注解 Data 包含了 ToString、EqualsAndHashCode、Getter / Setter和RequiredArgsConstructor的功能。 当使用 Data注解时&#xff0c;则有了 EqualsAndHashCode注解&#xff08;即EqualsAndHashCode(callSuperfalse)&#xff09;&#xff0c;那么就会在此…

基于java,springboot的学生考勤系统

1.环境以及简介 基于java,springboot的学生考勤系统&#xff0c;Java项目&#xff0c;SpringBoot项目&#xff0c;vue项目&#xff0c;含开发文档&#xff0c;源码&#xff0c;数据库以及ppt。 源码下载 另有1000份项目源码&#xff0c;项目有java&#xff08;包含springboo…

【Java】设计模式之两阶段终止

两阶段终止 两阶段终止&#xff0c;即Two Phase Termination。是用来终止线程的套路。 它的思想是&#xff0c;如何在一个线程T1中优雅地终止线程T2&#xff1f;这里的【优雅】指的是给T2一个料理后事的机会。 错误思路&#xff1a; 使用stop方法。stop 方法会真正杀死线程…