渲染9——复杂材质

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wodownload2/article/details/82261833

创建一个自定义的shader GUI
混合金属和非金属
使用不统一的光滑度
支持自发光表面

本节是渲染课程的第九节。上一节我们学习了如何反射周围的环境,包括反射环境光和周围的建筑物。本节我们会使用更多多的贴图创建更复杂的材质。但是在此之前,我们要需要一个更好的GUI来显示shader的属性。

本节课程使用untiy版本为5.4.1f1
这里写图片描述

1 用户接口
unity标准的shader有很好的展示界面,我们也要自己定制一个属性面板,来显示shader。

1.1 ShaderGUI
创建一个继承了UnityEditor.SahderGUI类,如下:

using UnityEngine;
using UnityEditor;
public class MyLightingSahderGUI:ShaderGUI
{
    ……
}

为了使用自定义的渲染器,还需要在shader中添加一行代码:

Shader "Custom/My First Lighting Shader" 
{
    CustomEditor "MyLightingShaderGUI"
}

重新OnGUI方法:

public class MyLightingShaderGUI:ShaderGUI
{
    public override void OnGUI(MaterialEditor editor, MaterialProperty[] properties)
    {
        ……
    }
}

1.2 创建一个label

public override void OnGUI (
        MaterialEditor editor, MaterialProperty[] properties
    ) {
        DoMain();
    }

    void DoMain() {
        GUILayout.Label("Main Maps", EditorStyles.boldLabel);
    }

效果如下:
这里写图片描述

1.3 显示反射率
把OnGUI中的传递的属性数组保存起来:

MaterialEditor editor;
MaterialProperty[] properties;
public override void OnGUI(MaterialEditor editor, MaterialProperty[] properties)
{
    this.eidtor = editor;
    this.properties = properties;
    DoMain();
}

根据名字找到shader中的某个属性:

void DoMain()
{
    MaterialProperty mainTex = FindProperty("_MainTex", properties);
}

给属性一个显示的名字:

void DoMain()
{
    MaterialProperty mainTex = FindProperty("_MainTex", properties);
    GUIContent albedoLabel = new GUIContent("Albedo");
}

因为在shader中属性_MainTex的显示名就已经为Albedo:

_MainTex("Albedo", 2D) = "white"{}

所以我们可以直接用这个属性的展示名:

void DoMain()
{
    MaterialProperty mainTex = FindProperty("_MainTex", properties);
    GUIContent albedoLabel = new GUIContent(mainTex.displayName);
    editor.TexturePropertySingleLine(albedoLabel, mainTex);
}

这样写了之后:
这里写图片描述

这个和unity内置的standard shader类似,但是内置的比我们自定义的还多了提示信息。当你的鼠标悬停在属性上的时候要给出提示可以通过下面的方法:

GUIContent albedoLabel = new GUIContent(mainTex.displayName, "Albedo (RGB)"); 

只要把原来的label后面再添加要给tip字符串就可以了。
这里写图片描述

TexturePropertySingleLine 函数后面还可以加上额外的属性,然后显示在一行,比如下面:

MaterialProperty tint = FindProperty("_Tint", properties);
editor.TexturePropertySingleLine(albedoLabel, mainTex, tint);

这里写图片描述

为了贴图增加scale和offset的设置选项:

editor.TextureScaleOffsetProperty(mainTex);

这里写图片描述

1.4 提取方法
上面找属性的方法可以共用出来,如下:

MaterialProperty FindProperty (string name) 
{
    return FindProperty(name, properties);
}

简化之后我们的代码变为:

void DoMain()
{
    GUILayout.Label("Main Maps", EditorStyles.boldLabel);
    MaterialProperty mainTex = FindProperty("_MainTex");
    GUIContent albedoLabel = new GUIContent(mainTex.displayName, "Albedo (RGB)");
    editor.TexturePropertySingleLine(albedoLabel, mainTex , FindProperty("_Tint"));
    editor.TextureScaleOffsetProperty(mainTex);
}

创建一个静态的文本方法:

static GUIContent staticLabel = new GUIContent();
static GUIContent MakeLabel(string text, string toolTip = null)
{
    staticLabel.text = text;
    staticLabel.tooltip = toolTip;
    return staticLabel;
}

更简单的方法是直接利用属性的display name作为label的text。则有如下的方法:

static GUIContent MakeLabel(MaterialProperty property, string tooltip = null)
{
    staticLabel.text = property.displayName;
    staticLabel.tooltip = tooltip;
    return staticLabel;
}

那么现在就可以进一步的简化代码了:

void DoMain()
{
    GUILayout.Label("Main Maps", EditorStyles.boldLabel);
    MaterialProperty mainTex = FindProperty("_MainTex");
    editor.TexturePropertySingleLine(MakeLabel(mainTex, "Albedo (RGB)"), mainTex , FindProperty("_Tint"));
    editor.TextureScaleOffsetProperty(mainTex);
}

1.5 显示法线
创建单独的函数显示法线:

DoNormals();
editor.TextureScaleOffsetProperty(mainTex);

然后再DoNormals()中加入下面的代码:

void DoNormals()
{
    MaterialProperty map = FindProperty("_NormalMap");
    editor.TexturePropertySingleLine(MakeLabel(map), map);
}

然后在法线贴图下面添加一个凹凸系数:

void DoNormals()
{
    MaterialProperty map = FindProperty("_NormalMap");
    editor.TexturePropertySingleLine(MakeLabel(map), map, FindProperty("_BumpScale"));
}

这样之后就会得到:
这里写图片描述

这样不管Normals贴图是否赋值上去,都会有一个scale,那么标准的shader中不是这样的,当有值得时候才会显示这个scale。
这里写图片描述
这里写图片描述

1.6 显示金属和光滑度

void DoMetallic () 
{
    MaterialProperty slider = FindProperty("_Metallic");
    EditorGUI.indentLevel += 2;
    editor.ShaderProperty(slider, MakeLabel(slider));
    EditorGUI.indentLevel -= 2;
}

void DoSmoothness () {
    MaterialProperty slider = FindProperty("_Smoothness");
    EditorGUI.indentLevel += 2;
    editor.ShaderProperty(slider, MakeLabel(slider));
    EditorGUI.indentLevel -= 2;
}

这里写图片描述

1.7 显示第二个纹理贴图和法线贴图
和显示第一个贴图一样,我们直接这样做:

void DoSecondary () {
        GUILayout.Label("Secondary Maps", EditorStyles.boldLabel);

        MaterialProperty detailTex = FindProperty("_DetailTex");
        editor.TexturePropertySingleLine(
            MakeLabel(detailTex, "Albedo (RGB) multiplied by 2"), detailTex
        );
        DoSecondaryNormals();
        editor.TextureScaleOffsetProperty(detailTex);
    }

    void DoSecondaryNormals () {
        MaterialProperty map = FindProperty("_DetailNormalMap");
        editor.TexturePropertySingleLine(
            MakeLabel(map), map,
            map.textureValue ? FindProperty("_DetailBumpScale") : null
        );
    }

这里写图片描述

2 混合金属和非金属
我们的shader是使用同一的变量来控制物体表面是否是金属,所以一个物体不是金属就是非金属,这个灵活性不大,所以需要使用一个滑动条来控制某个材质介于金属和非金属之间。

2.1 金属贴图
内置标准shader支持金属贴图,这个贴图定义了每个像素位置的金属性,而不是整个材质是否是金属。下面是一张灰白图来标记电路板的金属性。
这里写图片描述

增加一个金属贴图属性:

[NoScaleOffset] _MetallicMap ("Metallic", 2D) = "white" {}
[Gamma] _Metallic ("Metallic", Range(0, 1)) = 0

使用这个贴图的方法:

sampler2D _MetallicMap;
float _Metallic;

struct Interpolators
{
    ……
};

float GetMetallic(Interpolators i)
{
    return tex2D(_MetallicMap, i.uv.xy).r * _Metallic;
}

然后是在片段着色器中使用赋颜色:

float MyFragmentProgram(Interpolators i):SV_TARGET
{
    ……
    albedo = DiffuseAndSpecularFromMetallic(albedo, GetMetallic(i), specularTint, oneMinusReflectivity);
    ……
}

你可自己定义计算金属性的方法,在GetMetallic方法中修改。DiffuseAndSpecularFromMetallic函数在UnityStandardUtils中定义。

2.2 自定义GUI
添加金属贴图自定义面板:

void DoMetallic () 
{
        MaterialProperty map = FindProperty("_MetallicMap");
        editor.TexturePropertySingleLine(
            MakeLabel(map, "Metallic (R)"), map,
            FindProperty("_Metallic")
        );
}

这里写图片描述

2.3 贴图和滑动条
选择用金属贴图或者是滑动条:

editor.TexturePropertySingleLine(
            MakeLabel(map, "Metallic (R)"), map,
            map.textureValue ? null : FindProperty("_Metallic")
        );

无金属贴图:
这里写图片描述

这里写图片描述

2.4 自定义shader关键字

猜你喜欢

转载自blog.csdn.net/wodownload2/article/details/82261833