• 【Unity】Compute Shader计算BRDF存储到纹理


    在移动平台,BRDF的计算会消耗较多的ALU,同时对于BRDF计算结果的精度要求没有这么高。一种优化的方式是将BRDF的部分复杂计算,预计算存储到纹理中。已增加一张BRDF贴图和纹理采样器的代价,来节约ALU。

    将BRDF预计算存储到纹理的方式有很多,使用C#实现或者Unity2018的新的Custom Render Texture都可以很方便的实现功能。

    作为一个Compute Shader的入门,这里使用Compute Shader,也就是计算着色器来实现我们的需求。

    首先,我们新建一个C#脚本,BRDFGenerator.cs

     1 using UnityEditor;
     2 using UnityEngine;
     3 using System.Collections;
     4 using System.Collections.Generic;
     5 public class BRDFGenerator : ScriptableWizard
     6 {
     7     public ComputeShader computeShader;
     8     public int size=256;
     9  //   public RenderTexture rt;
    10     public Material mat;
    11     private int _kernel;
    12     [MenuItem("Texture Generator/BRDF Texture Generator")]
    13     static void CreateWizard()
    14     {
    15     //    ScriptableWizard.DisplayWizard<t>("Create Light", "Create", "Apply");
    16         ScriptableWizard.DisplayWizard<BRDFGenerator>("BRDF Texture Generator", "生成");
    17         //If you don't want to use the secondary button simply leave it out:
    18     }
    19     private void OnEnable()
    20     {
    21         Debug.Log("Start!");
    22     }
    23     void OnWizardCreate()
    24     {
    25         RenderTexture renderTexture = new RenderTexture(size,size,0,RenderTextureFormat.ARGB32);
    26         renderTexture.enableRandomWrite = true;
    27         renderTexture.Create();
    28      //   rt.enableRandomWrite = true;
    29         mat.SetTexture("_MainTex", renderTexture);
    30         float temp = size / 1.0f;
    31         _kernel = computeShader.FindKernel("CSMain");
    32         computeShader.SetTexture(_kernel, "Result", renderTexture);
    33         computeShader.SetFloat("size", temp);
    34         computeShader.Dispatch(_kernel, renderTexture.width / 8, renderTexture.height / 8, 1);
    35         Debug.Log("Sucess!");
    36     }
    37 
    38     void OnWizardUpdate()
    39     {
    40         helpString = "BRDF";
    41     }
    42 
    43 }
    BRDFGenerator

    BRDFGenerator.cs实现了一个窗口

     同时,还进行了线程的分发,这里,我们一个线程控制一个像素点。

    对应的Compute Shader如下:

     1 // Each #kernel tells which function to compile; you can have many kernels
     2 #pragma kernel CSMain
     3 
     4 // Create a RenderTexture with enableRandomWrite flag and set it
     5 // with cs.SetTexture
     6 RWTexture2D<float4> Result;
     7 float size;
     8 #define UNITY_PI            3.14159265359f
     9 #define UNITY_INV_PI        0.31830988618f
    10 float Pow5(float x)
    11 {
    12     return x*x*x*x*x;
    13 }
    14 [numthreads(8,8,1)]
    15 void CSMain (uint3 id : SV_DispatchThreadID)
    16 {
    17     // TODO: insert actual code here!
    18     float x=id.x/size;
    19     float y=id.y/size;
    20     //可见性项计算
    21     float roughness=x;
    22     float r2=roughness*roughness;
    23     float dot2=y*y;
    24     float V=   (-1 + sqrt(r2 * (1 - dot2) / dot2 + 1)) * 0.5f;
    25     //微表面分布项计算
    26     float nh=y;
    27     float d_temp = (nh * r2 - nh) * nh + 1.0f; 
    28        float D= UNITY_INV_PI * r2 / (d_temp * d_temp + 1e-7f); 
    29     //菲涅尔计算
    30     float cosA=x;
    31     float F=Pow5(1-cosA);
    32     //漫反射计算
    33     float fd90=y*2.5;
    34     float diffuse   = (1 + (fd90 - 1) * Pow5(1 - x))*0.4;
    35     //输出结果
    36     Result[id.xy] = float4(V, D, F, diffuse);
    37 }
    Compute Shader

    Compute Shader的语法和顶点及片段着色器没有什么区别,SV_DispatchThreadID的具体解释可以查阅MSDN。

    这里使用的BRDF的计算都是摘取的UnityStandardBRDF.cginc的实现,也可以选择自己的BRDF模型。

    BRDF的各项分别存储在RGBA四个通道中。计算速度比在C#中快超多。

    结果如下:

    RGB通道

    Alpha通道

  • 相关阅读:
    学习笔录——大话设计模式——简单工厂模式
    学习笔录——大话设计模式——代理模式
    学习笔录——大话设计模式——装饰模式
    经典扫雷下载
    C# 实现敏感词过滤
    C# 时间戳的相关操作
    easyui-datetimebox 控件绑定双击事件实现自动选中当前日期时间
    OpenGL笔记(4)纹理
    LearnOpenGL笔记(3)着色器
    c# 值类型和引用类型 笔记
  • 原文地址:https://www.cnblogs.com/jaffhan/p/7389450.html
Copyright © 2020-2023  润新知