Unity3D学习笔记7——GPU实例化(2)
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. 解析
对比修改之前的着色器代码:
#pragma multi_compile_instancing
的意思是给这个着色器增加了实例化的变体,也就是增加了诸如INSTANCING_ON PROCEDURAL_ON这样的关键字,可以编译实例化的着色器版本。#pragma instancing_options procedural:setup
是搭配Graphics.DrawMeshInstancedIndirect
使用的,在顶点着色器阶段开始时,Unity会调用冒号后指定的setup()函数。- setup()函数的意思是通过实例化Id也就是unity_InstanceID,找到正确的实例化数据,并且调整Unity的内置变量unity_ObjectToWorld——也就是模型矩阵。正如上一篇文章所言,GPU实例化的关键就在于模型矩阵的重新计算。在Unity API官方示例中,还修改了其逆矩阵unity_WorldToObject。
3. 参考
- 《Unity3D学习笔记6——GPU实例化(1)》
- Graphics.DrawMeshInstancedIndirect
- Declaring and using shader keywords in HLSL
- Creating shaders that support GPU instancing
Unity3D学习笔记7——GPU实例化(2)的更多相关文章
- Unity3D学习笔记8——GPU实例化(3)
目录 1. 概述 2. 详论 2.1. 自动实例化 2.2. MaterialPropertyBlock 3. 参考 1. 概述 在前两篇文章<Unity3D学习笔记6--GPU实例化(1)&g ...
- Unity3D学习笔记6——GPU实例化(1)
目录 1. 概述 2. 详论 3. 参考 1. 概述 在之前的文章中说到,一种材质对应一次绘制调用的指令.即使是这种情况,两个三维物体使用同一种材质,但它们使用的材质参数不一样,那么最终仍然会造成两次 ...
- unity3d学习笔记(一) 第一人称视角实现和倒计时实现
unity3d学习笔记(一) 第一人称视角实现和倒计时实现 1. 第一人称视角 (1)让mainCamera和player(视角对象)同步在一起 因为我们的player是生成的,所以不能把mainCa ...
- Unity3D学习笔记2——绘制一个带纹理的面
目录 1. 概述 2. 详论 2.1. 网格(Mesh) 2.1.1. 顶点 2.1.2. 顶点索引 2.2. 材质(Material) 2.2.1. 创建材质 2.2.2. 使用材质 2.3. 光照 ...
- 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. 渲染 ...
- Unity3D学习笔记4——创建Mesh高级接口
目录 1. 概述 2. 详论 3. 其他 4. 参考 1. 概述 在文章Unity3D学习笔记2--绘制一个带纹理的面中使用代码的方式创建了一个Mesh,不过这套接口在Unity中被称为简单接口.与其 ...
- Unity3D学习笔记12——渲染纹理
目录 1. 概述 2. 详论 3. 问题 1. 概述 在文章<Unity3D学习笔记11--后处理>中论述了后处理是帧缓存(Framebuffer)技术实现之一:而另外一个帧缓存技术实现就 ...
- 一步一步学习Unity3d学习笔记系1.3 英雄联盟服务器集群架构猜想
说到了网游那就涉及到服务器了,时下最火的属英雄联盟了,我也是它的粉丝,每周必撸一把,都说小撸怡情,大撸伤身,强撸灰飞烟灭,也告诫一下同仁们,注意身体,那么他的服务器架构是什么呢,给大家分享一下, 具体 ...
- Unity3D 学习笔记
不是什么技术文章,纯粹是我个人学习是遇到一些觉得需要注意的要点,当成笔记. 1.关于调试,在Android下无法断点,Debug也无法查看,查看日志方法可以启动adb的log功能,或者自己写个GUI控 ...
随机推荐
- Vue_基础功能循环、计算、绑定、事件处理、组件
1 <!DOCTYPE html> 2 <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xht ...
- 彻底解决Failed to execute goal on project xxxxx
1.错误内容:Could not resolve dependencies for project 今天在使用mvn clean package命令对一个子项目打包的时候出现如下错误(但是使用mave ...
- [AcWing 788] 逆序对的数量
点击查看代码 #include<iostream> using namespace std; typedef long long ll; const int N = 1e5 + 10; i ...
- clion 预编译文件的查看
看了一圈网上也没有我能一下就能看的懂的配置教程 我就手打一篇给在用clion的同学来参考一下 本文适用于g++编译 cmake Ninja生成器 clion 默认使用的是CMAKE来构建程序 生成器用 ...
- 详解六大国产CPU处理器
一个执着于技术的公众号 CPU作为计算机设备的运算和控制核心,负责指令读取.译码与执行,因研发门槛高.生态构建难,被认为是集成电路产业中的"珠穆朗玛峰". 纵观全球,Intel.A ...
- .net core JWT验证,HttpContext.User为空的问题
这几天在学习张老师.net core教程JWT部分,链接 https://mp.weixin.qq.com/s/7135y3MkUlPIp-flfwscig 教程使用的.net core 2.2, 在 ...
- Mysql数据库基础_复习思维导图
Mysql复习的一个小总结,用xmind写的.(字数没有都不给我发博客) 下面是一些备注 子查询 MySQL子查询称为内部查询,而包含子查询的查询称为外部查询. 子查询可以在使用表达式的任何地方使用, ...
- 在博客文章中使用mermaid 定义流程图,序列图,甘特图
概述 Mermaid(美人鱼)是一套markdown语法规范,用来在markdown文档中定义图形,包括流程图.序列图.甘特图等等. 它的官方网站是 https://mermaid-js.github ...
- 1.Docker简介
Docker是个什么东西 假定您在开发一个项目,您使用的是一台笔记本电脑而且您的开发环境具有特定的配置.其他开发人员身处的环境配置也各有不同.您正在开发的应用依赖于您当前的配置且还要依赖于某些配置文件 ...
- 好客租房13-在jsx中使用javascript表达式
嵌入js表达式 数据存储在js中 语法{javascript表达式} 注意语法中是单大括号 不是双大括号 //导入react import React from "react&quo ...