本文主要是介绍Unity中Shader面片一直面向摄像机,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 前言
- 一、实现思路
- 1、 我们要实现模型面片一直跟着摄像机旋转,那么就需要用到旋转矩阵
- 2、确定 原坐标系 和 目标坐标系
- 3、确定旋转后坐标系基向量
- 二、确定旋转后 坐标系基向量 在 原坐标系 下的值
- 1、Z轴基向量
- 2、假设Y轴基向量 和 世界空间下 的Y轴方向一致竖直向上
- 3、X轴基向量
- 4、Y轴基向量
- 三、顶点应用旋转
- 法一:向量乘法
- 法二:矩阵乘法
- 最后转化到齐次裁剪空间
- 四、最终效果
- 最终测试代码
前言
在之前的文章中,我们实现了Shader的序列帧动画。
- Unity中Shader序列帧动画(总结篇)
但是,我们会发现,我们的面片不会一直面向摄像机,当摄像机移动时,人物或特效就会出现穿帮的效果。所以,我们接下来就来实现让我们的面片面向摄像机。
类似的功能,还可能用于:特效、公告牌、八方旅人风格效果、饥荒风格效果。
一、实现思路
1、 我们要实现模型面片一直跟着摄像机旋转,那么就需要用到旋转矩阵
- Unity中Shader旋转矩阵(二维旋转矩阵)
- Unity中Shader旋转矩阵(四维旋转矩阵)
- Unity中Shader矩阵变换的几何体现
2、确定 原坐标系 和 目标坐标系
- 原坐标系 就是模型的本地坐标
- 目标坐标系
因为我们的面片需要一直朝向摄像机。
所以,可以确定旋转后的坐标系Z轴方向 需要 和 原模型本地空间坐标系原点 指向 摄像机 方向一致。
3、确定旋转后坐标系基向量
二、确定旋转后 坐标系基向量 在 原坐标系 下的值
1、Z轴基向量
- 求 摄像机坐标 在模型本地空间下的坐标值,在 归一化后 就是 Z轴基向量
float3 viewDir = mul(GetWorldToObjectMatrix(),float4(_WorldSpaceCameraPos,1)).xyz;
2、假设Y轴基向量 和 世界空间下 的Y轴方向一致竖直向上
float3 upDir = float3(0,1,0);
3、X轴基向量
-
X轴基向量 = Z轴基向量 × Y轴基向量
-
叉积 的顺序取决于 坐标系类型 (逆时针叉积)
-
模型本地空间坐标系为左手坐标系
-
左手坐标系中,X轴 = 食指 × 拇指 = Z × Y
float3 rightDir = normalize(cross(viewDir,upDir));
4、Y轴基向量
- Y轴基向量 = X轴基向量 × Z轴基向量
- 叉积 的顺序取决于 坐标系类型 (逆时针叉积)
- 模型本地空间坐标系为左手坐标系
- 左手坐标系中,Y轴 = 中指 × 食指 = X × Z
upDir = normalize(cross(rightDir,viewDir));
三、顶点应用旋转
法一:向量乘法
- n e w P o s O S = X 基向量 ∗ p o s O S x + Y 基向量 ∗ p o s O S y + Z 基向量 ∗ p o s O S z newPosOS = X基向量*posOS_x + Y基向量*posOS_y+Z基向量*posOS_z newPosOS=X基向量∗posOSx+Y基向量∗posOSy+Z基向量∗posOSz
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);
四、最终效果
最终测试代码
Shader "MyShader/URP/P3_10_1"
{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)}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;CBUFFER_ENDTEXTURE2D(_MainTex);SAMPLER(sampler_MainTex);Varying vert(Attribute v){Varying o;//Z轴基向量float3 viewDir = mul(GetWorldToObjectMatrix(),float4(_WorldSpaceCameraPos,1)).xyz;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}}}
这篇关于Unity中Shader面片一直面向摄像机的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!