1. 概述

在上一篇文章《Unity3D学习笔记6——GPU实例化(1)》详细介绍了Unity3d中GPU实例化的实现,并且给出了详细代码。不过其着色器实现是简单的顶点+片元着色器实现的。Unity提供的很多着色器是表面着色器,通过表面着色器,也是可以实现GPU实例化的。

2. 详论

2.1. 实现

首先,我们还是挂接与上篇文章一样的脚本:

using UnityEngine;

[ExecuteInEditMode]
public class Note7Main : MonoBehaviour
{
public Mesh mesh;
public Material material; int instanceCount = 200;
Bounds instanceBounds; ComputeBuffer bufferWithArgs = null;
ComputeBuffer instanceParamBufferData = null; // Start is called before the first frame update
void Start()
{
instanceBounds = new Bounds(new Vector3(0, 0, 0), new Vector3(100, 100, 100)); uint[] args = new uint[5] { 0, 0, 0, 0, 0 };
bufferWithArgs = new ComputeBuffer(1, args.Length * sizeof(uint), ComputeBufferType.IndirectArguments);
int subMeshIndex = 0;
args[0] = mesh.GetIndexCount(subMeshIndex);
args[1] = (uint)instanceCount;
args[2] = mesh.GetIndexStart(subMeshIndex);
args[3] = mesh.GetBaseVertex(subMeshIndex);
bufferWithArgs.SetData(args); InstanceParam[] instanceParam = new InstanceParam[instanceCount]; for (int i = 0; i < instanceCount; i++)
{
Vector3 position = Random.insideUnitSphere * 5;
Quaternion q = Quaternion.Euler(Random.Range(0.0f, 90.0f), Random.Range(0.0f, 90.0f), Random.Range(0.0f, 90.0f));
float s = Random.value;
Vector3 scale = new Vector3(s, s, s); instanceParam[i].instanceToObjectMatrix = Matrix4x4.TRS(position, q, scale);
instanceParam[i].color = Random.ColorHSV();
} int stride = System.Runtime.InteropServices.Marshal.SizeOf(typeof(InstanceParam));
instanceParamBufferData = new ComputeBuffer(instanceCount, stride);
instanceParamBufferData.SetData(instanceParam);
material.SetBuffer("dataBuffer", instanceParamBufferData);
material.SetMatrix("ObjectToWorld", Matrix4x4.identity);
} // Update is called once per frame
void Update()
{
if (bufferWithArgs != null)
{
Graphics.DrawMeshInstancedIndirect(mesh, 0, material, instanceBounds, bufferWithArgs, 0);
}
} private void OnDestroy()
{
if (bufferWithArgs != null)
{
bufferWithArgs.Release();
} if (instanceParamBufferData != null)
{
instanceParamBufferData.Release();
}
}
}

不过,脚本的材质设置需要使用我们新的材质:

这个材质可以通过使用Standard Surface Shader作为我们修改的模板:

修改后的着色器代码如下:

Shader "Custom/SimpleSurfaceIntanceShader"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200 CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
#pragma target 4.5
#pragma multi_compile_instancing
#pragma instancing_options procedural:setup struct InstanceParam
{
float4 color;
float4x4 instanceToObjectMatrix;
}; #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
StructuredBuffer<InstanceParam> dataBuffer;
#endif float4x4 ObjectToWorld; sampler2D _MainTex; struct Input
{
float2 uv_MainTex;
}; half _Glossiness;
half _Metallic;
fixed4 _Color; void setup()
{
#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
InstanceParam data = dataBuffer[unity_InstanceID];
unity_ObjectToWorld = mul(ObjectToWorld, data.instanceToObjectMatrix);
#endif
} void surf (Input IN, inout SurfaceOutputStandard o)
{
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}

最后的显示效果如下:

2.2. 解析

对比修改之前的着色器代码:

  1. #pragma multi_compile_instancing的意思是给这个着色器增加了实例化的变体,也就是增加了诸如INSTANCING_ON PROCEDURAL_ON这样的关键字,可以编译实例化的着色器版本。
  2. #pragma instancing_options procedural:setup是搭配Graphics.DrawMeshInstancedIndirect 使用的,在顶点着色器阶段开始时,Unity会调用冒号后指定的setup()函数。
  3. setup()函数的意思是通过实例化Id也就是unity_InstanceID,找到正确的实例化数据,并且调整Unity的内置变量unity_ObjectToWorld——也就是模型矩阵。正如上一篇文章所言,GPU实例化的关键就在于模型矩阵的重新计算。在Unity API官方示例中,还修改了其逆矩阵unity_WorldToObject。

3. 参考

  1. 《Unity3D学习笔记6——GPU实例化(1)》
  2. Graphics.DrawMeshInstancedIndirect
  3. Declaring and using shader keywords in HLSL
  4. Creating shaders that support GPU instancing

具体实现代码

Unity3D学习笔记7——GPU实例化(2)的更多相关文章

  1. Unity3D学习笔记8——GPU实例化(3)

    目录 1. 概述 2. 详论 2.1. 自动实例化 2.2. MaterialPropertyBlock 3. 参考 1. 概述 在前两篇文章<Unity3D学习笔记6--GPU实例化(1)&g ...

  2. Unity3D学习笔记6——GPU实例化(1)

    目录 1. 概述 2. 详论 3. 参考 1. 概述 在之前的文章中说到,一种材质对应一次绘制调用的指令.即使是这种情况,两个三维物体使用同一种材质,但它们使用的材质参数不一样,那么最终仍然会造成两次 ...

  3. unity3d学习笔记(一) 第一人称视角实现和倒计时实现

    unity3d学习笔记(一) 第一人称视角实现和倒计时实现 1. 第一人称视角 (1)让mainCamera和player(视角对象)同步在一起 因为我们的player是生成的,所以不能把mainCa ...

  4. Unity3D学习笔记2——绘制一个带纹理的面

    目录 1. 概述 2. 详论 2.1. 网格(Mesh) 2.1.1. 顶点 2.1.2. 顶点索引 2.2. 材质(Material) 2.2.1. 创建材质 2.2.2. 使用材质 2.3. 光照 ...

  5. Unity3D学习笔记3——Unity Shader的初步使用

    目录 1. 概述 2. 详论 2.1. 创建材质 2.2. 着色器 2.2.1. 名称 2.2.2. 属性 2.2.3. SubShader 2.2.3.1. 标签(Tags) 2.2.3.2. 渲染 ...

  6. Unity3D学习笔记4——创建Mesh高级接口

    目录 1. 概述 2. 详论 3. 其他 4. 参考 1. 概述 在文章Unity3D学习笔记2--绘制一个带纹理的面中使用代码的方式创建了一个Mesh,不过这套接口在Unity中被称为简单接口.与其 ...

  7. Unity3D学习笔记12——渲染纹理

    目录 1. 概述 2. 详论 3. 问题 1. 概述 在文章<Unity3D学习笔记11--后处理>中论述了后处理是帧缓存(Framebuffer)技术实现之一:而另外一个帧缓存技术实现就 ...

  8. 一步一步学习Unity3d学习笔记系1.3 英雄联盟服务器集群架构猜想

    说到了网游那就涉及到服务器了,时下最火的属英雄联盟了,我也是它的粉丝,每周必撸一把,都说小撸怡情,大撸伤身,强撸灰飞烟灭,也告诫一下同仁们,注意身体,那么他的服务器架构是什么呢,给大家分享一下, 具体 ...

  9. Unity3D 学习笔记

    不是什么技术文章,纯粹是我个人学习是遇到一些觉得需要注意的要点,当成笔记. 1.关于调试,在Android下无法断点,Debug也无法查看,查看日志方法可以启动adb的log功能,或者自己写个GUI控 ...

随机推荐

  1. 09. 树莓派ASP.NET环境配置

    在树莓派上部署ASP.NET环境(树莓派做ASP.NET项目服务器),之后Windows上开发的ASP.NET项目可以部署在树莓派上.配置过程如下: 前言:本篇文章内容是根据mono官网上查阅的配置教 ...

  2. XCTF练习题---MISC---功夫再高也怕菜刀

    XCTF练习题---MISC---功夫再高也怕菜刀 flag:flag{3OpWdJ-JP6FzK-koCMAK-VkfWBq-75Un2z} 解题步骤: 1.观察题目,下载附件 2.下载到电脑后发现 ...

  3. 『现学现忘』Git基础 — 18、Git对象的总结

    目录 1.Git操作最基本的流程 2.工作目录中文件的状态 3.Git效率说明 提示:前面三篇文章已经分别的对blob对象.tree对象.commit对象进行了详细的说明,这篇文章我们总结一下,Git ...

  4. FreeRTOS --(16)资源管理之临界区

    转载自 https://blog.csdn.net/zhoutaopower/article/details/107387427 临界区的概念在任何的 SoC 都存在,比如,针对一个寄存器,基本操作为 ...

  5. 一个比 Nginx 功能更强大的 Web 服务器

    公众号关注 「开源Linux」 回复「学习」,有我为您特别筛选的学习资料~ Caddy 简介 Caddy 是一个 Go 编写的 Web 服务器,类似于 Nginx,Caddy 提供了更加强大的功能,随 ...

  6. Water 2.6.3 发布,一站式服务治理平台

    Water(水孕育万物...) Water 为项目开发.服务治理,提供一站式解决方案(可以理解为微服务架构支持套件).基于 Solon 框架开发,并支持完整的 Solon Cloud 规范:已在生产环 ...

  7. DOM操作标签,事件绑定,jQuery框架

    DOM操作标签 ''' 在起变量名的时候 如果该变量指向的是一个标签 那么建议使用 xxxEle eg:aEle\pEle\divEle\spanEle ''' 基本使用 动态创建一个标签 var 变 ...

  8. drools中query的使用

    一.背景 我们知道在drools中是存在工作内存的,我们的Fact对象会加入到工作内存中,同时我们自己也可以在drl文件中使用insert/modify/update/delete等方法,修改工作内存 ...

  9. arts-week11

    Algorithm 69. Sqrt(x) - LeetCode Review Building a network attached storage device with a Raspberry ...

  10. 141. Linked List Cycle - LeetCode

    Question 141. Linked List Cycle Solution 题目大意:给一个链表,判断是否存在循环,最好不要使用额外空间 思路:定义一个假节点fakeNext,遍历这个链表,判断 ...