【模块】物体放置系统设计

instancing system

描述:

结构:

  • List InstanceObject 指定为场景的container.
  • Monitor 显示器,显示生成的object,使用graphic.drawmeshinstance;
  • 工具-笔刷,在editorview中创建instances;

设计原则:

  • 显示器运行在prefab中,prefab装载着instance Data.

  • 显示器继承monoBehaviuor

  • 控制显示器object的位置可以影响所有instance Data的显示位置.

  • 编辑器显示器:运行在编辑器工具中

  • Runtime显示器:Mono物体中

  • 数据应该都要存到Constant Buffer中.这样在shader中可以做tint的功能.

  • GameObject能够控制所有instance的transform.

  • 需要用到一个command buffer Draw所有Instances

  • command buffer装载所有的数据.

  • InstanceShader中接收并处理cbuffer的数据.

  • 注册到RenderingSystem中(最后再接入)

  • Instance中需要一个个对应的列表材质进行setbuffer.而不是设置全局buffer.

  • shader中需要编写instanced structure接收buffer的数据.

  • bufferInfo中的结构尽量简化.

  • 重新定义序列化的文件结构.

  • transform矩阵定义重构.

  • view Type 重构.

  • 显示层级Isolated 单一化显示

  • 最后读取静态序列化数据

  • 完成吸色器的状态

测试到的问题:

  • 最大数组不能超过1024,超过时可以开一个新的data来避免1024溢出

  • 待完善,笔刷距离patinting。(高优先级)

  • 刷出来物体matrix的法线不匹配地形方向。

  • editor状态下没有显示物体.(高优先级)

  • 笔刷状态卡顿比较严重(但是在游戏运行是卡顿可以解决)

  • 笔刷刷的颜色需要对其进行伽马矫正(已经在shader中完成gamma矫正)

  • 拾色器的颜色拾取出来颜色变暗.

  • Display中显示的buffer颜色数据不一致.

  • buffer 数据不一致.

配置项

  • 渲染物体
  • 渲染材质
  • 统一覆盖渲染材质
  • 可控transform
  • 分组(备用)

基本代码结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class InstancingData : scriptableObject
{
SceneInstancingData data;
}
class SceneInstancingData : ScriptableObject
{
Scene scene;
Material overriderMaterial;
InstanceObject[] objects;
}
class Monitor
{
InstancingData sysdata;

void Display();
void Clear();
void Refresh();
}

实例对象的结构

  • 源模型
  • 对应渲染材质
  • 位置
  • 旋转
  • 大小
  • 法线
  • 颜色
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct InstanceObject{
Mesh origin;
Material material;
Color objectColor;
Matrix4x4 matrix;

float3 position;
float3 rotation;
float3 localScale;

float3 up;
float3 right;
float3 forward
};
1
2
3
4
5
6
public struct InstanceBuffer{
public float4 _cColour;
public float3 _cPosition;
public float4 _cRotation;
public float3 _cLocalScale;
}
1
2
3
4
5
6
CBUFFER_START(_CBufferInstance)
float3 _cPosition;
float4 _cRotation;
float3 _cLocalScale;
float4 _cColour;
CBUFFER_END

笔刷 EditorTool

结构

  • 笔刷形状

  • 笔刷状态

  • 有配置文件可以配置笔刷的详细设置。

  • 显示_handles

  • 设置当前的instanceData层级

  • 编辑器中可视化数据

  • 切换自动显示当前显示的数据

配置项

  • 工具快捷键
    • 快捷键B呼出笔刷
    • G lookAt笔刷位置
    • S 吸取指定位置的屏幕颜色
    • 调节笔刷散布噪声级别

工具状态

  • 工具未初始化状态
    • 显示未初始化的提示
  • 橡皮擦模式
    • shift 切换到橡皮擦模式
    • 松开shift 切换回笔刷模式
    • shift + 左键清理笔刷范围内的数据
  • 笔刷模式热键B
    • 左键放置数据
  • 调整大小模式
    • f进入调整模式
    • 鼠标左右移动调整笔刷大小
    • 鼠标上下移动调整笔刷射线高度
    • 按住shift 调整精度变小
    • 鼠标左键确定调整大小
    • 鼠标右键取消并推出该模式
  • 调整密度模式
    • shift + f 进入调整模式
    • 鼠标左键确定调整大小
    • 鼠标右键取消并退出该模式
    • 最大密度为64位
  • 调整噪声权重模式
    • D 进入调整模式
    • 鼠标左键确定调整大小
    • 右键取消并退出该模式
    • 权重最大为1
  • 调整噪声强度模式
    • shift + D进入该模式
    • 鼠标左键确定调整大小
    • 右键取消并退出该模式
    • 噪声强度最大为5
  • 调整笔刷物体大小模式
    • shift + S进入模式
    • 鼠标左键确定调整大小
    • 右键取消并退出该模式
    • 大小最大为5
  • 调整笔刷颜色
    • s直接吸取场景渲染中的颜色
    • 或者出现一个圆盘,让用户自己调整颜色
  • 按住s键进入拾色器
    • 松开s键执行吸色功能
    • 吸色模式旁边会有当前吸取的颜色提示

其他配置

  • 生成物体可配置
  • 散布范围可配置
  • 散布密度上限可配置
  • 快捷键配置
  • 笔刷形状
  • 噪声形状
  • instance数据篡改

功能

  • 投射射线获取交点,在交点中根据交点平面的法线重建一个圆盘,在此圆盘上按照配置的物体密度重新投射射线检测交点。

  • 如果在检测圆盘中已存在数据,检测圆盘中密度的数量,不超过最大密度进行放置。

  • 编辑器中,打开笔刷后,检查场景中含有对应mono的物体,如果没有,则询问是否需要创建。

  • 当存在mono物体,显示所有读取到的实例物体,编辑时,会按照顺序创建一个列表,并且可以使用快捷键切换到下一个instance data中进行编辑,每次切换的数据都会有提示。

  • 每次成功刷上,记录当前位置。当下一次刷的时候对比上一次位置的距离,如果没超过阈值,则不执行笔刷刷数据的功能。反之则执行。

  • 笔刷预览显示物体位置大小形状网格,并且有预览材质和预览shader.

  • 第一次启动和使用都有提示界面出现进行配置.

  • 如果没有加载上实例数据,则弹窗询问是否需要创建数据,确认后数据会保存在resources/instance目录里面.

  • 笔刷绘制修改器,需要旋转、颜色、大小等属性随机,可以实现一个修改器并且添加内容即可.

  • 随机颜色的修改器逻辑,需要参考到色卡和随机种等算法.

需求

  • 基于Editor 窗口的笔刷,在视窗中投射球体到场景中,放置物体。

  • 用graphic.drawmesh显示已经放置的物体

  • 判断球体中放置的物体的密度,物体密度会有上限。

  • Editor中绘制笔刷预览笔刷位置(handles)

  • 可以吸附物体碰撞体进行放置物体

  • 笔刷功能时屏蔽Unity的鼠标事件(指定事件)

  • 拦截默认鼠标事件Event

  • 预览位置按照距离着色

  • 按下F键视角会移动到鼠标附近的位置LOOKAT

  • 可通过笔刷删除已经布置的物体

  • 按下翻页键可以切换当前的层级,instance”层级”.也就是instance scriptableobject

  • 当层级里的instanceObject超过了1024个对象,那么则下次刷的时候自动寻找下一个没有满1024的层级。

  • 当第一层已经达到1024个实例数据,需要策略切换到下一层再绘制.

Bonus

  • 十六进制色彩转换
  • 快捷键配置
  • 配置面板GUI自定义
  • S 吸取指定位置的屏幕颜色
  • 可以undo上一次刷的记录
  • 可以把整个系统做成package
  • 使整个工具与unity更加统一

笔记

  • 根据法线变换整体的顶点坐标,矩阵变换,求法线的变换矩阵然后转换。

  • 每个场景中创建一个储存数据的文件,该文件路径统一放在Resources,而且文件名与场景文件名字相同。如果该场景没有实例文件,调用笔刷后会提示是否要创建实例文件,如果是,则创建一个新的实例文件。

  • 在游戏加载时,实际会创建一个实例,该实例用于显示所有储存在数据中的“物体”,用作数据的可视化。如果该场景没有实例文件,则进入待机模式,当场景发生变化后,又重新检测一遍是否有实例对象。

  • overlays Menu Custom 将层级的放在空格键可打开的overlay menu中,提高使用效率.

  • 编辑器中实例数据可视化。

  • 当缩小笔刷大小的时候,密度也随之上升。算是一个显而易见的bug.

  • 将在编辑器中读取文件的静态方法抽象出来.做成一个通用的方法.

  • handles显示与模型匹配度较低,笔刷使用时感知力度较小.

  • 刷出来的物体大小没有变化,旋转没有变换。

  • 层级应该移动到overlays页面中,可以在overlays中对对应层级隐藏

  • 笔刷稳定性运行检测再0617日完成.


  • 重点,修改颜色变化的功能.让其笔刷数据的颜色会随着一定规律变化,不太单调.
  • cbuffer显示后的数据和显示结果不一致.待修复
  • 单一显示和整体显示的功能.
  • 完善mono状态下的displayer
  • 引导功能的完善.
  • 说明手册和功能列表.使用文档.

施工compute buffer

  • 一个float 占4个字节
  • 确定的结构
1
2
3
4
5
6
7
struct InstanceInfo
{
float3 position;
float4 rotation;
float3 localscale;
float4 color;
};

(3+4+3+4)*4

1
2
3
4
5
6
7
8
9
重要参数
uint args []
{
mesh.getindexcount(submeshindex),
instanceCount,
mesh.getindexstart(submeshindex),
mesh.getbasevertex(submeshindex),
0
};
  • indirect Arguments:

  • AppendsturctBuffer;

  • drawMeshInstance会分割批次

  • DrawMeshInstanceIndirect不会分割批次,保证了每个instanceId的顺序.

  • DMII: DrawMeshInstanceIndirect

  • 每次一层layer设置新的offset;

  • 如果使用sturcturedbuffer.一个material 只会有一个buffer数据被设置.并不会叠加数据.

  • DMII 中一个材质就相当于一个draw batch被传输.

  • 重写文档.

  • 使用每个id的值去设置顶部颜色产生有不一样的variation