Learn ComputeShader 15 Grass

news2024/12/23 11:04:07

1.Using Blender to create a single grass clump

首先blender与unity的坐标轴不同,z轴向上,不是y轴

通过小键盘的数字键可以快速切换视图,选中物体以后按下小键盘的点可以将物体聚焦于屏幕中心

首先我们创建一个平面,宽度为0.2m,然后切换到正交前视图,复制两个平面。shift+D可以复制面

接着将上下两个面旋转45°至中间面的中心。先按下R然后按下Y可以绕y轴旋转,然后按G键可以移动面

然后切换到正交顶视图(数字键7)

 

将两个复制的面分别向左向右旋转10.5°左右

最后加上材质和贴图以后的效果就是下面这样

然后就可以保存退出Blender了,后面我们在unity中批量产出这个grass

2. Using instancing to cover a surface with grass

首先就是定义草的类,包含了草的位置,摆动角度

 struct GrassClump
    {
        public Vector3 position;
        public float lean;
        public float noise;

        public GrassClump( Vector3 pos)
        {
            position.x = pos.x;
            position.y = pos.y;
            position.z = pos.z;
            lean = 0;
            noise = Random.Range(0.5f, 1);
            if (Random.value < 0.5f) noise = -noise;
        }
    }

接着还有全局的草的密度,大小,最大摆动角度

 [Range(0,1)]
    public float density = 0.8f;
    [Range(0.1f,3)]
    public float scale = 0.2f;
    [Range(10, 45)]
    public float maxLean = 25;

然后就是初始化草丛的位置信息,生成一个 ComputeBuffer 来存储这些位置数据,并通过计算着色器来模拟草丛的摆动效果。

获取附加的 MeshFilter 组件中的网格边界,bounds.extents 返回边界框的一半大小(每个轴的范围的一半)

MeshFilter mf = GetComponent<MeshFilter>();
Bounds bounds = mf.sharedMesh.bounds;
Vector3 clumps = bounds.extents;

使用对象的缩放值(transform.localScale)和一个密度因子来调整草丛的分布范围,主要是 x 和 z 轴 。并且计算草丛的总数量


        Vector3 vec = transform.localScale / 0.1f * density;
        clumps.x *= vec.x;
        clumps.z *= vec.z;

        int total = (int)clumps.x * (int)clumps.z;

获取计算着色器中的内核 LeanGrass,并计算每个线程组的大小。groupSize 是用于处理草丛的线程组数,而 count 则是实际生成的草丛总数 

kernelLeanGrass = shader.FindKernel("LeanGrass");
shader.GetKernelThreadGroupSizes(kernelLeanGrass, out threadGroupSize, out _, out _);
groupSize = Mathf.CeilToInt((float)total / (float)threadGroupSize);
int count = groupSize * (int)threadGroupSize;

随机生成 count 个草丛的 pos 位置。这个位置基于网格的边界和中心生成,使用 TransformPoint 将局部坐标转换为全局坐标 (世界坐标)

clumpsArray = new GrassClump[count];

for (int i = 0; i < count; i++)
{
    Vector3 pos = new Vector3(Random.value * bounds.extents.x * 2 - bounds.extents.x + bounds.center.x,
                              0,
                              Random.value * bounds.extents.z * 2 - bounds.extents.z + bounds.center.z);
    pos = transform.TransformPoint(pos);
    clumpsArray[i] = new GrassClump(pos);
}

创建了一个 ComputeBuffer 来存储所有的草丛位置信息,并将 clumpsArray 赋值到缓冲区中。 

clumpsBuffer = new ComputeBuffer(count, SIZE_GRASS_CLUMP);
clumpsBuffer.SetData(clumpsArray);

将缓冲区 clumpsBuffer 绑定到计算着色器的 clumpsBuffer 参数,并将草丛最大倾斜角度 maxLean 传递给着色器。 

shader.SetBuffer(kernelLeanGrass, "clumpsBuffer", clumpsBuffer);
shader.SetFloat("maxLean", maxLean * Mathf.PI / 180);
timeID = Shader.PropertyToID("time");

 通过 argsArray 设置绘制调用的参数(索引数量和实例数量),并使用 ComputeBuffer 类型为 IndirectArguments 创建一个缓冲区,用于 DrawMeshInstancedIndirect 函数的调用

  • argsArray[0] = mesh.GetIndexCount(0);

    • 这行代码获取的是 mesh 的索引数量,也就是用来渲染的几何体有多少个顶点索引。每个网格都有其顶点、法线、UV 等信息,而索引决定了如何连接这些顶点来形成三角形。
    • IndirectArguments 绘制时,第一个参数就是表示绘制网格时使用的顶点索引数量。
  • argsArray[1] = (uint)count;

    • count 是实例化对象的数量。通过 Graphics.DrawMeshInstancedIndirect 方法可以在一次绘制调用中实例化多个对象。
    • 这里第二个参数表示要绘制的实例化网格的数量
argsArray[0] = mesh.GetIndexCount(0);
argsArray[1] = (uint)count;
argsBuffer = new ComputeBuffer(1, 5 * sizeof(uint), ComputeBufferType.IndirectArguments);
argsBuffer.SetData(argsArray);

然后看一下我们的计算着色器

很简短,就是设置了个倾斜角度,方便后续在表面shader中进行旋转

[numthreads(THREADGROUPSIZE,1,1)]
void LeanGrass (uint3 id : SV_DispatchThreadID)
{
    GrassClump clump = clumpsBuffer[id.x];

    clump.lean = sin(time + clump.noise) * maxLean * clump.noise;

    clumpsBuffer[id.x] = clump;
}

接着继续编写表面着色器

首先是设置每个草丛的位置以及旋转平移矩阵

        void setup()
        {
            #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
                GrassClump clump = clumpsBuffer[unity_InstanceID];
                _Position = clump.position;
                _Matrix = create_matrix(clump.position, clump.lean);
            #endif
        }

然后是创建矩阵函数,这是一个绕z轴旋转的矩阵

  float4x4 create_matrix(float3 pos, float theta){
            float c = cos(theta);
            float s = sin(theta);
            return float4x4(
                c,-s, 0, pos.x,
                s, c, 0, pos.y,
                0, 0, 1, pos.z,
                0, 0, 0, 1
            );
        }

最后就是顶点函数的设置

首先乘上缩放系数,然后计算经过旋转和平移的顶点位置,接着计算只经过平移的位置,最后根据uv的y值来插值坐标,也就是高度越高,弯曲幅度越大

 void vert(inout appdata_full v, out Input data)
        {
            UNITY_INITIALIZE_OUTPUT(Input, data);

            #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
                v.vertex.xyz *= _Scale;
                float4 rotatedVertex = mul(_Matrix, v.vertex);
                v.vertex.xyz += _Position;
                v.vertex = lerp(v.vertex, rotatedVertex, v.texcoord.y);
            #endif
        }

最终效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2141078.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI替代插画师跟设计师?不用焦虑!

一个固定的工作流&#xff0c; 一个训练好的lora模型 输入一段提示词 二三十秒的时间&#xff0c;就能生成一张精致美观有韵味的中秋国风插画 这张不喜欢&#xff0c;改下提示词重新生成一张不一样的。还是二十几秒 同样的插画&#xff0c;你用手绘&#xff0c;从起稿到上…

大数据新视界 --大数据大厂之MongoDB与大数据:灵活文档数据库的应用场景

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【设计模式-外观】

这里写自定义目录标题 定义UML图角色作用代码使用场景 定义 为子系统中一组相关接口提供一致界面&#xff0c;定义一个高级接口&#xff0c;使得子系统更加容易使用。 UML图 角色作用 外观&#xff08;Facade&#xff09;角色&#xff1a;这是外观模式的核心&#xff0c;它知…

MongoDB的详细安装教程

6、MongoDB安装 6.1 为什么使用MongoDB 性能好大规模数据存储&#xff08;可拓展性&#xff09;可靠安全&#xff08;本地复制、自动故障转移&#xff09;方便存储复杂数据结构 6.2 下载安装 【1】下载地址&#xff0c;这里下载的是5.0版本的&#xff0c;否则配置环境变量之…

【电路笔记】-差分运算放大器

差分运算放大器 文章目录 差分运算放大器1、概述2、差分运算放大器表示2.1 差分模式2.2 减法器模式3、差分放大器示例3.1 相关电阻3.2 惠斯通桥3.3 光/温度检测4、仪表放大器5、总结1、概述 在之前的文章中,我们讨论了反相运算放大器和同相运算放大器,我们考虑了在运算放大器…

revisiting拉普拉斯模板

二维向量的二阶微分是Hessian矩阵&#xff0c;拉普拉斯算子是将两个独立的二阶微分求和&#xff0c;对二阶微分的近似。 我不认同冈萨雷斯的8邻域拉普拉斯模板。 MATLAB图像处理工具箱中fspecial函数’laplacian’参数给的拉普拉斯模板&#xff1a; 对于数字滤波器&#xff…

中秋前夕-我居然使用技术来鞭策兄弟

中秋前夕-我居然使用技术来鞭策兄弟 前言 最近在带领一些小伙伴在完成功能&#xff0c;因为人数不少&#xff0c;那么我们如何统计大家有没有摸鱼偷懒呢&#xff1f; 聪明的朋友们可以想到&#xff0c;利用git的提交记录统计。 因为git提交时&#xff0c;会给我们带上一些关…

高德2.0 多边形覆盖物无法选中编辑

多边形覆盖物无法选中编辑。先检查一下数据的类型得是<number[]>,里面是字符串的虽然显示没问题&#xff0c;但是不能选中编辑。 &#xff08;在项目中排查了加载时机&#xff0c;事件监听…等等种种原因&#xff0c;就是没发现问题。突然想到可能是数据就有问题&#xf…

ROS组合导航笔记:融合传感器数据

使用机器人定位包&#xff08;robot_localization package&#xff09;来合并来自不同传感器的数据&#xff0c;以改进机器人定位时的姿态估计。 基本概念 在现实生活中操作机器人时&#xff0c;有时我们需要处理不够准确的传感器数据。如果我们想要实现机器人的高精度定位&am…

初探全同态加密1 —— FHE的定义与历史回顾

文章目录 一、加密体系1、什么是加密体系2、加密体系的属性 Properties 二、同态加密&#xff1a;偶然的特殊性质三、同态加密体系的分类四、部分同态加密 Partially Homomorphic Encryption1、加法同态加密算法 —— ElGamal 加密算法1.1、ElGamal 的大致步骤1.2、ElGamal 的加…

vue3+vite项目中使用阿里图标库(svg)图标

前端项目中有很多地方会用到小图标&#xff0c;阿里的 iconfont 是一个不错的选择&#xff0c;同时&#xff0c; 它上面的 svg 矢量图标占用资源更少加载更快是一个不错的选择&#xff0c; 下面我们就来说一说&#xff0c;项目中如何来使用 svg 图标 安装插件 vite-plugin-svg…

RP2040 C SDK SysTick滴答定时器功能使用

RP2040 C SDK SysTick滴答定时器功能使用 ✨更好的阅读体验请移步到&#xff1a;飞书-云文档&#xff1a;https://u1etqmuwl9z.feishu.cn/wiki/VkoHwPGqHierOEkY651cZvaOntg?fromfrom_copylink RP2040的SysTick滴答定时器为24位的&#xff0c;计数方式为倒计时&#xff0c;扩展…

基于对数变换的图像美白增强,Matlab实现

博主简介&#xff1a;matlab图像处理&#xff08;QQ:3249726188&#xff09; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于对数变换的图像美白增强&#xff0c;用matlab实现。 一、案例背景和算法介绍 这次案例是美白算法&…

Stable Diffusion Web UI基础插件推荐

通过前面知识的介绍&#xff0c;我们对使用 Web UI 进行绘画有了基本了解&#xff0c;在平时我们使用中&#xff0c;有很多好用的插件&#xff0c;通过这些插件我们创作能够事半功倍&#xff0c;下面我就推荐一下在平时经常使用到的插件&#xff0c;希望这篇文章能够帮助大家更…

MelosBoom:解锁数据价值的新纪元

在当今的数字时代&#xff0c;数据被誉为“新的石油”&#xff0c;但用户在传统的Web2环境中&#xff0c;往往无法真正享受到自己贡献数据的价值。大型互联网公司通过集中化的系统和算法&#xff0c;垄断了数据的使用权&#xff0c;并从中获取巨大的商业利益&#xff0c;而数据…

浏览器页面被禁用 F12(dev tools)

解决办法1: 使用浏览器设置栏, 打开开发者工具, 设置->更多工具->开发者工具 解决办法2: 命令行启动浏览器, 携带参数, 强制打开所有页面的 devtools chrome.exe –auto-open-devtools-for-tabs –user-data-dir./

时序必读论文10|ICLR23 Crossformer 跨维度依赖的多变量时序预测模型

论文标题&#xff1a;iCROSSFORMER : TRANSFORMER UTILIZING CROSS DIMENSION DEPENDENCY FOR MULTIVARIATE TIME SERIES FORECASTING 开源代码&#xff1a;https://github.com/Thinklab-SJTU/Crossformer 前言 Crossformer是一篇非常典型的在transformer基础上魔改注意力机…

k8s使用本地docker私服启动自制的flink集群

目标&#xff1a;使用本地flink环境自制flink镜像包上传到本地的私服&#xff0c;然后k8s使用本地的私服拉取镜像启动Flink集群 1、将本地的flink软件包打包成Docker镜像 从官网下载flink-1.13.6的安装包&#xff0c;修改其中的flink-conf.yaml&#xff0c;修改下面几项配置 …

鸿蒙开发之ArkTS 基础九 枚举类型

枚举把变量固定在特定的范围内 枚举的语法&#xff1a; enum 枚举名字 { 常量1 值1, 常量1 值1, 常量1 值1, ... } 定义具体如下: 使用具体如下&#xff1a;

【无人机设计与控制】四旋翼无人机俯仰姿态保持模糊PID控制(带说明报告)

摘要 为了克服常规PID控制方法在无人机俯仰姿态控制中的不足&#xff0c;本研究设计了一种基于模糊自适应PID控制的控制律。通过引入模糊控制器&#xff0c;实现了对输入输出论域的优化选择&#xff0c;同时解决了模糊规则数量与控制精度之间的矛盾。仿真结果表明&#xff0c;…