Unity3D后期Shader特效-马赛克1-基础(UV马赛克化)
=========源文件下载群========QQ群:818511955
=========================
最近在知乎上看到很多聊unity后期特效的文章。
自己研究了一下,做出了很多效果。
今天开一个新坑,做个系列教程。
欢迎大家,观看和讨论。
=======下面进入正文=======
先看最终效果
镜头特效的作用流程是:
在摄像机上挂载一个引入Shader的C#程序。
=====C#程序中渲染特效结构====
OnRenderImage(渲染输入,渲染输出)
{
Graphics.Blit(渲染输入,渲染输出,特效材质球);
}
==============
使用Shader驱动GPU渲染输出。
首先要在摄像机上添加一个C#程序。
在启动程序中,我预先确定用来处理图像的Shader名称。
在 OnRenderImage()渲染处理是系统默认函数。
使用Graphics.Blit()引入Shader和渲染图像。
C#中预先定义好将要使用的“马赛克尺寸”变量。
使用Material.SetInt()传入材质的“_TileSize”变量
CRLuo_CameraFX_Mosaic_Base.cs 代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//摄像机特效(马赛克)C#
public class CRLuo_CameraFX_Mosaic_Base : MonoBehaviour
{
//特效Shader变量
private Shader shader;
//特效材质球变量
private Material material;
//单块马赛克尺寸
public int tileSize = 10;
//程序启动处理部分
void Start()
{
//依据材质球路径和名称获取shader
shader = Shader.Find("CRLuo/CameraFXShader_Mosaic_Base");
//依据Shader创建材质球
material = new Material(shader);
}
//渲染处理部分
void OnRenderImage(RenderTexture InImg, RenderTexture OutImg)
{
//片段是否成功获取Shader
if (shader != null)
{
//给特效材质球传递马赛克块儿尺寸参数
material.SetInt("_TileSize", tileSize);
//渲染(输入渲染图像,输出渲染图像,使用材质球)
//输入渲染图像自动传递给材质球的_MainTex属性。
Graphics.Blit(InImg, OutImg, material);
}
else
{
//直接输出渲染图像
Graphics.Blit(InImg, OutImg);
}
}
}
======CameraFXShader_Mosaic_Base.shader
源代码
//材质的路径与名称
Shader "CRLuo/CameraFXShader_Mosaic_Base"
{
//材质的变量定义
Properties
{
_MainTex ("需要处理的图像", 2D) = "white" {}
_TileSize("块尺寸", Range(0, 100)) = 10
}
//子着色器
SubShader
{
//渲染队列顺序
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
//引入程序使用的函数集
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
//获取场景模型数据
struct appdata
{
//获取模型顶点数据
float4 vertex : POSITION;
//获取模型UV数据
float2 uv : TEXCOORD0;
};
//定义顶点片段着色器数据类型
struct v2f
{
//UV数据
float2 uv : TEXCOORD0;
//顶点数据
float4 vertex : SV_POSITION;
};
//载入材质球主贴图
sampler2D _MainTex;
//获取贴图的偏移与重复数据
float4 _MainTex_ST;
//载入马赛克尺寸(正整形数据)
uniform int _TileSize;
//顶点片段着色器程序
v2f vert (appdata v)
{
//定义输出数据
v2f o;
//顶点转换为摄像机视角坐标
o.vertex = UnityObjectToClipPos(v.vertex);
//应用贴图的偏移与重复
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
//输出模型结果
return o;
}
//表面着色器程序
fixed4 frag (v2f i) : SV_Target
{
//获取马赛克块数量 = 屏幕像素个数/块的像素个数
float2 TileSum = _ScreenParams / _TileSize;
//整理UV,让一个马赛克块儿中的UV统一为一个数据
float2 uv_Mosaic = ceil(i.uv *TileSum)/ TileSum;
//把整理后的UV结果赋给渲染图像,获得马赛克画面。
fixed4 col_Mosaic = tex2D(_MainTex, uv_Mosaic);
//输出图像 = 马赛克图像;
fixed4 col = col_Mosaic;
//输出贴图结果
return col;
}
ENDCG
}
}
}
自定义材质球名称与参数,注意与上面CS文件中使用的材质路径,名称与参数一致。
参数中我们定义了 _MainTex 主贴图(名称一定不要改),用来接收渲染图片。
使用_TileSize来定义马赛克尺寸(像素个数)。(一个数据是方形的,可以定义两个数据来保存长/宽)
并且在Pass(渲染片段)程序中正确的载入变量。
最后就是核心的,效果实现部分:
_ScreenParams是系统默认保存屏幕尺寸的二维变量
屏幕尺寸/马赛克像素尺寸=屏幕的横竖需要X,Y块马赛克
二维数据除以一维数据,相当于每个二维数据被除(X,Y)/A=(X/A,Y/A)
//获取马赛克块数量 = 屏幕像素个数/块的像素个数
float2 TileSum = _ScreenParams / _TileSize;
===========================
要想看懂接下来的内容,
我们需要知道,到底在对什么操作。
UV的0~1与贴图的0~1一一对应,如果我们使用程序重新定义一个UV坐标,然后就可以通过UV与贴图一一对应的关系,得到UV修改后的贴图。
=============================
原始i.UV的范围就是0~1,与输出图像一一对应。
使用 i.UV(原始UV数据)*块数,使得UV从0~1,放大到0~X。
然后使用,ceil()向上取整函数得到 1,2,3,4,5~X的UV分布。
结果除以块数,把UV约束回0~1范围,这时每块儿中UV数据相同。
//整理UV,让一个马赛克块儿中的UV统一为一个数据
float2 uv_Mosaic = ceil(i.uv *TileSum)/ TileSum;
随后应用UV数据给渲染图像
//把整理后的UV结果赋给渲染图像,获得马赛克画面。
fixed4 col_Mosaic = tex2D(_MainTex, uv_Mosaic);
输出图像结果
//输出图像 = 马赛克图像;
fixed4 col = col_Mosaic;
//输出贴图结果
return col;
=====本节完======
谢谢观看。 强啊 写的好详细 这是我见过写的最详细的教程
页:
[1]