惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
Cisco Talos Blog
Cisco Talos Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
博客园 - 三生石上(FineUI控件)
Martin Fowler
Martin Fowler
WordPress大学
WordPress大学
D
Docker
S
SegmentFault 最新的问题
博客园 - 聂微东
美团技术团队
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
M
MIT News - Artificial intelligence
F
Fortinet All Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
GbyAI
GbyAI
L
LangChain Blog
Vercel News
Vercel News
博客园 - 叶小钗
MongoDB | Blog
MongoDB | Blog
Stack Overflow Blog
Stack Overflow Blog
H
Help Net Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
Engineering at Meta
Engineering at Meta
T
Threat Research - Cisco Blogs
T
Threatpost
Scott Helme
Scott Helme
T
Tailwind CSS Blog
Latest news
Latest news
Stack Overflow Blog
Stack Overflow Blog
Blog — PlanetScale
Blog — PlanetScale
The Register - Security
The Register - Security
罗磊的独立博客
P
Proofpoint News Feed
腾讯CDC
S
Schneier on Security
雷峰网
雷峰网
A
About on SuperTechFans
T
Tenable Blog
F
Full Disclosure
Cyberwarzone
Cyberwarzone
博客园_首页
有赞技术团队
有赞技术团队
K
Kaspersky official blog

文章列表

游戏玩后感:ReLief:献给亲爱的你 我的周边(谷子)分享 游戏玩后感:Kanon 简谱:致真实的你 《Rust中常见的有关生命周期的误解》学习笔记 简谱:StarMap 简谱:かく咲きたらばいと恋ひめやも 简谱:东风 简谱:无法诉说的思念 简谱:Girlish 游戏玩后感:时钟机关的Layline 简谱:风之琶音 简谱:星空的记忆 简谱:因为遇见了你 简谱:月童 番茄简谱脚本转调器 游戏玩后感:青空下的约定:Refine 游戏玩后感:在这苍穹展翅 书籍读后感:控制论与科学方法论 游戏玩后感:恋爱表达式 游戏玩后感:樱之诗 MLIR-tutorial学习笔记 游戏玩后感:潜伏之赤途 游戏玩后感:纯爱咖啡厅:帕露菲重制版 游戏玩后感:智以泪聚 游戏玩后感:初雪樱 游戏玩后感:告别回忆:从今以后 游戏玩后感:梦灯花 游戏玩后感:金辉恋曲四重奏 游戏玩后感:五彩斑斓的世界 昇腾310P使用记录 游戏玩后感:AIR 游戏玩后感:弹丸论破 游戏玩后感:流景之海的艾佩莉亚 Xilinx_HLS上板过程记录 游戏玩后感:告别回忆2 游戏玩后感:恋爱绮谭 Faiss和Rapidsai_Raft使用记录 游戏玩后感:近月少女的礼仪 游戏玩后感:樱色之云,绯色之恋 游戏玩后感:幸运草的约定 游戏玩后感:星之梦、候鸟和丸子与银河龙 游戏玩后感:白色相簿2 Windows上使用VTune分析PyTorchExtension调用的Cpp程序 SpinalHDL上板过程记录 游戏玩后感:仰望夜空的星辰 最简单的算卦方法之一:梅花易数法 游戏玩后感:苍之彼方的四重奏 krkr引擎解包工具介绍 自定义CUDA实现PyTorch算子的四种简单方法 游戏玩后感:星空的记忆 游戏玩后感:9nine 游戏玩后感:AtriMyDearMoments 游戏玩后感:极限脱出 游戏玩后感:魔女的夜宴 SSH实现多跳代理 动漫观后感:向山进发 flv重封装H264、AAC流 动漫观后感:夏日重现 CSP模板 游戏玩后感:海沙风云 动漫观后感:灵能百分百 游戏玩后感:交响乐之雨 游戏玩后感:爱上火车LastRun 游戏玩后感:LittleBustersEX 游戏玩后感:SummerPockets 游戏玩后感:逆转裁判 Ultra96V2开发板简单使用 SpinalWorkshop实验笔记(三) SpinalWorkshop实验笔记(二) SpinalWorkshop实验笔记(一) PYNQ开发板上使用USB声卡+OSS兼容层播放音频 TestOS移植K210开发板 rCore-Tutorial-Book-v3学习笔记(七) 动漫观后感:凉宫春日的忧郁 rCore-Tutorial-Book-v3学习笔记(♭七) rCore-Tutorial-Book-v3学习笔记(六) rCore-Tutorial-Book-v3学习笔记(五) rCore-Tutorial-Book-v3学习笔记(四) rCore-Tutorial-Book-v3学习笔记(三) rCore-Tutorial-Book-v3学习笔记(二) rCore-Tutorial-Book-v3学习笔记(一) 游戏玩后感:RewritePlus MIT-6.S081-2020实验(xv6-riscv64)十一:net MIT-6.S081-2020实验(xv6-riscv64)十:mmap MIT-6.S081-2020实验(xv6-riscv64)九:fs MIT-6.S081-2020实验(xv6-riscv64)八:lock MIT-6.S081-2020实验(xv6-riscv64)七:thread MIT-6.S081-2020实验(xv6-riscv64)六:cow MIT-6.S081-2020实验(xv6-riscv64)五:lazy MIT-6.S081-2020实验(xv6-riscv64)四:traps MIT-6.S081-2020实验(xv6-riscv64)三:pgtbl MIT-6.S081-2020实验(xv6-riscv64)二:syscall 动漫观后感:吹响吧上低音号 MIT-6.S081-2020实验(xv6-riscv64)一:util 快速生成网络mp4视频缩略图技术 用plantuml画图示例 QQ缩略图和大图不同实现 Python制作字符图片 动漫观后感:命运石之门
Unity3D+Post Processing Stack V2自定义后处理效果研究
VnYzm · 2020-07-14 · via

背景

众所周知,Unity3D支持自定义后处理效果,实现过程有三步: 1. 添加着色器,在着色器里书写后处理代码; 2. 添加材质,把材质和着色器绑定; 3. 给相机添加脚本,重写其OnRenderImage方法,将材质传入Graphics.Blit方法中。

但是在做最近的一个项目时,我使用了Unity3D的官方后处理插件Post Processing Stack V2(以下简称PPV2)来简化辉光、环境光遮蔽这类后处理效果的使用。但之后我又需要自定义一些后处理效果,此时就出现了问题。我发现我的OnRenderImage方法没有正常地接收到渲染帧经过插件处理后的纹理,而是接收到一个纯黑纹理,最后输出的也是纯黑,使得我的后处理效果无法正常工作,网上也找不到实际原因,可能和渲染管线的不同有关。为了解决这个问题,必须基于PPV2自定义一个效果,然后在其他代码中操作这个效果里的参数,由PPV2来执行我们的后处理效果。这个国内国外的教程都非常少,我主要参考了PPV2的官方文档,在这里给出。

代码

着色器

Shader "Hidden/Custom/Blend" {
    HLSLINCLUDE

        #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/StdLib.hlsl"

        TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
        TEXTURE2D_SAMPLER2D(_DesTex, sampler_DesTex);
        float _Alpha;

        float4 Frag(VaryingsDefault i) : SV_Target {
            float4 col1 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
            float4 col2 = SAMPLE_TEXTURE2D(_DesTex, sampler_DesTex, i.texcoord);
            float4 col = lerp(col2, col1, _Alpha);
            return col;
        }

    ENDHLSL

    SubShader {
        Cull Off ZWrite Off ZTest Always

        Pass {
            HLSLPROGRAM

                #pragma vertex VertDefault
                #pragma fragment Frag

            ENDHLSL
        }
    }
}

基本和文档中的一致,只是修改了片元着色器函数里的代码,实现将两张纹理进行混合的过程,另外由于这个文档比较新,实例的Shader语法好像和以前的CG语言不太一样,不知道是不是换成了HLSL。

效果自定义

using System;
using UnityEngine;
using UnityEngine.Rendering.PostProcessing;

[Serializable]
[PostProcess(typeof(BlendRenderer), PostProcessEvent.AfterStack, "Custom/Blend")]
public sealed class Blend : PostProcessEffectSettings {
    public TextureParameter DesTex = new TextureParameter();
    public FloatParameter Alpha = new FloatParameter();
}

public sealed class BlendRenderer : PostProcessEffectRenderer<Blend>
{
    public override void Render(PostProcessRenderContext context) {
        var sheet = context.propertySheets.Get(Shader.Find("Hidden/Custom/Blend"));
        sheet.properties.SetTexture("_DesTex", settings.DesTex);
        sheet.properties.SetFloat("_Alpha", settings.Alpha);
        context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
    }
}

这里定义了两个类,一个是设置类,提供了后处理效果所需的各种属性,其中支持的属性类型可以在项目下Packages/Post Processing/PostProcessing/Runtime/ParameterOverride.cs里找到,对应的基础类型有int、float、color、vector2、vector3、vector4、spline和texture。第二个类用来重写后处理方法,一般在这里指定要用的shader和给shader里的变量赋值。

修改效果参数

    void Start() {
        m_Blend = ScriptableObject.CreateInstance<Blend>();
        m_Blend.enabled.Override(true);
        m_Blend.Alpha.Override(1f);
        m_Blend.DesTex.Override(Texture2D.blackTexture);
        m_Volume = PostProcessManager.instance.QuickVolume(8, 100f, m_Blend);
        // 8是后处理所在的层
    }

这一段是初始化,先创建后处理效果,然后将其加入到后处理体积中。初始化后处理效果参数用Override方法,注意QuickVolume方法的第一个参数非常重要,它对应在PostProcessing Layer组件里填写的层的编号。

m_Blend.DesTex.value = tex; // tex -> Texture2D
m_Blend.Alpha.value = Alpha; // Alpha -> float

平常赋值直接修改属性名的value属性。

    private void OnDestroy() {
        RuntimeUtilities.DestroyVolume(m_Volume, true, true);
    }

注意在对象被销毁时要将创建的临时后处理体积销毁。如果没有这一段,更换场景时后处理会继续工作,不是我们想要的效果。

总结

Unity3D+Post Processing Stack V2自定义后处理效果其实也是只有三步,就是编写后处理着色器、编写后处理效果类、编写操作后处理参数类。主要还是国内外的教程没有与时俱进导致资料查找困难,希望更多的新教程能不断涌现,方便开发者的学习。

更新

使用已有的后处理体积

在上面的代码中,后处理体积是临时创建的,所以自定义后处理效果也是由代码生成的。如果是修改已有的后处理效果的参数,可以使用下面的代码:

m_Volume = GetComponent<PostProcessVolume>();
volume.profile.TryGetSettings<Blend>(out m_Blend);

先获取脚本所在物体的后处理体积组件,然后直接获取已有的后处理效果的设置类,之后就可以修改属性了。

m_Blend.DesTex.value = tex; // tex -> Texture2D
m_Blend.Alpha.value = Alpha; // Alpha -> float

构建时的注意事项

由于我们在代码中引用了Hidden/Custom/Blend这个着色器文件,但是场景中并没有什么物体引用这个shader,所以构建时可能不会打包这个shader文件,导致实际运行时出现错误。我的解决方法是在场景中随意创建一个有渲染器的物体,然后创建一个引用这个shader的材质,再将材质传给这个物体,这样打包时就不会忽略了。当然可能有其他的方案有待我学习。