接上回 Rounded Cube 3.本章主题如下:
- Create a custom shader. 使用自定义shader
此为本人阅读笔记不作为转载处理,详细还请参看原文. 原文地址
虽然我们现在可以区分面,但我们仍然没有纹理坐标。 假设我们想在整个立方体上显示一个网格模式,以便我们可以看到单个四边形。 我们怎样才能做到这一点?
我们可以使用自定义着色器来找出如何应用纹理,而不是将UV坐标存储在网格中。 这是一个刚创建的着色器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| Shader "Custom/Rounded Cube Grid" { 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;
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" }
|
这是默认的表面着色器。 重要的是它定义了一个输入结构,它要求主纹理的坐标。 这些坐标在surf函数中使用,为每个渲染片段调用。 由于我们没有这样的坐标,我们必须用其他的东西替换uv_MainTex。– Google这段翻译的真好
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| struct Input { float2 cubeUV; };
…
void surf (Input IN, inout SurfaceOutputStandard o) { fixed4 c = tex2D(_MainTex, IN.cubeUV) * _Color; o.Albedo = c.rgb; o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = c.a; } }
|
由于每个顶点定义了UV,所以我们必须添加一个每个顶点调用的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| CGPROGRAM #pragma surface surf Standard fullforwardshadows vertex:vert #pragma target 3.0
sampler2D _MainTex;
struct Input { float2 cubeUV; };
half _Glossiness; half _Metallic; fixed4 _Color; void vert (inout appdata_full v, out Input o) { UNITY_INITIALIZE_OUTPUT(Input, o); }
void surf (Input IN, inout SurfaceOutputStandard o) { fixed4 c = tex2D(_MainTex, IN.cubeUV) * _Color; o.Albedo = c.rgb; o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = c.a; } ENDCG
|
为了检查我们的着色器是否工作,直接使用顶点位置的XY坐标作为UV。
1 2 3 4
| void vert (inout appdata_full v, out Input o) { UNITY_INITIALIZE_OUTPUT(Input, o); o.cubeUV = v.vertex.xy; }
|
这对于Z面来说是合理的,但其他的却是一团糟。 我们需要为它们使用不同的顶点坐标。 所以我们有一个选择,我们可以通过添加关键字枚举着色器属性来支持。
这里划重点了 使用关键枚举来决定渲染不同的面,背后的工作原理是:枚举对应的宏定义
1 2 3 4 5 6 7
| 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 [KeywordEnum(X, Y, Z)] _Faces ("Faces", Float) = 0 }
|
可以通过定义关键字义,使我们能够为每个选项编写不同的代码。
1 2 3 4 5 6 7 8 9 10
| void vert (inout appdata_full v, out Input o) { UNITY_INITIALIZE_OUTPUT(Input, o); #if defined(_FACES_X) o.cubeUV = v.vertex.yz; #elif defined(_FACES_Y) o.cubeUV = v.vertex.xz; #elif defined(_FACES_Z) o.cubeUV = v.vertex.xy; #endif }
|
刚开始看起来不错,但网格线不适合实际四边形。 更糟糕的是,当我们使用世界空间顶点位置时,移动或旋转立方体时会变得很奇怪。
在四舍五入之前,我们需要原始立方体的顶点位置。 如果我们可以将它们存储在网格中,我们可以将它们传递给着色器。 由于我们不使用顶点颜色,因此我们可以使用顶点颜色通道来达到此目的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| private Color32[] cubeUV;
private void CreateVertices () { int cornerVertices = 8; int edgeVertices = (xSize + ySize + zSize - 3) * 4; int faceVertices = ( (xSize - 1) * (ySize - 1) + (xSize - 1) * (zSize - 1) + (ySize - 1) * (zSize - 1)) * 2; vertices = new Vector3[cornerVertices + edgeVertices + faceVertices]; normals = new Vector3[vertices.Length]; cubeUV = new Color32[vertices.Length];
…
mesh.vertices = vertices; mesh.normals = normals; mesh.colors32 = cubeUV; }
private void SetVertex (int i, int x, int y, int z) { …
normals[i] = (vertices[i] - inner).normalized; vertices[i] = inner + normals[i] * roundness; cubeUV[i] = new Color32((byte)x, (byte)y, (byte)z, 0); }
|
这里我们必须使用Color32来代替通常的Color类型,因为顶点颜色组件被存储为单个字节。 整个颜色是四个字节,与单个浮点大小相同。
如果我们使用常规颜色,那么Unity将从0-1浮点数转换为0-255字节,截断该范围之外的所有内容。 通过直接转换为字节,我们可以处理多达255的多维数据集,这应该是足够的。
在着色器方面,我们现在可以使用顶点颜色而不是其位置。 当着色器将顶点颜色通道解释为0-1范围内的值时,我们必须通过乘以255来撤消此转换。
1 2 3 4 5 6 7 8 9 10
| void vert (inout appdata_full v, out Input o) { UNITY_INITIALIZE_OUTPUT(Input, o); #if defined(_FACES_X) o.cubeUV = v.color.yz * 255; #elif defined(_FACES_Y) o.cubeUV = v.color.xz * 255; #elif defined(_FACES_Z) o.cubeUV = v.color.xy * 255; #endif }
|
我们终于有了一个功能性的网格纹理。 请注意,每对面之一的UV坐标是镜像的,但这不是重点,因为我们使用的是对称纹理。
本文标题:Rounded Cube 4
文章作者:Keyle
发布时间:2017-11-25
最后更新:2017-11-26
原始链接:https://vrast.cn/posts/60f3453/
版权声明:©Keyle's Blog. 本站采用署名-非商业性使用-相同方式共享 4.0 国际进行许可