unity urp 视差卡牌

总体效果大概四层,从后往前排序为:卡背、背景、画像、边框

首先卡背比较简单,只要判断如果网格的背面就直接采样卡背图片展示即可

资源准备:

然后是背景,网上找到一张这样的图。

但他还不符合要求,我们的背景需要四方接续否则在视差下会看到不连续的接痕。关于如何处理四方接续的图。

首先是把这张图拽进ps里,裁切到512X512,然后在滤镜-其他-位移,将其水平垂直都移动512/2个像素,随后修补接痕位置使其连续即可。

然后是画像,这张图看过我上一个文章的应该很熟悉,而且我认为是很有趣的一件事,推荐去看一眼。Unity图片导入趣事随笔-CSDN博客

最后是边框,直接加在最顶层,这也是图片背景使用黑色的理由。

资源完毕,还需要视差的思路。红色为原本物体的uv位置,绿色是视觉上存在深度后所延长到的uv位置,理论上不需要计算z向量,但为了方便计算,原本物体的uv位置的z分量定为0。在红色上顶点的切线空间中,是右手坐标系,z向量向外,所以深度向量一定为(0,0,-1)根据这两个向量点乘可以求出深度向量和视角向量的cosθ,就可以根据深度反推出视角向量延长的距离,那么原本物体的uv位置 + 视角向量延长的距离就是视觉上存在深度后所延长到的uv位置,随后舍弃z分量就是视觉上存在深度后的uv位置。

这个方法根据输入的原uv坐标、视角向量(切线空间下)和深度来返回视觉上存在深度后的uv坐标

            float2 CalculateRealUVAfterDepth(float2 originUV, float3 viewDirTS, float depth){//计算视角方向和深度方向的cos值float cosTheta = dot(normalize(viewDirTS), float3(0,0,-1));  //  一般来讲unity是左手坐标系,但在切线和观察空间较为特殊是右手坐标系,不过这并不影响z轴方向的判断//根据深度差算出两点间距离float dis = depth / cosTheta;//算出应用深度差后对应点位float3 originUVPoint = float3(originUV, 0);float3 afrerDepthUVPoint = originUVPoint + normalize(viewDirTS) * dis;//返回应用深度差后对应UVreturn afrerDepthUVPoint.xy;}

根据这些视差过后的uv坐标采样图片并叠加,就能做出视觉上有距离感的图片结构。

Shader "Kerzh/Tarol"
{Properties{[Space(50)]_FrameTexture("FrameTexture",2D) = "Black"{}[Space(50)]_ParallaxTexture1("Parallax Texture1",2D) = "Black"{}_ParallaxDepth1("Parallax Depth1",Float) = 0[Space(50)]_ParallaxTexture2("Parallax Texture2",2D) = "Black"{}_ParallaxDepth2("Parallax Depth2",Float) = 0_FlowVector2AndSpeed("FlowVector2AndSpeed",Vector) = (0,0,0,0)[Space(50)]_BackTexture("_BackTexture",2D) = "Black"{}}SubShader{Tags {"RenderPipeline" = "UniversalRenderPipeline" "Queue" = "Geometry" "RenderType" = "ReplaceMePlease" "ForceNoShadowCasting" = "false" "DisableBatching" = "False" "IgnoreProjector" = "False" "PreviewType" = "Plane"}LOD 100Pass{Cull OffCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include  "CommonCgInclude.cginc"V2FData vert (MeshData input){V2FData output = FillBaseV2FData(input);return output;}sampler2D _FrameTexture;float4 _FrameTexture_ST;sampler2D _ParallaxTexture1;float4 _ParallaxTexture1_ST;float _ParallaxDepth1;sampler2D _ParallaxTexture2;float4 _ParallaxTexture2_ST;float _ParallaxDepth2;vector _FlowVector2AndSpeed;sampler2D _BackTexture;float4 _BackTexture_ST;float2 CalculateRealUVAfterDepth(float2 originUV, float3 viewDirTS, float depth){//计算视角方向和深度方向的cos值float cosTheta = dot(normalize(viewDirTS), float3(0,0,-1));  //  一般来讲unity是左手坐标系,但在切线和观察空间较为特殊是右手坐标系,不过这并不影响z轴方向的判断//根据深度差算出两点间距离float dis = depth / cosTheta;//算出应用深度差后对应点位float3 originUVPoint = float3(originUV, 0);float3 afrerDepthUVPoint = originUVPoint + normalize(viewDirTS) * dis;//返回应用深度差后对应UVreturn afrerDepthUVPoint.xy;}fixed4 frag (V2FData input,float backFace:VFace) : SV_Target{float3 tangentWS = normalize(input.tangentWS);float3 normalWS = normalize(input.normalWS);float3 bitangentWS = normalize(input.bitangentWS);float3 lightDirWS = normalize(UnityWorldSpaceLightDir(input.posWS.xyz));float3 viewDirWS = normalize(UnityWorldSpaceViewDir(input.posWS.xyz));float2 uv = input.uv;//背面处理if(backFace<0){float2 backUV = float2(1-uv.x,uv.y);float4 backTextureSample = tex2D(_BackTexture,backUV*_BackTexture_ST.xy + _BackTexture_ST.zw);return backTextureSample;}//下面都是正面的了float3x3 TBN_WS2TS = float3x3(tangentWS,bitangentWS,normalWS);  //  世界-》切线变换矩阵float3 viewDirTS = mul(TBN_WS2TS, viewDirWS);//为什么需要在切线空间计算呢?因为深度值是相对于切线空间定义的//计算经深度值影响过后的uvfloat2 uv1AfterDepth = CalculateRealUVAfterDepth(uv, viewDirTS, _ParallaxDepth1);float2 uv2AfterDepth = CalculateRealUVAfterDepth(uv, viewDirTS, _ParallaxDepth2);//采样视差图1uv1AfterDepth = saturate(uv1AfterDepth);float4 _ParallaxTexture1Sample = tex2D(_ParallaxTexture1,uv1AfterDepth*_ParallaxTexture1_ST.xy + _ParallaxTexture1_ST.zw);//采样视差图2uv2AfterDepth += -_FlowVector2AndSpeed.xy * _Time.y * _FlowVector2AndSpeed.z;float4 _ParallaxTexture2Sample = tex2D(_ParallaxTexture2,uv2AfterDepth*_ParallaxTexture2_ST.xy + _ParallaxTexture2_ST.zw);//采样边框float4 _FrameTextureSample = tex2D(_FrameTexture,uv*_FrameTexture_ST.xy + _FrameTexture_ST.zw);float4 finalCol = float4(0,0,0,1);finalCol = _ParallaxTexture2Sample;finalCol = lerp(finalCol,_ParallaxTexture1Sample,_ParallaxTexture1Sample.a);finalCol += _FrameTextureSample;return finalCol;}ENDCG}}
}

库文件:CommonCGinclude.cginc

#ifndef COMMONCGINCLUDE
#define COMMONCGINCLUDEstruct MeshData
{float4 vertex : POSITION;float2 uv : TEXCOORD0;float2 uv2 : TEXCOORD1;float4 tangentOS :TANGENT;float3 normalOS : NORMAL;float4 vertexColor : COLOR;
};struct V2FData
{float4 pos : SV_POSITION; // 必须命名为pos ,因为 TRANSFER_VERTEX_TO_FRAGMENT 是这么命名的,为了正确地获取到Shadowfloat2 uv : TEXCOORD0;float3 tangentWS : TEXCOORD1;float3 bitangentWS : TEXCOORD2;float3 normalWS : TEXCOORD3;float3 posWS : TEXCOORD4;float3 posOS : TEXCOORD5;float3 normalOS : TEXCOORD6;float4 vertexColor : TEXCOORD7;float2 uv2 : TEXCOORD8;
};V2FData FillBaseV2FData(MeshData input)
{V2FData output;output.pos = UnityObjectToClipPos(input.vertex);output.uv = input.uv;output.uv2 = input.uv2;output.normalWS = normalize(UnityObjectToWorldNormal(input.normalOS));output.posWS = mul(unity_ObjectToWorld, input.vertex);output.posOS = input.vertex.xyz;output.tangentWS = normalize(UnityObjectToWorldDir(input.tangentOS));output.bitangentWS = cross(output.normalWS, output.tangentWS) * input.tangentOS.w; //乘上input.tangentOS.w 是unity引擎的bug,有的模型是 1 有的模型是 -1,必须这么写output.normalOS = input.normalOS;output.vertexColor = input.vertexColor;return output;
}#endif

在面板上这样赋值即可获得这样的效果

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端 TS 语法继承 多态 修饰符 readonly 抽象类 ts 基本写法 可选 剩余参数 函数重载 接口 类(3)

继承 继承之间的叫法 A类继承了B类&#xff0c;那么A类叫做子类&#xff0c;B类叫成基类 子类 ---》派生类 基类 ---》超类&#xff08;父类&#xff09; // 继承之间的叫法 // A类继承了B类&#xff0c;那么A类叫做子类&#xff0c;B类叫成基类 // 子类 ---》派生类 // 基类 …

2024年美国大学生数学建模思路 - 复盘:校园消费行为分析

文章目录 0 赛题思路1 赛题背景2 分析目标3 数据说明4 数据预处理5 数据分析5.1 食堂就餐行为分析5.2 学生消费行为分析 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 赛题背景 校园一卡通是集…

黑马程序员 Docker笔记

本篇学习笔记文档对应B站视频&#xff1a; 暂时无法在飞书文档外展示此内容 同学们&#xff0c;在前两天我们学习了Linux操作系统的常见命令以及如何在Linux上部署一个单体项目。大家想一想自己最大的感受是什么&#xff1f; 我相信&#xff0c;除了个别天赋异禀的同学以外&a…

不要再搞混标准化与归一化啦,数据标准化与数据归一化的区别!!

数据标准化与归一化 1. 数据的标准化&#xff08;Standardization&#xff09;&#xff1a;2. 数据的归一化&#xff08;Normalization&#xff09;&#xff1a;总结&#xff08;数据标准化和数据归一化的不同之处和相同之处&#xff09; 1. 数据的标准化&#xff08;Standardi…

【LabVIEW FPGA 编程入门】使用FPGA IO进行编程

1.在项目中新建一个VI&#xff0c;命名为FPGA IO Test。 2. 可以直接将项目中的FPGA IO拖入程序框图中。 FPGA IO的类型&#xff1a; 数字线&#xff1a; 数字端口&#xff1a; 模拟IO&#xff1a; 其他&#xff1a; 3.如果新增加了FPGA资源&#xff0c;不是创建项目时扫描到的…

【数据结构】二叉树问题总结

目录 1.二叉树前序遍历&#xff0c;中序遍历和后序的实现 2.层序遍历 3.求二叉树中的节点个数 4.求二叉树中的叶子节点个数 5.求二叉树的高度 6.求二叉树第k层节点个数 7.二叉树查找值为x的节点 8.单值二叉树 9.二叉树最大深度 10.翻转二叉树 11. 检查两颗树是否相同…

【SAP】如何删除控制范围

经历就是财富&#xff0c;可你终将遗忘。期望文字打败时间。 本周心惊胆战地在配置系统删除了一个控制范围&#xff0c;还是有些收获&#xff0c;特此记录一下。 背景&#xff1a;在删除控制范围之前&#xff0c;我主要做了如下配置。 定义控制范围&#xff08;自动生成了成本…

Unable to find node on an unmounted component in React

小众错误一枚&#xff0c;网上都说需要react版本没有升级原因&#xff0c;因为是内部错误&#xff0c;控制台又无法定位到代码哪一行报错&#xff0c;网上又没有类似的解决方法&#xff0c;特此记录思路&#xff0c;供大家参考。 通过网上说的版本原因&#xff0c;合理推测是因…

如何创建并格式化硬盘分区?

一般将新硬盘连接到计算机后&#xff0c;需先创建并格式化硬盘分区。否则在磁盘管理中会显示为“未分配空间”&#xff0c;并在文件资源管理器中不可见。那我们如何在硬盘上创建新分区&#xff0c;并对新分区进行格式化&#xff1f; 方法1. 通过命令提示符 首先&#xff0c;我…

C#,入门教程(17)——条件语句(if-else)的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(16)——可变数据类型&#xff08;var&#xff09;的基础知识与使用禁忌https://blog.csdn.net/beijinghorn/article/details/124032216 程序的核心是逻辑。 逻辑的核心是布尔条件表达式。 逻辑的主要体现形式之一是 if-else 语句…

Unity中URP中的光照简介

文章目录 前言URP下的光照在Unity中的设置1、主灯设置2、额外灯设置3、反射光设置 前言 我们在这篇文章开始了解URP下的光照。 URP下的光照在Unity中的设置 1、主灯设置 主灯可以选择 禁用 或 逐像素 光照 当选择逐像素光照的主灯后 Cast Shadows&#xff1a;可以选择开启 或…

Redis 中的哨兵选举算法是如何实现的?

“Redis 中的哨兵选举算法是如何实现的&#xff1f;” 昨天&#xff0c;一个工作 7 年的粉丝&#xff0c;去某外包公司面试&#xff0c;被问到这个问题不知道该怎么回答。 今天正好有空&#xff0c;给大家分享一下这个问题的回答思路。 对了&#xff0c;这个问题在我之前整理…