Unity Shader 常量、变量、结构体、函数一般可以在 Unity Editor 安装目录下面的【Editor\Data\CGIncludes\UnityShader】目录下查看源码,主要源码文件如下:
#define UNITY_PI 3.14159265359f
#define UNITY_TWO_PI 6.28318530718f
#define UNITY_FOUR_PI 12.56637061436f
#define UNITY_INV_PI 0.31830988618f
#define UNITY_INV_TWO_PI 0.15915494309f
#define UNITY_INV_FOUR_PI 0.07957747155f
#define UNITY_HALF_PI 1.57079632679f
#define UNITY_INV_HALF_PI 0.636619772367f
1)时间变量
// Time (t = time since current level load) values from Unity
float4 _Time; // (t/20, t, t*2, t*3)
float4 _SinTime; // sin(t/8), sin(t/4), sin(t/2), sin(t)
float4 _CosTime; // cos(t/8), cos(t/4), cos(t/2), cos(t)
float4 unity_DeltaTime; // dt, 1/dt, smoothdt, 1/smoothdt
2)相机和光源的世界坐标
float3 _WorldSpaceCameraPos; // 相机的世界坐标
half4 _WorldSpaceLightPos0; // 光源的世界坐标(当光源是平行光时, _WorldSpaceLightPos0表示灯光照射方向)
3)投影参数
// x = 1 or -1 (-1 if projection is flipped)
// y = near plane
// z = far plane
// w = 1/far plane
float4 _ProjectionParams;
4)屏幕参数
// x = width
// y = height
// z = 1 + 1.0/width
// w = 1 + 1.0/height
float4 _ScreenParams;
5)MVP 矩阵
float4x4 UNITY_MATRIX_M, unity_ObjectToWorld; // [模型空间->世界空间]的变换矩阵M
float4x4 UNITY_MATRIX_V, unity_MatrixV; // [世界空间->观察空间]的变换矩阵V
float4x4 UNITY_MATRIX_P, glstate_matrix_projection; // [观察空间->裁剪空间]的变换矩阵P
float4x4 UNITY_MATRIX_MV, unity_MatrixMV; // [模型空间->观察空间]的变换矩阵MV
float4x4 UNITY_MATRIX_VP, unity_MatrixVP; // [世界空间->裁剪空间]的变换矩阵VP
float4x4 UNITY_MATRIX_MVP, unity_MatrixMVP; // [模型空间->裁剪空间]的变换矩阵MVP
float4x4 UNITY_MATRIX_I_V, unity_MatrixInvV; // V矩阵的逆矩阵
float4x4 UNITY_MATRIX_T_MV, unity_MatrixTMV; // MV矩阵的转置
float4x4 UNITY_MATRIX_IT_MV, unity_MatrixITMV; // MV矩阵的逆转矩阵
float4x4 unity_WorldToObject; // [世界空间->模型空间]的变换矩阵M
说明:unity_ObjectToWorld 与 unity_WorldToObject 互为逆矩阵。

1)appdata_base
struct appdata_base {
float4 vertex : POSITION; // 模型坐标系下顶点坐标
float3 normal : NORMAL; // 模型坐标系下法线向量
float4 texcoord : TEXCOORD0; // 纹理坐标
UNITY_VERTEX_INPUT_INSTANCE_ID
};
2)appdata_tan
struct appdata_tan {
float4 vertex : POSITION; // 模型坐标系下顶点坐标
float4 tangent : TANGENT; // 模型坐标系下切线向量
float3 normal : NORMAL; // 模型坐标系下法线向量
float4 texcoord : TEXCOORD0; // 纹理坐标
UNITY_VERTEX_INPUT_INSTANCE_ID
};
3)appdata_full
struct appdata_full {
float4 vertex : POSITION; // 模型坐标系下顶点坐标
float4 tangent : TANGENT; // 模型坐标系下切线向量
float3 normal : NORMAL; // 模型坐标系下法线向量
float4 texcoord : TEXCOORD0; // 纹理坐标0
float4 texcoord1 : TEXCOORD1; // 纹理坐标1
float4 texcoord2 : TEXCOORD2; // 纹理坐标2
float4 texcoord3 : TEXCOORD3; // 纹理坐标3
fixed4 color : COLOR; // 顶点颜色
UNITY_VERTEX_INPUT_INSTANCE_ID
};
4)appdata_img
struct appdata_img
{
float4 vertex : POSITION; // 模型坐标系下顶点坐标
half2 texcoord : TEXCOORD0; // 纹理坐标
UNITY_VERTEX_INPUT_INSTANCE_ID
};
5)v2f_img
struct v2f_img
{
// 作为顶点着色器输出时, pos指裁剪坐标系下的坐标; 作为片元着色器输入时, pos指屏幕坐标系下的坐标
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0; // 纹理坐标
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
说明:作为顶点着色器输出时, pos指裁剪坐标系下的坐标; 作为片元着色器输入时, pos指屏幕坐标系下的坐标。
6)vert_img 着色器
v2f_img vert_img(appdata_img v)
{
v2f_img o;
UNITY_INITIALIZE_OUTPUT(v2f_img, o);
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
return o;
}
用户可以通过以下方式引用内置顶点着色器:
#pragma vertex vert_img
1)数值计算
sign(x)、abs(x) // 符号、绝对值
min(a, b)、max(a, b) // 最值函数
ceil(x)、floor(x)、round(x) // 取整函数
frac(x) // 取小数部分
fmod(x, y) // 取余数
rap(x) // 倒数(1/x)
sqrt(x)、pow(x) // 幂函数
exp(x)、exp2(x) // 指数函数(e^x、2^x)
log(x)、log10(x)、log2(x) // 对数函数
degrees(x)、radians(x) // 角度转换函数
sin(x)、cos(x)、tan(x)、asin(x)、acos(x)、atan(x) // 三角函数
sinh(x)、cosh(x)、tanh(x) // 双曲线函数
saturate(x) // 将x约束在0和1之间, 超过边界就取边界值
clamp(x, min, max) // 将x约束在min和max之间, 超过边界就取边界值
smoothstep (min, max, x) // 平滑比例, 公式: k=saturate((x-min)/(max-min)), y=k*k*(3-2*k)
lerp(a, b, f) // 插值, 公式: y=x+f*(y-x), a、b可以是向量
2)向量计算
all(vec) // 如果vec中每个分量都是非零的则返回true, 否则返回false
any(vec) // 如果vec中存在一个分量是非零的则返回true, 否则返回false
distance(pos1, pos2) // 计算pos1与pos2之间的距离
length(vec) // 计算向量的模长
normalize(vec) // 计算向量的单位向量
dot(vec1, vec2) // 向量点乘
cross(vec1, vec2) // 向量叉乘
reflect(i, n) // 根据入射向量和法线向量计算反射向量
3)矩阵计算
// mul(M, v) = mul(v, transpose(M)), mul(v, M) = mul(transpose(M), v)
mul(M, N)、mul(M, v), mul(v, M)
determinant(M) // 计算矩阵的行列式
transpose(M) // 矩阵转置
补充:CG 中矩阵类型变量初始化顺序是按照行优先的顺序进行的,访问矩阵中元素也是按照行优先的顺序进行的;float3、float4 类型变量,既可以当作一个矢量,也可以当作一个 1 x n 的行矩阵或 n x 1 的列矩阵。
// 定义一个矩阵, 第一行: 1.0, 2.0, 3.0; 第二行: 4.0, 5.0, 6.0; 第三行: 7.0, 8.0, 9.0
float3x3 M = float3x3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
// 得到矩阵M的第一行, 即: 1.0, 2.0, 3.0
float3 row = M[0];
// 得到矩阵M的第2行、第3列元素, 即: 6.0
float e = M[1][2];
4)纹理计算
tex2D(sampler2D, uv_Tex) // 查询纹理坐标对应的纹理值
UnpackNormal(color) // 根据法线纹理解析法线向量
1)坐标变换
// 模型空间->观察空间
float3 UnityObjectToViewPos(float3 pos) // mul(UNITY_MATRIX_MV, float4(pos, 1.0)).xyz
float3 UnityObjectToViewPos(float4 pos) // UnityObjectToViewPos(pos.xyz)
// 模型空间->裁剪空间
float4 UnityObjectToClipPos(float3 pos) // mul(UNITY_MATRIX_MVP, float4(pos, 1.0))
float4 UnityObjectToClipPos(float4 pos) // UnityObjectToClipPos(pos.xyz)
// 世界空间->观察空间
float3 UnityWorldToViewPos(float3 pos) // mul(UNITY_MATRIX_V, float4(pos, 1.0)).xyz
// 世界空间->裁剪空间
float4 UnityWorldToClipPos(float3 pos) // mul(UNITY_MATRIX_VP, float4(pos, 1.0))
// 观察空间->裁剪空间
float4 UnityViewToClipPos(float3 pos) // mul(UNITY_MATRIX_P, float4(pos, 1.0))
2)向量变换
// 模型空间->世界空间
float3 UnityObjectToWorldDir(float3 dir) // normalize(mul((float3x3)unity_ObjectToWorld, dir))
// 世界空间->模型空间
float3 UnityWorldToObjectDir(float3 dir) // normalize(mul((float3x3)unity_WorldToObject, dir))
3)法线变换
// 模型空间->世界空间(已归一化)
float3 UnityObjectToWorldNormal(float3 norm) {
#ifdef UNITY_ASSUME_UNIFORM_SCALING // 统一缩放(x、y、z分量缩放系数一致)
return UnityObjectToWorldDir(norm); // normalize(mul((float3x3)unity_ObjectToWorld, norm))
#else
return normalize(mul(norm, (float3x3)unity_WorldToObject)); // mul(IT_M, norm) => mul(norm, I_M)
#endif
}
法线由切线计算而来,在模型空间中 A 点的切线向量为 v1,法线向量为 n1,经过模型变换(矩阵 M)后,切线向量为 v2,法线向量为 n2,假设法线向量的变换矩阵为 G,因此存在以下关系:

Unity 中线性变换主要有平移、旋转、缩放,由于向量不受平移变换影响,因此,对于法线向量而言,只受旋转和缩放影响。
4)其他变换
// 观察空间->裁剪空间
float2 TransformViewToProjection (float2 v) // mul((float2x2)UNITY_MATRIX_P, v)
float3 TransformViewToProjection (float3 v) // mul((float3x3)UNITY_MATRIX_P, v)
1)计算顶点指向相机的向量
// _WorldSpaceCameraPos.xyz - worldPos
float3 ObjSpaceViewDir(float4 v) // 输入: 模型空间坐标, 输出: 模型空间坐标
float3 WorldSpaceViewDir(float4 localPos) // 输入: 模型空间坐标, 输出: 世界空间坐标
float3 UnityWorldSpaceViewDir(float3 worldPos) // 输入: 世界空间坐标, 输出: 世界空间坐标
2)计算顶点指向光源的向量
// mul(unity_WorldToObject, _WorldSpaceLightPos0).xyz - v.xyz
float3 ObjSpaceLightDir(float4 v) // 输入: 模型空间坐标, 输出: 模型空间坐标
float3 WorldSpaceLightDir(float4 localPos) // 输入: 模型空间坐标, 输出: 世界空间坐标
float3 UnityWorldSpaceLightDir(float3 worldPos) // 输入: 世界空间坐标, 输出: 世界空间坐标 在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到rubygems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决
我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我正在尝试用ruby中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc