[Unity] 字符风格shader

知乎上看到字符风格的shader,然后照着自己撸了一遍代码,微做修改,增加了控制材质的C#代码
https://zhuanlan.zhihu.com/p/30775000
先看一下我实现的效果(字符由大到小,最后字符过密产生摩尔纹),素材图片在文章末尾:
这里写图片描述

思路是这样的:
将原图分割为很多个小方块,然后取小方块左上角位置的颜色,计算灰度值。
灰度值和字符图上的字符一一对应。最终就实现了字符组成的图片。当然这种左上角取颜色的方式只适合大色块的原始图。

下面是稍作修改的shader代码,注释已经写好了。

Shader "Custom/CharacterStyleShader" {
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _CharTex ("Char texture", 2D) = "white" {}
        //每个字符所占的uv比例,由C#传入
        _WidthPerChar("Width per char", Range(0.0, 1.0)) =  0.001
        //(字符图上)一共支持几个色阶
        _CharCount("Char count", int) = 16
        //(字符图上)每行几个色阶
        _CharCountPerRow("char per row", int) = 4
    }

    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }
            float _WidthPerChar;
            sampler2D _MainTex;
            int _CharCountPerRow;
            int _CharCount;
            sampler2D _CharTex;

            fixed4 frag (v2f i) : SV_Target
            {
                //找到原图上网格的起点
                float2 startUv = float2(floor(i.uv.x / _WidthPerChar) * _WidthPerChar, floor(i.uv.y / _WidthPerChar) * _WidthPerChar);
                //找到字符图上相对网格起点的坐标
                float ratio = 1.0 / _WidthPerChar / _CharCountPerRow;
                float2 oppositeUv = float2((i.uv.x - startUv.x) * ratio, (i.uv.y - startUv.y) * ratio);
                //计算灰度值
                fixed3 color = tex2D(_MainTex, startUv).rgb;
                fixed luminosity = dot(color.rgb,fixed3(0.299,0.587,0.114));
                //计算灰度阶数
                int greyStep = floor(luminosity * _CharCount);
                //计算字符图上对应网格起点坐标
                float _ReciprocalPerRow = 1.0 / _CharCountPerRow;
                float2 greyStartUv = float2(floor(greyStep / _CharCountPerRow) * _ReciprocalPerRow, (greyStep % _CharCountPerRow) * _ReciprocalPerRow);
                //获取
                float2 greyUv = greyStartUv + oppositeUv;
                return tex2D(_CharTex, greyUv);
            }
            ENDCG
        }
    }
}

控制的C#代码:

//Author: 邵志恒
//E-mail: [email protected]
//参考 破晓(知乎专栏) https://zhuanlan.zhihu.com/p/30775000
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
public class CharacterStyleAdjust : MonoBehaviour {

    [Range(0.00001f,0.1f)]
    public float withPerChar = 0.001f;      //每个字符所占uv比例
    public int charCount = 16;              //色阶数 
    [Range(1, 16)]
    public int charCountPerRow = 4;         //每行色阶数

    private Renderer m_Renderer;
    private Material m_Mat;

    private MaterialPropertyBlock m_PropBlock;

    private int m_MainTexId = Shader.PropertyToID("_MainTex");
    private int m_CharTexId = Shader.PropertyToID("_CharTex");
    private int m_WidthPerCharId = Shader.PropertyToID("_WidthPerChar");
    private int m_CharCountId = Shader.PropertyToID("_CharCount");
    private int m_CharCountPerRowId = Shader.PropertyToID("_CharCountPerRow"); 

    void Awake() {
        m_PropBlock = new MaterialPropertyBlock();
        m_Renderer = this.GetComponent<MeshRenderer>();
        m_Mat = m_Renderer.sharedMaterial;
        Debug.Log(m_Mat.name);
        UpdatePropBlock();
    }

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        UpdatePropBlock();
    }

    void UpdatePropBlock()
    {
        m_Renderer.GetPropertyBlock(m_PropBlock);
        m_PropBlock.SetFloat(m_WidthPerCharId, withPerChar);
        m_PropBlock.SetFloat(m_CharCountId, charCount);
        m_PropBlock.SetFloat(m_CharCountPerRowId, charCountPerRow);
        m_Renderer.SetPropertyBlock(m_PropBlock);
    }
}

附:
字符图片:
这里写图片描述
原始图片:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/rickshaozhiheng/article/details/78503226