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

这篇具有很好参考价值的文章主要介绍了Unity中Shader裁剪空间推导(在Shader中实现)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

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

  • 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 中修改项目渲染平台设置
    unity 裁切空间,Unity,unity,游戏引擎

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

  • 传入当前摄像机信息
    unity 裁切空间,Unity,unity,游戏引擎

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

  • Edit->ProjectSetting->Player 中修改项目渲染平台设置
    unity 裁切空间,Unity,unity,游戏引擎

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

  • 传入当前摄像机信息
    unity 裁切空间,Unity,unity,游戏引擎

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

裁剪空间下的近剪裁值,(DX为1,OpenGL为-1).文章来源地址https://www.toymoban.com/news/detail-779863.html

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_END
            
            TEXTURE2D(_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_world
                float3 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_view
                float4x4 M_clip;
                if(UNITY_NEAR_CLIP_VALUE==-1)
                {
                    //OpenGL
                    M_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)
                {
                    //DirectX
                    M_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
        }
    }
}


到了这里,关于Unity中Shader裁剪空间推导(在Shader中实现)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity游戏图形学 Shader结构

    openGL:SLG跨平台 =GLSL:openGL shaderlauguge DX:微软开发,性能很好,但是不能跨平台 =HLSL:high level shader language CG:微软和Nvidia公司联合开发,跨平台,基于c语言开发,性能很好 openGL、dx、cg都包含 CG和HLSL包括在 CGPROGRAM...ENDCG 语法快内 GLSL包括在 GLSLPROGRAM...ENDGLSL 语法快内 自己

    2024年02月01日
    浏览(35)
  • 【Unity实战篇 】| 游戏中实现镂空遮罩效果【矩形、圆形镂空遮罩】

    前言 本文来写一下怎样在Unity中完成一个 镂空遮罩 的效果。 镂空遮罩 比较常用的有两种ÿ

    2024年02月15日
    浏览(75)
  • 【游戏开发小技】Unity通过UI全屏图来模糊场景画面(Shader | 模糊 | 滤镜 | Blur)

    一、前言 嗨,大家好,我是新发。 以前我写文章都是很长很长,接下来我会尝试用新的方式来写博客,尽量简短,以实用为主。同时也是作为自己零碎的一些记录,方便查阅。 本文我要说的是在 Unity 中通过 UI 全屏图来模糊场景画面的效果。 二、效果演示 这是没用模糊效果

    2024年02月05日
    浏览(32)
  • Unity空间与运动(中山大学3D游戏作业3)

    代码仓库:https://github.com/linfn3/3d_game b站视频:https://www.bilibili.com/video/BV1YD4y1r7GR/?vd_source=6d44ed4eff5157be7cd6838983f17b44 物体运动的本质 unity中物体运动的本质是游戏对象的位置和状态变化。 三种方法实现抛物线运动 使用translate方法 将transfrom.position1加上改变向量 position加减实现

    2024年02月03日
    浏览(36)
  • 【游戏开发小技】Unity中实现Dota里的角色技能地面贴花效果(URP ShaderGraph Decal)(1)

    [Toggle(_SupportOrthographicCamera)] _SupportOrthographicCamera(“_SupportOrthographicCamera (default = off)”, Float) = 0 } SubShader { // 关于tags的内容可以查阅官网手册:https://docs.unity3d.com/Manual/SL-SubShaderTags.html // 为了避免渲染顺序问题, Queue必须 = 2501, 它位于透明队列中 // 在透明队列中,Unity总是从后

    2024年04月16日
    浏览(42)
  • 【Unity3D】Unity 脚本 ③ ( C# 脚本的执行入口函数 | 获取当前游戏物体及物体名称 | 获取游戏物体的 Transform 组件数据 | UnityEngine 命名空间简介 )

    在 C# 脚本中控制 游戏物体 GameObject 运动 , 要先获取该物体 , 然后 修改其 Transform 组件的属性 ; 在 游戏开始运行后 , 会自动执行 游戏物体 GameObject 上的 C# 组件代码 , 程序入口是 MonoBehaviour#Start() 函数 ; 在 C# 脚本中 , 主要的内容都在 Start() 函数 中实现 ; 在 C# 脚本中 , 游戏物体

    2023年04月12日
    浏览(59)
  • 微信小程序分享的图片被裁切了。怎么让他不裁剪正常比例5:4显示

     现在的效果 希望的效果  最主要的是下面的这个函数。把图片转成了5:4的临时图片  页面上。使用定位让用户看不到这个绘图,但是实际上只是不出现在可视范围内 然后调用函数把你的图片换成这个临时的图片 }

    2024年02月09日
    浏览(36)
  • 【Unity Shader】Unity阴影

    记录下在unity中如果想实现阴影,有哪些路子可以选择,目前看有两种 1.经典的shadowmap 2.planar projection 如果开启renderer组件的cast shadows为on,开启平行光的light组件的shadow type,那么就会在物体shader中寻找LightMode=ShadowCaster的Pass进行渲染 场景有两个物体,平面和球体,使用unity内

    2024年02月09日
    浏览(42)
  • Unity | Shader基础知识(第一集:unity中最简单的shader)

    目录 一、unity的shader 二、创建一个shader(在创建时,选前三种都可以) 三、内容解读 1.shader一直都在 2.我们写shader在写什么 四、没有被干预的shader(最简单的shader) 相关阅读 编写着色器概述 - Unity 手册 一、unity的shader unity写的shader并不是真正意义上的shader。 官方解释:

    2024年02月04日
    浏览(42)
  • 【Unity Shader】Unity前向渲染

    ForwardBase Pass(优先渲染),渲染一个逐像素平行光和所有的顶点/球面调和光,阴影只和平行光有关系,那阴影应该是这个Pass中实现的 ForwardAdd Pass(需要和Base配合使用,否则不生效),渲染剩余全部逐像素灯光 Unity会根据场景中各个光源的设置以及这些光源对物体的影响程

    2024年02月08日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包