Unity入门系列
目标: 创建图形, 可视化数学函数
1 用立方体cube组成线
依赖数学函数, 计算出一系列的坐标对, 然后组成一条线
1.1 Prefabs 预制件
创建一个cube
删除 collider component
拉到Assets中, 这样就形成了一个prefabs
删除场景中的cube
1.2 Graph component
建一个脚本Graph
新建一个C# script, 命名为Graph
添加变量 public Transform pointPrefab;
新建一个Game Object
Create Empty, 命名为Graph
把上面的脚本Graph添加为component
再把上面的预制件cube设置到point prefab字段
1.3 实例化预制件
通过Instatiate方法实例化
public class Graph : MonoBehaviour {
public Transform pointPrefab;
void Awake () {
Instantiate(pointPrefab);
}
}
通过 Transform point = Instantiate(pointPrefab); 获得对象的引用
通过对象的localPosition属性设置位置
位置参数使用 3D vector.
Transform point = Instantiate(pointPrefab);
point.localPosition = Vector3.right;
试运行, 可以看到位置略有变化的立方体.
下面添加多一个对象
Transform point = Instantiate(pointPrefab);
point.localPosition = Vector3.right;
point = Instantiate(pointPrefab);
point.localPosition = Vector3.right * 2;
1.4 循环代码
int i = 0;
while (i < 10)
{
Transform point = Instantiate(pointPrefab);
point.localPosition = Vector3.right * i;
i = i + 1;
}
1.5 简化代码
for (int i = 0; i < 10; i++)
{
Transform point = Instantiate(pointPrefab);
point.localPosition = Vector3.right * i;
}
效果是一样的.
1.6 改变范围
为函数表达方便, x的范围一般在0-1, 或者-1 ~ 1
相应的, 立方体也需要缩小
for (int i = 0; i < 10; i++)
{
Transform point = Instantiate(pointPrefab);
point.localPosition = Vector3.right * i;
point.localScale = Vector3.one / 5f;
}
调整x的范围到 -1 ~ 1
point.localPosition = Vector3.right * ((i + 0.5f) / 5f - 1f);
重新排成一条直线.
1.7 优化一下代码
Vector3 scale = Vector3.one / 5f;
Vector3 position;
position.y = 0f;
position.z = 0f;
for (int i = 0; i < 10; i++)
{
Transform point = Instantiate(pointPrefab);
position.x = (i + 0.5f) / 5f - 1f;
point.localPosition = position;
point.localScale = scale;
}
1.8 通过函数, 用x计算出y
f(x)=x
Vector3 scale = Vector3.one / 5f;
Vector3 position;
//position.y = 0f;
position.z = 0f;
for (int i = 0; i < 10; i++)
{
Transform point = Instantiate(pointPrefab);
position.x = (i + 0.5f) / 5f - 1f;
position.y = position.x;
point.localPosition = position;
point.localScale = scale;
}
f(x)=x2
position.y = position.x * position.x;
2 创建更多的立方体
2.1 可变数量
添加变量
public int resolution = 10;
指定范围
[Range(10, 100)]
public int resolution = 10;
2.2 使用这个变量
float step = 2f / resolution;
Vector3 scale = Vector3.one * step;
Vector3 position;
position.z = 0f;
for (int i = 0; i < resolution; i++)
{
Transform point = Instantiate(pointPrefab);
position.x = (i + 0.5f) * step - 1f;
position.y = position.x * position.x;
point.localPosition = position;
point.localScale = scale;
}
2.3 设置层次, 方便管理
现在生成的立方体都是在根节点上面
方便管理, 给他们设置一个父亲
point.SetParent(transform, false);
3, 设置颜色
3.1 定义着色器 Shader
Assets / Create / Shader / Standard Surface Shader
命名为ColoredPoint.
着色器是用脚本定义的, 但语法不同于C#, 双击可以看到脚本:
Shader "Custom/ColoredPoint" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Standard fullforwardshadows
#pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
UNITY_INSTANCING_CBUFFER_START(Props)
UNITY_INSTANCING_CBUFFER_END
void surf (Input IN, inout SurfaceOutputStandard o) {
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
修改成我们需要的, 留意 struct Input 部分
Shader "Custom/ColoredPoint" {
Properties {
// _Color ("Color", Color) = (1,1,1,1)
// _MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Standard fullforwardshadows
#pragma target 3.0
// sampler2D _MainTex;
struct Input {
// float2 uv_MainTex;
float3 worldPos;
};
half _Glossiness;
half _Metallic;
// fixed4 _Color;
UNITY_INSTANCING_CBUFFER_START(Props)
UNITY_INSTANCING_CBUFFER_END
void surf (Input IN, inout SurfaceOutputStandard o) {
// fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
// o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
// o.Alpha = c.a;
o.Alpha = 1;
}
ENDCG
}
FallBack "Diffuse"
}
现在我们已经有了一个可编程的shader
创建一个material, 命名为Colored Point, 采用上面的shader
给cube设置material为ColoredPoint
3.2 用坐标定义颜色
现在进入play模式, cube都是黑色的,
修改shader的surf函数:
// o.Albedo = 0;o.Albedo.r = IN.worldPos.x * 0.5 + 0.5;
用y赋值给绿色:
o.Albedo.r = IN.worldPos.x * 0.5 + 0.5;
o.Albedo.g = IN.worldPos.y * 0.5 + 0.5;
可合并成一行:(红色 + 绿色 = 黄色)
o.Albedo.rg = IN.worldPos.xy * 0.5 + 0.5;
改一个函数玩玩: position.y = position.x * position.x* position.x;
4 让图像动起来,
要让图像动起来, 必须增加一个时间参数: f(x,t)取代f(x),
4.1 追踪这些点
为了让这些点动起来, 我们先建一个数组, 保存这些点, 以便可以控制他们, 改变他们的位置
points = new Transform[resolution];
for (int i = 0; i < resolution; i++) {
…
points[i] = point;
}
4.2 改变点的坐标
为了动态,y值的计算移到了update函数:
public class Graph : MonoBehaviour
{
public Transform pointPrefab;
[Range(10, 100)]
public int resolution = 10;
public Transform[] points;
void Awake()
{
float step = 2f / resolution;
Vector3 scale = Vector3.one * step;
Vector3 position;
position.z = 0f;
position.y = 0f;
points = new Transform[resolution];
for (int i = 0; i < resolution; i++)
{
Transform point = Instantiate(pointPrefab);
position.x = (i + 0.5f) * step - 1f;
//不在这里计算y值了
point.localPosition = position;
point.localScale = scale;
point.SetParent(transform, false);
points[i] = point;
}
}
void Update()
{
for (int i = 0; i < points.Length; i++)
{
Transform point = points[i];
Vector3 position = point.localPosition;
position.y = position.x * position.x * position.x;
point.localPosition = position;
}
}
}
4.3 显示正弦波
现在进入play模式, 点坐标是一直值更新的, 只是一直一样, 所以我们看不出, 为了看效果, 采用正弦函数 + 时间变量
这样就可以看到动态效果了
原文: http://catlikecoding.com/unity/tutorials/basics/building-a-graph/