您的位置:首页 > 移动开发 > Unity3D

世界空间中的着色器(关于 uniforms)

2016-08-18 15:30 239 查看
从对象空间到世界空间的转变

转载地址:http://www.omuying.com/article/91.aspx


原文链接:http://en.wikibooks.org/wiki/Cg_Programming/Unity/Shading_in_World_Space


在《在着色器中调试》章节中提到,顶点输入参数使用语义词 POSITION 指定对象的坐标,即本地对象(模型)的网格空间坐标,对象空间(对象的坐标系统)是特定于每个游戏对象的,然而,所有的游戏对象会被转换到一个共同的坐标系中(世界空间)。

如果一个对象被直接放入世界空间中,游戏对象会通过转换组件直接将对象的坐标转成世界坐标。你可以在 Scene 视图或者 Hierarchy 视图中选中一个对象,然后在 Inspector 视图中查看 Transform 组件。在 Transform 组件中包括 Position、Rotation 和 Scale 属性,这个组件用来指定从本地坐标到世界坐标的顶点转换(如果一个游戏对象拥有父级对象,那么转换组件只转换父级对象的坐标)。在《Vertex
Transformations》章节中,我们将讨论顶点的转换、旋转、缩放以及 4 x 4 矩阵组合变换的细节。

回到我们的例子中:从对象空间到世界空间的转换是通过 4 x 4 矩阵来转换的,也叫“模型矩阵”,这个矩阵在 Unity 中通过 uniform 参数 _Object2World 已经声明了:

Shader "Custom/World Space"

{

SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//uniform flaot4*4 Object3World
//automatic definition of a Unity-specific uniform parameter 自动定义统一值是unity的一个特性
struct vertexOutput 
{
float4 pos: SV_POSITION;
float4 position_in_world_space : TEXCOORD0;
};

vertexOutput vert(float4 vertex:POSITION) 
{
vertexOutput output;
output.pos = mul(UNITY_MATRIX_MVP,vertex);
output.position_in_world_space = mul(_Object2World,vertex);//物体坐标转化为世界坐标
return output;
}

float4 frag(vertexOutput input) :COLOR
{
float dist = distance(input.position_in_world_space,float4(0.0,0.0,0.0,1.0));  //计算片段位置与原点距离(第四个坐标永远是1)
if (dist < 5.0)
{
return float4(0.0, 1.0, 0.0, 1.0);   //接近
}
else
return float4(0.3,0.3,0.3,1.0);//远离原点
}
ENDCG
}
}
}

更多的 Unity Uniforms

在 Unity 中,定义了几个和 _Object2World 一样的 float4x4  矩阵,下面是在系列教程中使用的 uniforms 简短列表:

uniform float4 _Time, _SinTime, _CosTime; // time values
uniform float4 _ProjectionParams;
// x = 1 or -1 (-1 if projection is flipped)
// y = near plane; z = far plane; w = 1/far plane
uniform float4 _ScreenParams;
// x = width; y = height; z = 1 + 1/width; w = 1 + 1/height
uniform float4 unity_Scale; // w = 1/scale; see _World2Object
uniform float3 _WorldSpaceCameraPos;
uniform float4x4 _Object2World; // model matrix
uniform float4x4 _World2Object; // inverse model matrix
// (all but the bottom-right element have to be scaled
// with unity_Scale.w if scaling is important)
uniform float4 _LightPositionRange; // xyz = pos, w = 1/range
uniform float4 _WorldSpaceLightPos0;
// position or direction of light source

uniform float4x4 UNITY_MATRIX_MVP; // model view projection matrix
uniform float4x4 UNITY_MATRIX_MV; // model view matrix
uniform float4x4 UNITY_MATRIX_V; // view matrix
uniform float4x4 UNITY_MATRIX_P; // projection matrix
uniform float4x4 UNITY_MATRIX_VP; // view projection matrix
uniform float4x4 UNITY_MATRIX_T_MV;
// transpose of model view matrix
uniform float4x4 UNITY_MATRIX_IT_MV;
// transpose of the inverse model view matrix
uniform float4x4 UNITY_MATRIX_TEXTURE0; // texture matrix
uniform float4x4 UNITY_MATRIX_TEXTURE1; // texture matrix
uniform float4x4 UNITY_MATRIX_TEXTURE2; // texture matrix
uniform float4x4 UNITY_MATRIX_TEXTURE3; // texture matrix
uniform float4 UNITY_LIGHTMODEL_AMBIENT; // ambient color


用户指定 Uniforms:着色器属性

还有一个更重要的 uniform  参数:用户自定义的 uniforms。实际上,这是 Unity 的属性,你可以认为他们是着色器的用户自定义 uniform 参数。通常一个着色器不带参数只能由编写的程序员在一些特定的程序中使用,但是如果一个着色器拥有参数并且还带有描述性的说明,那么这个着色器就可以被其他人使用,另外,如果你打算出售你的着色器,为着色器的提供参数会大大增加它的价值。

因为在 Unity 的 ShaderLab  中使用《description of shader properties 》非常不错,通过下面的例子我们来了解如何使用着色器属性,首先,我们声明一个属性,然后我们再定义一个与属性名称相同、类型相同的
uniforms 。
Shader "Cg shading in world space"
{
Properties
{
_Point ("a point in world space", Vector) = (0., 0., 0., 1.0)
_DistanceNear ("threshold distance", Float) = 5.0
_ColorNear ("color near to point", Color) = (0.0, 1.0, 0.0, 1.0)
_ColorFar ("color far from point", Color) = (0.3, 0.3, 0.3, 1.0)
}

SubShader
{
Pass
{
CGPROGRAM

#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"
// defines _Object2World and _World2Object
// uniforms corresponding to properties
uniform float4 _Point;
uniform float _DistanceNear;
uniform float4 _ColorNear;
uniform float4 _ColorFar;

struct vertexInput
{
float4 vertex : POSITION;
};
struct vertexOutput
{
float4 pos : SV_POSITION;
float4 position_in_world_space : TEXCOORD0;
};

vertexOutput vert(vertexInput input)
{
vertexOutput output;

output.pos =  mul(UNITY_MATRIX_MVP, input.vertex);
output.position_in_world_space = mul(_Object2World, input.vertex);
return output;
}

float4 frag(vertexOutput input) : COLOR
{
float dist = distance(input.position_in_world_space, _Point);
// computes the distance between the fragment position
// and the position _Point.
if (dist < _DistanceNear)
{
return _ColorNear;
}
else
{
return _ColorFar;
}
}
ENDCG
}
}
}


使用 sharedMaterial 我们可以改变所有使用了这个材质的对象的参数,如果你只希望改变一个并使用了这个材质的对象的参数,那么你应该使用 material 。假如你设置 _Point 属性为另一个对象的位置信息,这样你只需要在
Unity 中移动这个对象就可以查看效果了,你可以复制/粘贴 下面的代码到一个 C# 脚本中:

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class NewBehaviourScript : MonoBehaviour
{
public GameObject other;

void Update()
{
if(other != null)
{
GetComponent<Renderer>().sharedMaterial.SetVector("_Point", other.transform.position);
}
}
}


然后我们只需要移动另一个对象(Sphere)就可以看到(Cube)颜色的变化,当小球离原点近时,如图:

当小球离原点远时,如图:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息