CGPROGRRAM &(URP) HLSLPROGRAM (各种)坐标系转化(重点重点非常重点)

   一,原理

    整理这篇文章的原因是,前段时间项目主要用的是CG语言,最近项目用的是HLSL语言。为什么图形这块会转HLSL语言呢? 其实是CG语言已经很久不更新了,且垮平台压力比较大;HLSL是微软DX着色器汇编语言(当然也不完全一样),HLSL其实并不能与OpenGL兼容,但这也难不倒Unity(咱们可以编译,哈哈 )。言归正传,咱们线看一张图:

                                空间坐标系转换原理 :

 注意:一个顶点坐标从模型到最终渲染到屏幕中需要经过顶点变换(顶点要经过多个坐标空间的转化常能映射到屏幕上)。

             

 模型空间:以模型原点为参照物,当模型Transform改变的时候,模型空间也会随之改变,模型空间又被称为对象空间或局部空间。

世界空间:世界空间是游戏中最大的坐标空间(好比现实世界的经纬度和高度)。世界空间是基于世界原点坐标(0,0,0),为游戏空间提供一个绝对位置。

观察空间(摄像机空间):摄像机为原点,为游戏提供渲染视角。 Unity 的观察空间是 左手坐标系(正X指向右方,正Y指向上方,正Z轴指向摄像机后方)。

裁剪空间:对处于该空间内的图元进行渲染(裁剪),不处于该空间的图元会被剔除。裁剪区域是摄像机是视锥体决定(视锥体就是摄像机所看见的区域范围,它由六个平面包围。这些平面被称为裁剪平面。视锥体被分为两类:A,正交投影;B,透视投影)。

屏幕空间:最终显示到屏幕的空间,这里我们会得到像素位置,屏幕空间是2维坐标系。

  二,坐标系

       世界坐标系(World Space)

               按照笛卡尔坐标系定义出来的绝对坐标系(空间直角坐标系)。左手坐标系获取方法:Transform.Position 

     本地坐标系(Local Space)====>  模型坐标系

               模型自生坐标。美术建模即创建好,Unity无法修改坐标原点。在shader中默认输入的就是模型坐标 ,获取方法:Transform.LocalPosition

     屏幕坐标系(Screen Space)

               以屏幕作为坐标,左下角为(0,0)

    观察坐标系(ViewPort Space):视口坐标系

              摄像机即观察视角,将画面投影到该视口上,左下角为原点(0,0),右上角为(1,1)

   裁剪坐标 (Clip Space)

            对处于该空间内的图元进行渲染(裁剪),不处于该空间的图元会被剔除。

   UI坐标系

            UI坐标系是可视化窗口的最顶层,世界坐标系的物体都会被UI坐标系遮挡 .   

  UV坐标系

          uv坐标系只负责定位贴图和模型的关系

三,坐标系转化

   

 四,常见的矩阵   

2.1 平移矩阵
float4x4 M_translate = float4x4(
1, 0, 0, T.x,
0, 1, 0, T.y,
0, 0, 1, T.z,
0, 0, 0, 1);

2.2 缩放矩阵
float4x4 M_scale = float4x4(
S.x, 0, 0, 0,
0, S.y, 0, 0,
0, 0, S.z, 0,
0, 0, 0, 1);

旋转矩阵(X轴)
float4x4 M_rotationX = float4x4(
1, 0, 0, 0,
0, cos(θ), -sin(θ), 0,
0, sin(θ), cos(θ), 0,
0, 0, 0, 1);

旋转矩阵(Y轴)
float4x4 M_rotationY = float4x4(
cos(θ), 0, sin(θ), 0,
0, 1, 0, 0,
-sin(θ), 0, cos(θ), 0,
0, 0, 0, 1);

旋转矩阵(Z轴)
float4x4 M_rotationZ = float4x4(
cos(θ), -sin(θ), 0, 0,
sin(θ), cos(θ), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);

将P点从A空间变换到B空间

五,空间转化函数 (代码左右拉可以看CG和 HLSL函数对应)

	//顶点这色器
     
                Varyings o;
               
			       CGPROGRAM 语言                                                                   HLSLPROGRAM 语言
 *****顶点相关
			   //模型空间转为裁剪空间      
			     o.vec = UnityObjectToClipPos(v.vertex);                                     TransformObjectToHClip(positionOS ) ;
			     o.vec =  UnityObjectToClipPos(float4(v.vertex), 1.0));
			   //模型空间转换为观察空间                                                      
			     o.vec =  UnityObjectToViewPos(v.vertex);                                    TransformObjectToWorld(positionOS) ;
			     o.vec =  mul(UNITY_MATRIX_MV, float4(v.vertex), 1.0)).xyz;
			  //从世界空间转到观察空间                                                        //通过左乘UNITY_MATRIX_V矩阵 
			     o.vec =  UnityWorldToViewPos(v.vertex);                                     TransformWorldToView(positionOS) ;
              //模型空间转换到世界空间                                                        //通过左乘UNITY_MATRIX_M矩阵 
			     o.vec =  UnityObjectToWorldDir(v.vertex);                                  TransformObjectToWorld(positionOS) ;
              //观察空间转为裁剪空间
			     o.vec =  UnityViewToClipPos(v.vertex);                                     float4 TransformWViewToHClip(float3 positionVS) ;				                                                                        								 
			 //世界空间转到裁剪空间
                 o.vec =  UnityWorldToClipPos(v.vertex);                                    TransformWorldToHClip(positionWS) ;
             // 世界空间转化为模型空间                                                       //通过左乘UNITY_MATRIX_M矩阵 
			     o.vec =  UnityWorldToObject(v.vertex);                                     TransformWorldToObject(positionWS) ;
 *****法线相关
	        //法线从模型空间转换到世界空间                                                //这里使用右乘的数学意义是,非统一缩放的情况下,直接左乘变换矩阵法线方向会被改动,
                o.normal  =  UnityObjectToWorldNormal(v.vertex);                         //所以需要使用的是变换矩阵中缩放矩阵的逆矩阵,进行左乘。
				                                                                         //又有左乘矩阵和右乘矩阵的转置矩阵是等价的,而旋转矩阵是正交矩阵,其逆矩阵等价于转置矩阵。 
																						 //所以这里使用变换/矩阵的逆矩阵右乘法线,来抵消非统一缩放产生的影响.
																						 TransformObjectToWorldNormal(normalOS);

																						 // 法线–模型空间转世界空间 第二个参数true 对结果进行归一化
                                                                                         float3 TransformObjectToWorldNormal(float3 normalOS, bool doNormalize = true)

		   //世界空间转到模型空间                                                        // 法线–世界空间转模型空间 第二个参数true 对结果进行归一化
                o.normal  =  UnityWorldToObjectDir(v.vertex);                            float3 TransformWorldToObjectNormal(float3 normalWS, bool doNormalize = true)
            


 *****切线相关
                                                                                         //通过右乘世界空间到切线空间的变换矩阵完成逆变换,
		                                                                                 //把切线空间的方向矢量变换到世界空间 
                                                                                            TransformTangentToWorld(tangenOS) ;


                                                                                             //构建矩阵  切线空间转世界空间 
																						      real3 TransformTangentToWorld(real3 dirTS, real3x3 tangentToWorld)
																							  //世界空间转切线空间
																							  real3 TransformWorldToTangent(real3 dirWS, real3x3 tangentToWorld);

																							  //切线空间转模型空间
																							  real3 TransformTangentToObject(real3 dirTS, real3x3 tangentToWorld);

																							  //模型空间转切线空间
																							  real3 TransformObjectToTangent(real3 dirOS, real3x3 tangentToWorld); 



 *****摄像机相关
	      //输入一个object空间顶点位置,返回世界空间中从该点到摄像机的观察方向。
                o.camPos =  WorldSpaceViewDir(v.vertex);
         //输入一个object空间顶点位置,返回object空间中从该点到摄像机的观察方向。
                o.camPos =  ObjSpaceViewDir (v.vertex);


 *****灯光相关	
         //仅用于前向渲染,输入一个object空间顶点的位置,返回世界空间中从该点到光源的光照方向       //通过左乘UNITY_MATRIX_M矩阵,把方向矢量从模型空间变换到世界空间,
                o.LigtDir =  WorldSpaceLightDir (v.vertex);                                     //做了一次归一化以支持统一缩放 ,   
         //仅用于前向渲染,输入一个object空间顶点的位置,返回object空间中从该点到光源的光照方向    // 第二个参数用于判断是否进行归一化 .
                o.LigtDir = ObjSpaceLightDir (v.vertex);                                        TransformObjectToWorldDir(Direction, true) ;
				                                                                               //通过左乘UNITY_MATRIX_I_M矩阵,把方向矢量从世界空间变换到模型空间, 
																							   //做了一次归一化以支持统一缩放 ,
																							   // 第二个参数用于判断是否进行归一化 
																							   TransformWorldToObjectDir(Direction, true) ;

 *****求物体与摄像机距离
        //先将坐标转换至裁剪空间
               float3 viewPos=UnityObjectToClipPos(v.vertex);
	   //物体(顶点)与镜头距离
               float distance=length(viewPos);
 *****求物体(顶点)与摄像机的方向:
      //先将坐标从模型空间转为世界空间
              float3 worldPos=UnityObjectToWorldDir(v.vertex);
     //物体(顶点)与摄像机的方向
              o.viewDir=normalize(UnityWorldSpaceViewDir(worldPos));
                return o;
            }

 *****向量相关  
                                                                                               //向量–模型空间转世界空间 第二个参数true 对结果进行归一化
                                                                                              float3 TransformObjectToWorldDir(float3 dirOS, bool doNormalize = true)

                                                                                              //向量–世界空间转模型空间 第二个参数true 对结果进行归一化
                                                                                              float3 TransformWorldToObjectDir(float3 dirWS, bool doNormalize = true)

                                                                                              //向量–世界空间转观察空间 第二个参数true 对结果进行归一化
                                                                                              real3 TransformWorldToViewDir(real3 dirWS, bool doNormalize = false)

                                                                                              //向量–世界空间转齐次裁剪空间 第二个参数true 对结果进行归一化
                                                                                              real3 TransformWorldToHClipDir(real3 directionWS, bool doNormalize = false)

1,CG:空间转化函数

    
			       CGPROGRAM 语言                                                                 
 *****顶点相关
			   //模型空间转为裁剪空间      
			     o.vec = UnityObjectToClipPos(v.vertex);                                     
			     o.vec =  UnityObjectToClipPos(float4(v.vertex), 1.0));
			   //模型空间转换为观察空间                                                      
			     o.vec =  UnityObjectToViewPos(v.vertex);                                    
			     o.vec =  mul(UNITY_MATRIX_MV, float4(v.vertex), 1.0)).xyz;
			  //从世界空间转到观察空间                                                      
			     o.vec =  UnityWorldToViewPos(v.vertex);                                    
              //模型空间转换到世界空间                                                        
			     o.vec =  UnityObjectToWorldDir(v.vertex);                                  
              //观察空间转为裁剪空间
			     o.vec =  UnityViewToClipPos(v.vertex);                                    				                                                                        								 
			 //世界空间转到裁剪空间
                 o.vec =  UnityWorldToClipPos(v.vertex);                                    
             // 世界空间转化为模型空间                                                     
			     o.vec =  UnityWorldToObject(v.vertex);                                     
 *****法线相关
	        //法线从模型空间转换到世界空间                                                
                o.normal  =  UnityObjectToWorldNormal(v.vertex);                         
				                                                                                                                                                      
		   //世界空间转到模型空间                                                       
                o.normal  =  UnityWorldToObjectDir(v.vertex);                           
            


 *****切线相关
                                                                                        



 *****摄像机相关
	      //输入一个object空间顶点位置,返回世界空间中从该点到摄像机的观察方向。
                o.camPos =  WorldSpaceViewDir(v.vertex);
         //输入一个object空间顶点位置,返回object空间中从该点到摄像机的观察方向。
                o.camPos =  ObjSpaceViewDir (v.vertex);


 *****灯光相关	
         //仅用于前向渲染,输入一个object空间顶点的位置,返回世界空间中从该点到光源的光照方向       
                o.LigtDir =  WorldSpaceLightDir (v.vertex);                                       
         //仅用于前向渲染,输入一个object空间顶点的位置,返回object空间中从该点到光源的光照方向   
                o.LigtDir = ObjSpaceLightDir (v.vertex);                                      																					  

 *****求物体与摄像机距离
        //先将坐标转换至裁剪空间
               float3 viewPos=UnityObjectToClipPos(v.vertex);
	   //物体(顶点)与镜头距离
               float distance=length(viewPos);
 *****求物体(顶点)与摄像机的方向:
      //先将坐标从模型空间转为世界空间
              float3 worldPos=UnityObjectToWorldDir(v.vertex);
     //物体(顶点)与摄像机的方向
              o.viewDir=normalize(UnityWorldSpaceViewDir(worldPos));
                return o;
            }

2,HLSL:空间转化函数

              
			            HLSLPROGRAM 语言
 *****顶点相关
			   //模型空间转为裁剪空间      
			      TransformObjectToHClip(positionOS ) ;
			  
			   //模型空间转换为观察空间                                                      
			      TransformObjectToWorld(positionOS) ;
			   
			  //从世界空间转到观察空间    通过左乘UNITY_MATRIX_V矩阵 
			      TransformWorldToView(positionOS) ;
              //模型空间转换到世界空间    通过左乘UNITY_MATRIX_M矩阵 
			      TransformObjectToWorld(positionOS) ;
              //观察空间转为裁剪空间
			     float4 TransformWViewToHClip(float3 positionVS) ;				                                                                        								 
			 //世界空间转到裁剪空间
                  TransformWorldToHClip(positionWS) ;
             // 世界空间转化为模型空间  通过左乘UNITY_MATRIX_M矩阵 
			     TransformWorldToObject(positionWS) ;
 *****法线相关
	        //法线从模型空间转换到世界空间    //这里使用右乘的数学意义是,非统一缩放的情况下,直接左乘变换矩阵法线方向会被改动,
                                            //所以需要使用的是变换矩阵中缩放矩阵的逆矩阵,进行左乘。
				                            //又有左乘矩阵和右乘矩阵的转置矩阵是等价的,而旋转矩阵是正交矩阵,其逆矩阵等价于转置矩阵。 
											//所以这里使用变换/矩阵的逆矩阵右乘法线,来抵消非统一缩放产生的影响.
				TransformObjectToWorldNormal(normalOS);

			// 法线–模型空间转世界空间 第二个参数true 对结果进行归一化
                float3 TransformObjectToWorldNormal(float3 normalOS, bool doNormalize = true)

		   //世界空间转到模型空间   法线–世界空间转模型空间 第二个参数true 对结果进行归一化
                float3 TransformWorldToObjectNormal(float3 normalWS, bool doNormalize = true)
            


 *****切线相关
           //通过右乘世界空间到切线空间的变换矩阵完成逆变换,
		   //把切线空间的方向矢量变换到世界空间 
           TransformTangentToWorld(tangenOS) ;


           //构建矩阵  切线空间转世界空间 
		   real3 TransformTangentToWorld(real3 dirTS, real3x3 tangentToWorld)
		   //世界空间转切线空间
		   real3 TransformWorldToTangent(real3 dirWS, real3x3 tangentToWorld);

			//切线空间转模型空间
			real3 TransformTangentToObject(real3 dirTS, real3x3 tangentToWorld);

			//模型空间转切线空间
			real3 TransformObjectToTangent(real3 dirOS, real3x3 tangentToWorld); 



 *****摄像机相关
	      //输入一个object空间顶点位置,返回世界空间中从该点到摄像机的观察方向。
                o.camPos =  WorldSpaceViewDir(v.vertex);
         //输入一个object空间顶点位置,返回object空间中从该点到摄像机的观察方向。
                o.camPos =  ObjSpaceViewDir (v.vertex);


 *****灯光相关	
              //通过左乘UNITY_MATRIX_M矩阵,把方向矢量从模型空间变换到世界空间,
             //做了一次归一化以支持统一缩放 ,   
             // 第二个参数用于判断是否进行归一化 .
	           TransformObjectToWorldDir(Direction, true) ;
	         //通过左乘UNITY_MATRIX_I_M矩阵,把方向矢量从世界空间变换到模型空间, 
		    //做了一次归一化以支持统一缩放 ,
		   // 第二个参数用于判断是否进行归一化 
			  TransformWorldToObjectDir(Direction, true) ;

 *****求物体与摄像机距离
        //先将坐标转换至裁剪空间
               float3 viewPos=UnityObjectToClipPos(v.vertex);
	   //物体(顶点)与镜头距离
               float distance=length(viewPos);
 *****求物体(顶点)与摄像机的方向:
      //先将坐标从模型空间转为世界空间
              float3 worldPos=UnityObjectToWorldDir(v.vertex);
     //物体(顶点)与摄像机的方向
              o.viewDir=normalize(UnityWorldSpaceViewDir(worldPos));
                return o;
            }

 *****向量相关  
       //向量–模型空间转世界空间 第二个参数true 对结果进行归一化
        float3 TransformObjectToWorldDir(float3 dirOS, bool doNormalize = true)

       //向量–世界空间转模型空间 第二个参数true 对结果进行归一化
        float3 TransformWorldToObjectDir(float3 dirWS, bool doNormalize = true)

       //向量–世界空间转观察空间 第二个参数true 对结果进行归一化
        real3 TransformWorldToViewDir(real3 dirWS, bool doNormalize = false)

       //向量–世界空间转齐次裁剪空间 第二个参数true 对结果进行归一化
        real3 TransformWorldToHClipDir(real3 directionWS, bool doNormalize = false)

  • 27
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值