文章目录

  • 前言
    • Compute Shader的简单介绍
    • Compute Shader在Editor中
    • Unity Compute Shader代码原理简介
    • CPU对照组
    • 运用Compute Shader解决问题
    • 效果

前言

好久不见!今天使用Unity Compute Shader来实现一个大量正方体的随机颜色赋值,作为我的Unity ComputeShader入门练习。这个练习可以说很经典了。

Compute Shader的简单介绍

使用Compute Shader可以让GPU参与任意数据类型的运算,以此减小CPU的运算负荷。总所周知GPU十分擅长执行大量并行的简单算法,所以将此类运算交给GPU将能有效提升项目运行效率。Unity的Compute Shader使用的是HLSL书写。
你可以将Compute Shader当做C#脚本的一种延申,Compute Shader需要通过脚本来告诉它该什么时候执行以及如何执行。

Compute Shader在Editor中

你可以在Create -> Shader -> Compute Shader新建一个Compute Shader。

Unity Compute Shader代码原理简介

// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> Result;[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{// TODO: insert actual code here!Result[id.xy] = float4(id.x & id.y, (id.x & 15)/15.0, (id.y & 15)/15.0, 0.0);
}

这就是Compute Shader默认代码,你在里面先声明Compute Shader运行时(从C#里面Dispatch时)要调用的函数(#pragma kernel CSMain),kernel可以有很多个。用于和C#脚本传递数据的参数(这里是RWTexture2D,要处理任意数据一般使用StructuredBuffer类型),以及函数本身的定义(在这里他产生了一堆float4的数据,其实就是一张图),函数参数括号里面的东西是线程的ID。
此外,你还需要调整numthreads里的参数,这个玩意指定了Compute Shader会生成的线程数,需要根据情况设置,具体的我也不懂了,先保持默认。
函数内部的运算要尽可能简单,GPU不能很好的执行分支操作,所以也不要在里面做if之类的操作。
如果你对细节感兴趣,链接这篇老外写的文章能解释更多。

Getting Started With Compute Shaders In Unity
知乎中文翻译版:
Unity3d | 浅谈 Compute Shader
简书大佬教程
Unity Compute Shader入门初探

CPU对照组

为了体现Compute Shader的作用,我们先实现一个单纯使用CPU的对照组方法。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;struct Cube
{public Vector3 position;public Color color;
}public class ComputeShaderDemo : MonoBehaviour
{public int repetions;public List<GameObject> objects;public int count = 50;private void Start(){CreateCubes();}private void CreateCubes(){for (int i = 0; i < count; i++){for (int j = 0; j < count; j++){var go = GameObject.CreatePrimitive(PrimitiveType.Cube);go.transform.position = new Vector3(i, j, 0);Color color = UnityEngine.Random.ColorHSV();go.GetComponent<MeshRenderer>().material.SetColor("_Color", color);objects.Add(go);go.transform.SetParent(this.transform);}}}[ContextMenu("OnRandomize CPU")]public void OnRandomizeCPU(){for (int i = 0; i < repetions; i++){for (int c = 0; c < objects.Count; c++){GameObject obj = objects[c];obj.transform.position = new Vector3(obj.transform.position.x, obj.transform.position.y, UnityEngine.Random.Range(-0.1f, 0.1f));obj.GetComponent<MeshRenderer>().material.SetColor("_Color", UnityEngine.Random.ColorHSV());}}}

上述为C#脚本,干的事情就是给一堆正方体对象随机赋予颜色和y轴坐标,然后重复若干次,目的就是为了模拟需要大量运行的简单运算。

在50 * 50个正方体,执行1000次时,我的CPU运行起来就已经相当卡了,10000次重复直接卡死。

运用Compute Shader解决问题

现在我们将运用Compute Shader调用GPU来进行运算。

#pragma kernel CSMainstruct Cube {float3 position;float4 color;
};
// StructuredBuffer
RWStructuredBuffer<Cube> cubes;
float repetions;
float resolution;// GPU将用到的随机算法
float rand(float2 co)
{return(frac(sin(dot(co.xy, float2(12.9898, 78.233))) * 43758.5453)) * 1;
}[numthreads(10,1,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{float xPos = id.x / resolution;Cube cube = cubes[id.x];for (int i = 0; i < repetions; i++){float zPos = rand(float2(xPos, cube.position.z));cube.position.z = zPos;float r = rand(float2(cube.color.r, cube.color.g));float g = rand(float2(cube.color.g, cube.color.b));float b = rand(float2(cube.color.b, cube.color.r));cube.color = float4(r, g, b, 1.0);}cubes[id.x] = cube;
}

这是用来做这件事的Compute Shader代码,基本上干的就是OnRandomizeCPU的事情,当然,数据要从C#脚本中传递给Compute Shader,Compute Shader拿数据做完运算后再将运算结果返回给C#脚本,脚本最后再运用这些结果。

    [ContextMenu("OnRandomize GPU")]public void OnRandomizeGPU(){int colorSize = sizeof(float) * 4;int vector3Size = sizeof(float) * 3;int totalSize = colorSize + vector3Size;// 这玩意将与Compute Shader中的StructuredBuffer绑定ComputeBuffer cubeBuffer = new ComputeBuffer(data.Length, totalSize);// 将需要处理的数据放到buffer里面cubeBuffer.SetData(data);// 将cubeBuffer与Compute Shader中的StructuredBuffer绑定(可以这么说吧)// 现在cubeBuffer相当于CPU与GPU之间的输入输出缓冲区computeShader.SetBuffer(0, "cubes", cubeBuffer);computeShader.SetFloat("resolution", data.Length);computeShader.SetFloat("repetions", repetions);// 执行Compute ShadercomputeShader.Dispatch(0, data.Length / 10, 1, 1);// 从缓冲区获取数据cubeBuffer.GetData(data);// 运用数据for (int i = 0; i < objects.Count; i++){GameObject obj = objects[i];Cube cube = data[i];obj.transform.position = cube.position;obj.GetComponent<MeshRenderer>().material.SetColor("_Color", cube.color);}cubeBuffer.Dispose();}
}

这是C#脚本,干的就是我刚刚说的,传递数据给Compute Shader,运行Shader,拿到结果并将结果赋值给对象。

效果

效果可以说非常好了,10000次重复都是秒完成,当次数到100万次时才出现了一点点延迟,Compute Shader的性能瓶颈往往来自数据传递过程。

Unity Compute Shader入门(大量对象随机赋值颜色实验)相关推荐

  1. Unity Shader入门精要第3 章 Unity Shader 基础

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一.Unity Shader 概述 二.使用步骤 1.3.1.2 Unity 中的材质 2.Unity 中的Shader 3.Unity ...

  2. unity shader入门精要_Unity Shader 入门(一):渲染流水线

    一.参考与说明(需要写在开始东西): 1.1 Unity Shader 入门紧要学习 candycat1992/Unity_Shaders_Book​github.com 1.2 还有一些图形学的历史 ...

  3. 《Unity Shader 入门精要》读书笔记

    <Unity Shader 入门精要>读书笔记 --记录一下自己看书时遇到的一下困惑的地方和自己的一些想法,愿明天的我更加强大 1.要正确获得阴影和光照衰减效果,需要#pragma mul ...

  4. Unity Shader入门精要——第3章 Unity Shader基础

    Unity Shader入门精要读书笔记系列 第1章 欢迎来到Shader的世界 第2章 渲染流水线 第3章 Unity Shader基础 文章目录 Unity Shader入门精要读书笔记系列 前言 ...

  5. unity Shader 入门精要 EX

    unity Shader 入门精要: 1.shader概念 2.shader分类(顶点Shader.像素Shader) 3.Shader编程语言 4.Unity Shader 4.1概述 4.2分类( ...

  6. Unity Shader入门介绍

    原文地址:http://www.bubuko.com/infodetail-655318.html 刚开始接触Unity3D Shader编程时,你会发现有关shader的文档相当散,这也造成初学者对 ...

  7. Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照

    转自冯乐乐的<Unity Shader入门精要> 通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交 ...

  8. Unity Shader入门精要第七章 基础纹理之遮罩纹理

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一.实践 参考 前言 遮罩纹理(mask texture)是本章要介绍的最后一种纹理,它非常有用,在很多商业游戏中 都可以见到它的身影. ...

  9. Unity Shader入门精要第四章:学习Shader 所需的数学基础--坐标空间

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一.4.6.1 为什么要使用这么多不同的坐标空间 二.4.6.3 顶点的坐标空间变换过程 4.6.4 模型空间 4.6.6 观察空间 4 ...

  10. Unity Shader入门笔记

    学习资料:https://onevcat.com/2013/07/shader-tutorial-1/猫都能学会的Unity3D Shader入门指南(一)(二) 学习资料:http://98jy.n ...

最新文章

  1. linux下typora安装
  2. 强烈推荐一款Python可视化神器!
  3. python 操作mysql 返回字典_Python查询Mysql时返回字典结构的代码
  4. 零基础python从入门到精通 pdf-跟老齐学Python从入门到精通.pdf
  5. .Net 程序集 签名工具sn.exe 密钥对SNK文件 最基本的用法
  6. 《统计学》学习笔记之参数估计
  7. linux刻录win10u盘_手把手教你装系统之【制作官方win10安装U盘】
  8. l2-002 链表去重 (未解决)
  9. 甘肃省智慧教育云平台实名认证_“好分数”甘肃行,人工智能助力教育均衡
  10. mybatis_MyBatis下载
  11. fqa什么意思_FQA是什么意思
  12. java单词大全_编程常用英语单词大全
  13. 金山打字通 右手练习
  14. 综述:基于深度学习的文本分类 --《Deep Learning Based Text Classification: A Comprehensive Review》总结(二)
  15. “海大与我“ Scrum Meeting(第九周会议记录)
  16. python是面向对象开发_Python之面向对象
  17. Labview移位寄存器理解(例子说明)
  18. 机器学习(六)--------python实现朴素贝叶斯对email分类
  19. 在线预览office文件
  20. flutter icon 大全

热门文章

  1. 运放输入偏置电流方向_运算放大器的输入偏置电流
  2. 微信群如何设置永久有效二维码?99.99%的人都不知道!
  3. oracle 生成拼音输入码,c# 生成拼音输入码
  4. java笑话_[转]爆笑程序员的笑话集锦
  5. java数字与大写字母转化_数字 和 大小写字母之间的转换 10进制和26进制之间的转换...
  6. 在两个电子表格中找出相同的姓名
  7. 董明珠赞同取消住房公积金 格力员工每人一套房
  8. 一年月份大小月口诀_农历大小月卦口诀详解(最新版)
  9. ROS2暑期学校 ROS2 Summer School 2022-转-
  10. SQL注入中information_schema的作用