Unity中Shader裁剪空间推导(在Shader中实现)

文章目录

  • 前言
  • 一、在Shader中,手动把正交相机的坐标转化到裁剪空间
    • 1、我们在属性面板定义一个变量,用于传入摄像机的信息
    • 2、获取h、r、w、n、f
    • 3、获取OpenGL下的转化矩阵
    • 4、 获取DirectX下的转化矩阵
    • 5、手动将观察空间下的坐标转换到裁剪空间下
    • 6、这里为测试模型效果,进行了纹理采样(可选)
  • 二、最终效果
    • 1、OpenGL下:
    • 2、DirectX下(需要注意的是,在DX平台下屏幕的 y 坐标是相反的,需要在转化矩阵的 y 对应位置乘以 -1):
    • 3、可以使用 UNITY_NEAR_CLIP_VALUE 来判断是什么平台
    • 4、最终代码


前言

我们在上一篇文章中,进行了正交相机视图空间下转化到裁剪空间下的矩阵推导。

  • Unity中Shader裁剪空间推导(正交相机到裁剪空间的转化矩阵)

我们在这篇文章中,在Unity的Shader中实现一下。


一、在Shader中,手动把正交相机的坐标转化到裁剪空间

  • OpenGL下:

[ 2 w 0 0 0 0 2 h 0 0 0 0 2 n − f n + f n − f 0 0 0 1 ] \begin{bmatrix} \frac{2}{w} & 0 & 0 & 0 \\ 0 & \frac{2}{h} & 0 &0\\ 0 & 0 & \frac{2}{n -f} &\frac{n + f}{n - f}\\ 0 & 0 & 0 & 1\\ \end{bmatrix} w20000h20000nf2000nfn+f1

  • DirectX下:

[ 2 w 0 0 0 0 2 h 0 0 0 0 1 n − f n n − f 0 0 0 1 ] \begin{bmatrix} \frac{2}{w} & 0 & 0 & 0 \\ 0 & \frac{2}{h} & 0 &0\\ 0 & 0 & \frac{1}{n -f} &\frac{n}{n - f}\\ 0 & 0 & 0 & 1\\ \end{bmatrix} w20000h20000nf1000nfn1

  • ReversedZ

在DirectX中,因为精度问题
会把原本的范围从[0,1]修改为[1,0]。所以,矩阵需要按照之前的方法重新推导

[ 2 w 0 0 0 0 2 h 0 0 0 0 1 f − n f f − n 0 0 0 1 ] \begin{bmatrix} \frac{2}{w} & 0 & 0 & 0 \\ 0 & \frac{2}{h} & 0 &0\\ 0 & 0 & \frac{1}{f-n} &\frac{f}{f-n}\\ 0 & 0 & 0 & 1\\ \end{bmatrix} w20000h20000fn1000fnf1

1、我们在属性面板定义一个变量,用于传入摄像机的信息

这里信息包括:
摄像机的Size(X)、近裁剪面(Y)、远裁剪面(Z) 和 屏幕宽高比(W)
1.7777……是 1920 / 1080 的比值。

_CameraParams(“Size(X),Near(Y),Far(Z) Ratio(W)”,Vector) = (0,0,0,1.777)

2、获取h、r、w、n、f

float h = _CameraParams.x * 2;
float w = h * _CameraParams.w;
float n = _CameraParams.y;
float f = _CameraParams.z;

3、获取OpenGL下的转化矩阵

//OpenGL
float4x4 M_clip01 = float4x4
(2/w,0,0,0,0,2/h,0,0,0,0,2/(n - f),(n + f) / (n - f),0,0,0,1
);

4、 获取DirectX下的转化矩阵

//DirectX
float4x4 M_clip02 = float4x4
(2/w,0,0,0,0,2/h,0,0,0,0,1/(f-n),f/(f-n),0,0,0,1
);

5、手动将观察空间下的坐标转换到裁剪空间下

//手动将观察空间下的坐标转换到裁剪空间下
o.vertexCS = mul(M_clip01,float4(vertexVS,1));

6、这里为测试模型效果,进行了纹理采样(可选)

  • 属性面板接收纹理

_MainTex(“MainTex”,2D) = “white”{}

  • 定义纹理 和 采样器

TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);

  • 在片元着色器中,采样并且使用

float4 mainTex = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,i.uv);
return mainTex;


二、最终效果

1、OpenGL下:

  • Edit->ProjectSetting->Player 中修改项目渲染平台设置
    在这里插入图片描述

//手动将观察空间下的坐标转换到裁剪空间下
o.vertexCS = mul(M_clip01,float4(vertexVS,1));

  • 传入当前摄像机信息
    在这里插入图片描述

2、DirectX下(需要注意的是,在DX平台下屏幕的 y 坐标是相反的,需要在转化矩阵的 y 对应位置乘以 -1):

  • Edit->ProjectSetting->Player 中修改项目渲染平台设置
    在这里插入图片描述

//手动将观察空间下的坐标转换到裁剪空间下
o.vertexCS = mul(M_clip02,float4(vertexVS,1));

  • 传入当前摄像机信息
    在这里插入图片描述

3、可以使用 UNITY_NEAR_CLIP_VALUE 来判断是什么平台

裁剪空间下的近剪裁值,(DX为1,OpenGL为-1).

4、最终代码

//平移变换
//缩放变换
//旋转变换(四维)
//视图空间矩阵
//正交相机视图空间 -> 裁剪空间
Shader "MyShader/URP/P3_7_3"
{Properties{[Header(MainTexx)]_MainTex("MainTex",2D) = "white"{}[Header(Transtion)]_Translate("Translate(XYZ)",Vector) = (0,0,0,0)_Scale("Scale(XYZ)",Vector)= (1,1,1,1)_Rotation("Rotation(XYZ)",Vector) = (0,0,0,0)[Header(View)]_ViewPos("View Pos",vector) = (0,0,0,0)_ViewTarget("View Target",vector) = (0,0,0,0)[Header(Camera)]_CameraParams("Size(X),Near(Y),Far(Z) Ratio(W)",Vector) = (0,0,0,1.777)}SubShader{Tags{"PenderPipeline"="UniversalPipeline""RenderType"="Opaque""Queue"="Geometry"}Pass{HLSLPROGRAM#pragma vertex vert#pragma fragment frag#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 : TEXCOORD0;};CBUFFER_START(UnityPerMaterial)float4 _Translate;float4 _Scale;float4 _Rotation;float4 _ViewPos;float4 _ViewTarget;float4 _CameraParams;CBUFFER_ENDTEXTURE2D(_MainTex);SAMPLER(sampler_MainTex);Varying vert (Attribute v){Varying o;o.uv = v.uv;//平移变换float4x4 M_Translate = float4x4(1,0,0,_Translate.x,0,1,0,_Translate.y,0,0,1,_Translate.z,0,0,0,1);v.vertexOS = mul(M_Translate,v.vertexOS);//缩放交换float4x4 M_Scale = float4x4(_Scale.x,0,0,0,0,_Scale.y,0,0,0,0,_Scale.z,0,0,0,0,1);v.vertexOS = mul(M_Scale,v.vertexOS);//旋转变换float4x4 M_rotateX = float4x4(1,0,0,0,0,cos(_Rotation.x),sin(_Rotation.x),0,0,-sin(_Rotation.x),cos(_Rotation.x),0,0,0,0,1);float4x4 M_rotateY = float4x4(cos(_Rotation.y),0,sin(_Rotation.y),0,0,1,0,0,-sin(_Rotation.y),0,cos(_Rotation.y),0,0,0,0,1);float4x4 M_rotateZ = float4x4(cos(_Rotation.z),sin(_Rotation.z),0,0,-sin(_Rotation.z),cos(_Rotation.z),0,0,0,0,1,0,0,0,0,1);v.vertexOS = mul(M_rotateX,v.vertexOS);v.vertexOS = mul(M_rotateY,v.vertexOS);v.vertexOS = mul(M_rotateZ,v.vertexOS);//观察空间矩阵推导//P_view = [W_view] * P_world//P_view = [V_world]^-1 * P_world//P_view = [V_world]^T * P_worldfloat3 ViewZ = normalize(_ViewPos - _ViewTarget);float3 ViewY = float3(0,1,0);float3 ViewX = cross(ViewZ,ViewY);ViewY = cross(ViewX,ViewZ);float4x4 M_viewTemp = float4x4(ViewX.x,ViewX.y,ViewX.z,0,ViewY.x,ViewY.y,ViewY.z,0,ViewZ.x,ViewZ.y,ViewZ.z,0,0,0,0,1);float4x4 M_viewTranslate = float4x4(1,0,0,-_ViewPos.x,0,1,0,-_ViewPos.y,0,0,1,-_ViewPos.z,0,0,0,1);float4x4 M_view = mul(M_viewTemp,M_viewTranslate);float3 vertexWS = TransformObjectToWorld(v.vertexOS);//世界空间转化到观察空间float3 vertexVS = mul(M_view,float4(vertexWS,1));//相机参数float h = _CameraParams.x * 2;float w = h * _CameraParams.w;float n = _CameraParams.y;float f = _CameraParams.z;//正交相机投影矩阵//P_Clip = [M_Clip] * P_viewfloat4x4 M_clip;if(UNITY_NEAR_CLIP_VALUE==-1){//OpenGLM_clip = float4x4(2/w,0,0,0,0,2/h,0,0,0,0,2/(n - f),(n + f) / (n - f),0,0,0,1);}if(UNITY_NEAR_CLIP_VALUE==1){//DirectXM_clip = float4x4(2/w,0,0,0,0,-2/h,0,0,0,0,1/(f-n),f/(f-n),0,0,0,1);}//手动将观察空间下的坐标转换到裁剪空间下o.vertexCS = mul(M_clip,float4(vertexVS,1));//观察空间 转化到 齐次裁剪空间//o.vertexCS = TransformWViewToHClip(vertexVS);//o.vertexCS = TransformObjectToHClip(v.vertexOS.xyz);return o;}half4 frag (Varying i) : SV_Target{float4 mainTex = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,i.uv);return mainTex;}ENDHLSL}}
}

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

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

相关文章

MR实战:统计总分与平均分

文章目录 一、实战概述二、提出任务三、完成任务(一)准备数据1、在虚拟机上创建文本文件2、上传文件到HDFS指定目录 (二)实现步骤1、创建Maven项目2、添加相关依赖3、创建日志属性文件4、创建成绩映射器类5、创建成绩驱动器类6、启…

新手如何快速熟悉代码,写出东西(持续更新)

目录 第一章、最小编程任务的设想1.1)程序员入门会遇到的问题1.2)编程任务的设想 第二章、编程任务的练习2.1)代码初级练习2.2)项目中级练习2.3)其他编程练习 第三章、其他任务练习3.1)中间件使用3.2&#…

操作索引库-mapping属性

目录 一、mapping属性 二、总结 一、mapping属性 mapping是对索引库中文档的约束,常见的mapping属性包括: type:字段数据类型,常见的简单类型有: 字符串: text (可分词的文本)、keyword (精确值,例如:品…

JavaScript基础知识点总结:从零开始学习JavaScript(三)

如果大家感感兴趣也可以去看: 🎉博客主页:阿猫的故乡 🎉系列专栏:JavaScript专题栏 🎉ajax专栏:ajax知识点 🎉欢迎关注:👍点赞🙌收藏✍️留言 学习…

2024重新洗牌“IT界”,是谁给它的底气?

​在2023年下半年" IT界"最引发程序员关注的热点话题就是鸿蒙了。 就今年9月25日,从华为发布会宣布明年2024将推出HarmonyOS NEXT版本后,这意味着”鸿蒙不再与android兼容“。鸿蒙将与安卓、ios形成”三足鼎立“之势。 鸿蒙激起千层浪 12月…

Kibana操作ElasticSearch

1、索引操作 1.1、新增索引 a、创建索引默认配置 PUT /索引名称 b、创建索引指定字段类型 put /索引名称/_mapping/typeName {"properties":{"字段名":{"type":"类型", text keyword long short date integer object"index&quo…

2023安洵杯-秦岭防御军wp

reverse 感觉有点点简单## import base64 def ba64_decode(str1_1):mapp "4KBbSzwWClkZ2gsr1qAQu0FtxOm6/iVcJHPY9GNp7EaRoDf8UvIjnL5MydTX3eh"data_1 [0] * 4flag_1 [0] * 3for i in range(32, 127):for y in range(32, 127):for k in range(32, 127):flag_1[0]…

【RocketMQ笔记02】安装RocketMQ可视化工具rocketmq-dashboard

这篇文章,主要介绍如何安装RocketMQ可视化工具rocketmq-dashboard。 目录 一、RocketMQ可视化界面 1.1、下载rocketmq-dashboard 1.2、修改配置文件 1.3、打包工程 1.4、启动rocketmq-dashboard 一、RocketMQ可视化界面 1.1、下载rocketmq-dashboard rocketm…

TYPE C 接口知识

1、Type C 概述 Type-C口有4对TX/RX分线,2对USBD/D-,一对SBU,2个CC,另外还有4个VBUS和4个地线。 当Type-C接口仅用作传输DP信号时,则可利用4对TX/RX,从而实现4Lane传输,这种模式称为DPonly模式…

【Leetcode】重排链表、旋转链表、反转链表||

目录 💡重排链表 题目描述 方法一: 方法二: 💡旋转链表 题目描述 方法: 💡反转链表|| 题目描述 方法: 💡总结 💡重排链表 题目描述 给定一个单链表 L 的头节…

软件测试/测试开发丨Python 装饰器常见的报错信息、原因和解决方案

Python 装饰器简介 装饰器(Decorator)是 Python 非常实用的一个语法糖功能。装饰器本质是一种返回值也是函数的函数,可以称之为“函数的函数”。其目的是在不对现有函数进行修改的情况下,实现额外的功能。 在 Python 中&#xf…

C#学习笔记 - C#基础知识 - C#从入门到放弃 - C# 接口、抽象与密封

C# 入门基础知识 - C# 接口、抽象与密封 第10节 接口、抽象与密封10.1 接口的声明10.2 接口的实现和继承10.3 显式实现接口10.4 抽象类与抽象方法声明10.5 抽象方法(abstract)方法与虚方法(virtual)方法10.6 密封类与密封方法10.7 接口综合运用实践 更多C#基础知识点可查看&…

ueditor富文本编辑器中图片上传地址配置以及抓取远程图片地址的配置

一:图片上传保存地址配置 打开文件ueditor.php,找到imagePathFormat进行修改即可 一:远程抓取图片配置 打开文件ueditor.config.js,找到catchRemoteImageEnable,取消注释即可

2024年元旦节放假通知

致尊敬的客户以及全体同仁: 旧岁已展千重锦,新年再进百尺竿。在这辞旧迎新之际,易天光通信提前祝您元旦快乐!生意兴隆,身体健康,万事如意!根据国家法定假期的规定,并结合公司实际情…

使用pycharm虚拟环境和使用conda管理虚拟环境的区别

使用 PyCharm 虚拟环境和使用 Conda 管理虚拟环境有一些区别,主要涉及到环境的创建、依赖管理、跨平台性等方面。以下是一些关键区别: 创建环境: PyCharm 虚拟环境: PyCharm 使用其自己的虚拟环境管理器(通常是 venv&a…

开源verilog模拟 iverilog verilator +gtkwave仿真及一点区别

开源的 iverilog verilator 和商业软件动不动几G几十G相比,体积小的几乎可以忽略不计。 两个都比较好用,各有优势。 iverilog兼容性好。 verilator速度快。 配上gtkwave 看波形,仿真工具基本就齐了。 说下基本用法 计数器 counter.v module…

【接口测试】Postman(一)--接口测试知识准备 _

1.0 前言 ​ 应用程序编程接口(Application Programming Interface, API)是这些年来最流行的技术之一,强大的Web应用程序和领先的移动应用程序都离不开后端强大的API。API技术的应用给系统开发带来了便利,但也对测试人员提出了更高…

Redis主从切换(单点故障)解决源码

1、使用过程: 发布创建channel1消息 redis-cli> PUBLISH channel1 "Hello, world!" redis-cli> SUBSCRIBE channel1 优点: 1、采用Reactor事件单线程去驱动发布订阅事件的,实时性高。 2、从redis架构去思考,拓展哨…

4.vue学习笔记(事件处理+事件参数+事件修饰符)

文章目录 1.事件处理1.1.内联事件处理器 2.事件参数2.1.传参过程中获取Event 3.事件修饰符3.1.阻止默认事件阻止事件冒泡 1.事件处理 我们可以使用v-on指令(简写为)来监听DOM事件,并在事件触发时执行对应的JavaScript。 用法:v-o…

ubuntu服务器上安装KVM虚拟化

今天想着在ubuntu上来安装一个windwos操作系统,原因是因为我们楼上有几台不错的服务器,但是都是linux系统的。 今天我想着要给同事们搭建一个chatgpt环境,用来开发程序,但是ubuntu上其实也可以安装我嫌麻烦,刚好想折腾…