【原】Unity Shader VS UDK Material Editor
1. UDK CameraVector (相机位向量)表达式
机位向量表达式使您能够在游戏运行时访问相机的指向向量。在要求材质于不同视角角度下呈现出不同效果时
对应unity shader中Input结构附加变量: float3 viewDir。对于内建的viewDir, 它和CameraVector一样是切线空间中的变量。
对于unity 如果不使用附加变量,计算过程如下:ObjSpaceViewDir() 函数求摄像机到顶点的方向。
在顶点shander中还可以求反射方向
//float3 I = reflect( -viewDir, v.normal ); 求 ReflectionVector 反射向量
计算到切线空间
TANGENT_SPACE_ROTATION;
viewDir = normalize(mul(rotation, normalize(ObjSpaceViewDir(v.vertex))));
这个是基于物体切线空间的位置。 相机的世界坐标向量是:
float3 worldView = normalize(WorldSpaceViewDir(v.vertex));
在udk 中 float z = ScreenPosition.w.r
对应unity计算如下:
float z = - mul(UNITY_MATRIX_MV, v.vertex).z;
如果是在surf 函数中,也可以从screenPos.w.r 获得。
3. UDK ScreenPosition (屏幕位置)表达式
屏幕位置表达式用于输出当前指定像素在屏幕中的位置。像素处于屏幕空间中的位置,范围从[-1,-1],即屏幕左下角,到[1, 1],即右上角。它有一个参数,屏幕校准(ScreenAlign),用来将坐标范围改动为从[0, 0]到[1, 1]
udk 当前像素ScreenPosition是由CalcMaterialParameters函数计算出来的。
1. unity中顶点经过投影变换后再使用ComputeScreenPos计算出来。
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
o.ScreenPos = ComputeScreenPos (o.pos); //由[-1,1]范围映射到[0,1]范围.
2. unity 方法2 是surface shader中, 直接在surf Input 参数结构中声明screenPos变量 ,unity 会自动填入值.
screenPos.xy和上面计算的 o.ScreenPos.xy 相同
struct Input {
float4 screenPos;
void surf (Input IN, inout EditorSurfaceOutput o) {
btw: 做为uv使用前都要除w值:screenPos.w 或者 ScreenPos.w。
ComputeGrabScreenPos 函数用来映射像素到graptexture上,从GrabTexture 上可以获得 DestColor (目标颜色) ,这个grabuv和screenPos是不同的,在我机器上是除w之后,grabuv.y 是 1-screenPos.y(可能和我的环境有关,需要grabuv时最好从顶点中计算)。
4. UDK SceneDepth (场景深度)表达式
场 景深度表达式跟目标深度表达式(DestDepth)非常相似,但它可以针对整个关卡场景中对深度进行采样,改变输入的UV即可。
LinearEyeDepth (tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD( IN.screenPos)).r);
LinearEyeDepth 线性化函数,正交投影时是针对z值进行了1/z变换(让近处物件有更好的z值分辨率,如下公式),这样近处的东西有更大的分辨率
(opengl) 求 -Pz 即eyeZ 对应公式: -Pz = (2 * n * f) / (f + n - z' * (f - n))
-Pz 是顶点在3D空间中的z值, 这和计算出来的w值以及PixelDepth是相同的。z'是投影变换后的z值。也是_CameraDepthTexture记录的z值。所以进行z值差值,要求线性结果。例如:
//#define UNITY_SAMPLE_DEPTH(value) (value).r
BlendFactors = saturate(Paremeter * depthdiff);
对于当前点求的SceneDepth 也就是 udk 的DestDepth表达式。
5. UDK BumpOffset (凹凸偏移)表达式
用来创建虚拟位移贴图(Virtual Displacement Mapping)效果。在使用法线贴图来产生表面高度的物理差异假象时,此表达式能改善其效果。
BumpOffset 表达式公式如下:
BumpOffset = TexCoord + CameraVector.RG * (Height * HeightRatio - HeightRatio * RefPlane);
需要带Alpha高度图的法线贴图,用alpha通道作为Height节点输入。
unity 对应的函数是
inline float2 ParallaxOffset( half h, half height, half3 viewDir )
{
h = h * height - height/2.0;
float3 v = normalize(viewDir);
v.z += 0.42;
return h * (v.xy / v.z);
}
half h = tex2D (_SpecMap, IN.uv_BumpMap).w; //从法线贴图alpha通道读取高度
float2 offset = ParallaxOffset (h, _HeightRatio, IN.viewDir); //计算uv bumpoffset, _HeightRatio 是输入参数
IN.uv_MainTex += offset;
IN.uv_BumpMap += offset;
虽然者略有不同,但都是属于虚拟位移贴图
6. UDK ReflectionVector (反射向量)
反射向量表达式用来表示CameraVector(相机向量)通过应用材质的物体表面的法线的方向发射。
对应着unity 顶点附加变量 float3 worldRefl. 但ReflectionVector 是切向空间的, worldRefl 则是世界空间的。对于UDK可以使用Transfrom表达式进行空间变化。
Unity 局部空间变换到切向空间使用 TANGENT_SPACE_ROTATION得到rotation; 计算过程参考 CameraVector条目
//一个unity环境反射的例子
half4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
float3 worldRefl = WorldReflectionVector (IN, o.Normal);
half4 reflclr = texCUBE (_Cube, worldRefl);
reflclr *= tex.a;
o.Emission = reflclr.rgb * _ReflectColor.rgb;
7. UDK Fresnel (菲涅尔)
菲涅尔表达式是多种功能的复杂综合:读取像素的法线向量,并在向量指向镜头时输出值0,在法线方向与相机视角垂直时输出1
如下计算过程。法线和CameraVector都是位于切线空间的矢量。 如果没有法线贴图提供法线,那么法线就是 (0, 0, 1.0), 参考切线空间定义
计算过程 Fresnel = (1 - Max(Normal dot Camera, 0)) ^ Exponent
F = pow(1- max(N*C, 0), E)
UDK 对应 Shader
float Local2 = dot(float3(0.00000000,0.00000000,1.00000000),Parameters.TangentCameraVector); //切线空间viewDir
float Local3 = max((0.00000000),Local2);
float Local4 = ((1.00000000) - Local3);
float Local5 = ClampedPow(Local4,(3.00000000));
转换到unity
o.Normal = half3(0,0,1.0f); //有法线贴图则: o.Normal = UnpackNormal(tex2D(_BumpMap, IN.BumpUV));
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
o.Emission = float3(1.0f,0,0) * pow (rim, 3);
viewDir 基于切线空间, 法线也是。如果没有法线贴图, 可以使用 (0,0,1)
8. unity 变量_ ZBufferParams 的值. 主要用于 ComputeScreenPos 函数中。
double zc0, zc1;
//OPenGL would be this:
zc0 = (1.0 - m_FarClip / m_NearClip) / 2.0;
zc1 = (1.0 + m_FarClip / m_NearClip) / 2.0;
//D3D is this:
zc0 = 1.0 - m_FarClip / m_NearClip;
zc1 = m_FarClip / m_NearClip;
float4 _ZBufferParams = float4(zc0, zc1, zc0/m_FarClip, zc1/m_FarClip);
DX:
eyeZ 正交投影之前的z值。 z 是经过正交投影的值(即_CameraDepthTexture中的值)。
eyeZ = (n * f) / (f - z * (f - n))
LinearZ = eyeZ / f = n / (f - z * (f - n))
GL:
eyeZ = (2 * n * f) / (f + n - z * (f - n))
LinearZ = eyeZ / f = (2 * n) / (f + n - z * (f - n))
9. SceneTexture (场景贴图)
UDK 拥有这个表达式,代表当前的场景颜色信息
unity 没有当前的color bufrer。代替的方法如下:
Subshader
{
Tags {"RenderType"="Transparent" "Queue"="Transparent"}
GrabPass {}
sampler2D _GrabTexture; //捕获的纹理
Pass {
。。。。。
CGPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#pragma glsl
。。。。。
ENDCG
}
}
10. Desaturation (冲淡颜色)
Desaturation(冲淡颜色)表达式将抽出材质中的颜色量,也可用说 减饱和作用 。其整体效果会使材质中存在的颜色趋向于灰色
可用于冲淡漫反射图得到高光贴图
下面是unity 的函数Luminance, 作用类似
unity 点乘的常量是 fixed3(0.22, 0.707, 0.071),而UDK默认值是(0.3,0.59,0.11)
inline fixed Luminance( fixed3 c )
{
return dot( c, fixed3(0.22, 0.707, 0.071) );
}
11. DepthBiasedAlpha(深度偏移Alpha)
DepthBiasedAlpha表达式是两个主要用来消除尖锐边缘的表达式之一,这些边缘通常是由平面粒子实例(sprite particle)与几何体交叉而产生的。
表达式读取两个输入值:Alpha值和Bias值。Bias值对目的地缓冲器中的内容和材质进行实际混合。
Bias值读取黑、白之间的值,值0(黑)表示完全显示目的地缓冲器中的内容,值1(白)表示完全显示材质的颜色。
Alpha输入值则直接通过表达式,不需要进行任何运算。默认值为1
如果没有输入Alpha值,则DepthBiasedAlpha(深度偏移Alpha)表达式的输出值为1。
默认属性: float Local2 = DepthBiasedAlpha(Parameters,float((1.00000000)),float((0.50000000)),float((1.0000000)));
也有两个参数,bNormalize和BiasScale。BiasScale用作与Bias输入值的乘数,从而允许在材质和目的地缓冲器内容之间更大程度地进行混合。
bNormalize属性将深度值由范围的近到远映射到0到1的范围(bNormalize 暂时没看到起作用)
公式如下:
float DepthBiasedAlpha( FMaterialPixelParameters Parameters, float InAlpha, float InBias, float InBiasScale )
{
float Result;
half SceneDepth = PreviousDepth(Parameters.ScreenPosition);
float DepthBias = (1.0 - InBias) * InBiasScale;
float BlendAmt = saturate((SceneDepth - Parameters.ScreenPosition.w) / max(DepthBias,0.001));
Result = InAlpha * BlendAmt;
return Result;
}
unity 在这方面有一个 Soft Particles 的控制选项。 Edit->Project Setting->Quality。 或者在像素shader中:
Properties
{
_Bias("_Bias", Range(0,1) ) = 0.5
}
.......
half ScreenDepthDiff = LinearEyeDepth (tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(IN.screenPos)).r) - IN.screenPos.w;
half Pow = pow(ScreenDepthDiff, _Bias);
float Saturate = saturate(Pow);
o.Alpha = Saturate;
12. Distortion
Distortion 扭曲在UDK中是整个材质节点的一个输入参数。在unity 可以如下实现:使用法线扰动uv,然后从grab纹理取得像素值
Shader "Distortion"
{
Properties
{
_Distortion("_Distortion", Range(0,1) ) = 0.1632124
_BumpMap("_Offset", 2D) = "black" {}
}
SubShader
{
Tags
{"Queue"="Transparent" "IgnoreProjector"="False" "RenderType"="Transparent"}
GrabPass {}
Cull Back
ZWrite Off
ZTest LEqual
ColorMask RGBA
Fog{}
CGPROGRAM
#pragma surface surf BlinnPhong vertex:vert
#pragma target 2.0
float _Distortion;
sampler2D _BumpMap;
sampler2D _GrabTexture;
struct Input
{
float4 grabPos;
float2 uv_BumpMap;
};
void vert (inout appdata_full v, out Input o)
{
float4 pos = mul (UNITY_MATRIX_MVP, v.vertex);
o.grabPos = ComputeGrabScreenPos(pos);
}
void surf (Input IN, inout SurfaceOutput o)
{
o.Normal = float3(0.0,0.0,1.0);
o.Alpha = 1.0;
o.Albedo = 0.0;
float3 Normal=UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
float2 Multiply1=Normal.xy * _Distortion.xx;
float2 uvs = IN.grabPos.xy/IN.grabPos.w + Multiply1;
float4 Tex2D0 = tex2D(_GrabTexture,uvs);
o.Emission = Tex2D0.rgb;
}
ENDCG
}
Fallback "Diffuse"
}
13. 如果你的程序不会运行到手机设备上,可以禁止生成OpenGL ES 2.0 (Opengl 缩减版)的shader。
#pragma exclude_renderers gles
这样可以解决 shader 中 isnan 之类函数不能编译问题, 对于flash 可以用 #pragma exclude_renderers flash
flash 能支持的寄存器太少了
附:
1. unity 中可以附加到Input结构的变量.
float3 viewDir
- will contain view direction, for computing Parallax effects, rim lighting etc.float4
withCOLOR
semantic - will contain interpolated per-vertex color.float4 screenPos
- will contain screen space position for reflection effects. Used by WetStreet shader in Dark Unity for example.float3 worldPos
- will contain world space position.float3 worldRefl
- will contain world reflection vector if surface shader does not write to o.Normal. See Reflect-Diffuse shader for example.float3 worldNormal
- will contain world normal vector if surface shader does not write to o.Normal.float3 worldRefl; INTERNAL_DATA
- will contain world reflection vector if surface shader writes to o.Normal. To get the reflection vector based on per-pixel normal map, useWorldReflectionVector (IN, o.Normal)
. See Reflect-Bumped shader for example.float3 worldNormal; INTERNAL_DATA
- will contain world normal vector if surface shader writes to o.Normal. To get the normal vector based on per-pixel normal map, useWorldNormalVector (IN, o.Normal)
.
【原】Unity Shader VS UDK Material Editor的更多相关文章
- Unity Shader入门精要学习笔记 - 第10章 高级纹理
转载自 冯乐乐的 <Unity Shader入门精要> 立方体纹理 在图形学中,立方体纹理是环境映射的一种实现方法.环境映射可以模拟物体周围的环境,而使用了环境映射的物体可以看起来像镀了层 ...
- Unity Shader入门精要之 screen post-processing effect
本篇记录了学习Unity Shader入门精要的屏幕后处理的一些知识点. OnRenderImage(RenderTexture src, RenderTexture dest) 以上函数是Unity ...
- 【Unity Shader】(三) ------ 光照模型原理及漫反射和高光反射的实现
[Unity Shader](三) ---------------- 光照模型原理及漫反射和高光反射的实现 [Unity Shader](四) ------ 纹理之法线纹理.单张纹理及遮罩纹理的实现 ...
- Unity Shader入门精要学习笔记 - 第15章 使用噪声
转载自 冯乐乐的 <Unity Shader 入门精要> 消融效果 消融效果常见于游戏中的角色死亡.地图烧毁等效果.这这些效果中,消融往往从不同的区域开始,并向看似随机的方向扩张,最后整个 ...
- Unity Shader入门精要学习笔记 - 第12章 屏幕后处理效果
建立一个基本的屏幕后处理脚本系统 屏幕后处理,顾名思义,通常指的是在渲染完整个场景得到屏幕图像后,再对这个图像进行一系列操作,实现各种屏幕特效.使用这种技术,可以为游戏画面添加更多艺术效果,例如景深. ...
- Unity Shader入门精要学习笔记 - 第3章 Unity Shader 基础
来源作者:candycat http://blog.csdn.net/candycat1992/article/ 概述 总体来说,在Unity中我们需要配合使用材质和Unity Shader才能达 ...
- 【我的书】Unity Shader的书 — 文件夹(2015.12.21更新)
写在前面 感谢全部点进来看的朋友.没错.我眼下打算写一本关于Unity Shader的书. 出书的目的有以下几个: 总结我接触Unity Shader以来的历程,给其它人一个借鉴.我非常明确学Shad ...
- Unity Shader入门教程(一)
参考文献:http://www.360doc.com/content/13/0923/15/12282510_316492286.shtml Unity Shader是着色器,将纹理.网格信息输入,得 ...
- Unity Shader - 消融效果原理与变体
基本原理与实现 主要使用噪声和透明度测试,从噪声图中读取某个通道的值,然后使用该值进行透明度测试. 主要代码如下: fixed cutout = tex2D(_NoiseTex, i.uvNoiseT ...
随机推荐
- 3522: [Poi2014]Hotel
3522: [Poi2014]Hotel Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 253 Solved: 117[Submit][Status ...
- CSS限制字数,超出部份显示点点点...
最近项目中需要用CSS实现限制字数,超出部份显示点点点...,只需要一下代码即可: width:400px;/*要显示文字的宽度*/ text-overflow :ellipsis; /*让截断的文字 ...
- HttpURLConnection实现两个服务端的对接
在企业开发中,很多时候需要用到两个服务端的对接,在java类中进行连接并传递参数,其中的HttpURLConnection是一种轻量化,并且简单的方法! package httptest; impor ...
- (30)批处理文件.bat
批处理文件(bat) 简单的说,批处理的作用就是自动的连续执行多条命令 .编写bat处理文件可以使用记事本的方式: 常见批处理文件的命令: echo 表示显示此命令后的字符 tiltle 设置窗口的标 ...
- 【SF】开源的.NET CORE 基础管理系统 -介绍篇
[SF]开源的.NET CORE 基础管理系统 -系列导航 1.环境: .NET Core SDK (https://www.microsoft.com/net/core) SQL Server or ...
- javascript中构造StringBuffer实例
function StringBuffer(){ this.strings = new Array; } StringBuffer.prototype.append=function ...
- pyqt样式表语法笔记(上) --原创
pyqt样式表语法笔记(上) pyqt QSS python 样式表 因为软件课设的原因开始学习使用pyqt4,才发现原来它也有样式表,而且语法跟css基本相同,而且一些功能实现起来感觉比js要简单方 ...
- windows_keyboard shortcuts快捷键
单独按Windows:显示或隐藏"开始"功能表 Windows+BREAK:显示"系统属性" 对话框 Windows+D:显示桌面 Windows+M:最小化所 ...
- iOS面试必看经典试题分析
> **不用临时变量怎么实现两个数据的交换?** 方式一:加减法的运算方式求解new_b = a - b + b = a;new_a = a + b - a = b;一个简单的运算方式,最重要的 ...
- 五分钟秒懂Java日志组件
Java中有许多种日志记录方式,有些API有占位符,有些API没占位符,初学的人可能会搞不清楚这些日志组件的由来.我一开始的时候也是很懵逼的,后来一点点弄懂了于是就又了这篇文章. 在Java中进行日志 ...