Merge remote-tracking branch 'origin/master'

master
ArgonarioD 2022-11-23 11:11:32 +08:00
commit 03cd768f21
5 changed files with 456 additions and 47 deletions

271
1st_encode/example.json Normal file
View File

@ -0,0 +1,271 @@
{
"height": 1080,
"width": 1080,
"elements": [
{
"type": "path",
"data": {
"operations": [
{
"type": "line",
"data": {
"target": {
"x": 15,
"y": 20
}
}
},
{
"type": "cubic",
"data": {
"target": {
"x": 18,
"y": 21
},
"control": {
"start": {
"x": 17,
"y": 22
},
"end": {
"x": 20,
"y": 23
}
}
}
},
{
"type": "cubic-smooth",
"data": {
"target": {
"x": 18,
"y": 21
},
"control": {
"x": 18,
"y": 21
}
}
},
{
"type": "quadratic",
"data": {
"target": {
"x": 18,
"y": 21
},
"control": {
"x": 18,
"y": 21
}
}
},
{
"type": "quadratic-smooth",
"data": {
"target": {
"x": 18,
"y": 21
}
}
},
{
"type": "arc",
"data": {
"center": {
"x": 18,
"y": 21
},
"x-axis": 40,
"y-axis": 50,
"angle": 6000
}
},
{
"type": "zeal"
}
]
}
},
{
"type": "polygon",
"data": {
"points": [
{
"x": 10,
"y": 20
},
{
"x": 10,
"y": 20
},
{
"x": 10,
"y": 20
},
{
"x": 10,
"y": 20
},
{
"x": 10,
"y": 20
}
]
}
},
{
"type": "round",
"data": {
"x-axis":30,
"y-axis":40,
"angle": 6000
}
},
{
"type": "group",
"group-layer": [1,2]
}
],
"layers": [
{
"element": 1,
"position": {
"type":"absolute",
"x": 18,
"y": 21
},
"level": 1,
"attached": [
{
"type": "rotate",
"data": {
"clockwise": false,
"angle": 6000
}
},
{
"type": "zoom",
"data": {
"x-zoom": 1.0,
"y-zoom": 1.2
}
},
{
"type": "flip"
},
{
"type": "shadow",
"data": {}
}
]
},
{
"element": 2,
"position": {
"type":"offset",
"x": 18,
"y": 21
},
"level": 1,
"attached": []
}
],
{
"element-group": false,
"target": 2,
"times": 5,
"operations": [
{
"type": "move",
"data": {
"dx": 5,
"dy": 6
}
},
{
"type": "rotate",
"data": {
"center": {
"dx": 0,
"dy": 0
},
"dθ": 6000
}
},
{
"type": "zoom",
"data": {
"zoom": 1.5
}
},
{
"type": "flip"
}
]
},
{
"element-group": true,
"target": 5,
"times": 5,
"children": [
[
{
"type": "move",
"data": {
"dx": 5,
"dy": 6
}
},
{
"type": "rotate",
"data": {
"center": {
"dx": 0,
"dy": 0
},
"dθ": 6000
}
},
{
"type": "zoom",
"data": {
"zoom": 1.5
}
},
{
"type": "flip"
}
],
[
{
"type": "move",
"data": {
"dx": 5,
"dy": 6
}
},
{
"type": "rotate",
"data": {
"center": {
"dx": 0,
"dy": 0
},
"dθ": 6000
}
},
{
"type": "zoom",
"data": {
"zoom": 1.5
}
},
{
"type": "flip"
}
]
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,113 +1,156 @@
二级编码大体结构及渲染流程如下:
目标实现分辨率无关的、具有较高随机访问性能、相对节省显存的矢量图渲染使得其使用方式与传统texture类似便于在任意形状mesh中应用矢量图贴图。
首先分为图元和索引两大块,图元内坐标范围为-1到1一张图中可能有多个相同的图元这些图元只需在图元缓存中保存一次为了记录图元的位置和变换信息对图元建立一个索引结构同时为了方便求交使用BVH层次包围盒结构BVH每个结点包含leftChildrightChild和bound即包围盒坐标BVH的最后一个结点的leftChild为图元索引加上BVH数组长度rightChild特殊处理为逆时针旋转角度。
# 渲染流程
图元由轮廓包围的封闭图形和线条构成轮廓可以由直线、二阶贝塞尔曲线和三阶贝塞尔曲线组成支持任意数量轮廓围成的图形的渲染轮廓围成的图形中不能含有空腔对于一个复杂的含有许多轮廓的封闭图形而言应当尽可能将其分割成数个由三段轮廓线包围的广义三角形并对这些广义三角形以及不构成图形的线条建立BVH索引图元内BVH索引存储在外部BVH数组后。
## 总体流程
着色器接收的5个buffer
1. 普通mesh将基础色、世界坐标、法线、金属度和粗糙度、彩绘编号(0)输出到gbuffer彩绘mesh将世界坐标、法线、彩绘编号、彩绘纹理坐标输出到gbuffer
2. compute shader根据彩绘编号、彩绘纹理坐标gbuffer来计算彩绘纹理更新基础色、金属度和粗糙度gbuffer
3. 根据基础色、世界坐标、法线、金属度和粗糙度gbuffer以及光源计算光照。
![image-20220809141906110](2st_encode.assets/gbuffers.png)
后续计划实现shadow mapping。
## 计算彩绘纹理流程
彩绘由许多不同的图元组成一个图元可以由一系列贝塞尔曲线和贝塞尔曲线封闭的图形组成同一图元可能在彩绘中反复出现故计算彩绘纹理的过程就是根据矢量图纹理坐标计算像素点对应哪个图元的哪个部位得到颜色和材质相当于在二维平面中做光线追踪。为了加速这一过程将图元中的一个由数条曲线围成的封闭图形拆成多个由三条曲线围成的封闭图形对每个图形和每段不构成封闭图形的贝塞尔曲线建立BVH层次包围盒加速结构再对每个图元建立BVH。由此计算每个像素点的过程即为遍历两个BVH找到像素点对应的图形或曲线对于图形判断点是否在图形内对于线条判断点到曲线的距离是否小于一定值然后根据指定的样式计算其颜色和材质。
# 二级编码结构
首先分为图元和索引两大块,图元内坐标范围为-1到1一张图中可能有多个相同的图元这些图元只需在图元缓存中保存一次为了记录图元的位置和变换信息对图元建立一个索引结构同时为了方便求交使用BVH层次包围盒结构BVH每个结点包含bvhChildren每个结点的两个儿子x分量为左儿子y分量为右儿子和bound包围盒坐标QVector4D左下角x左下角y右上角x右上角yBVH的最后一个结点的左儿子为图元索引加上BVH数组长度右儿子特殊处理为图元zIndex和逆时针旋转角度。测试得到在重叠较少且不处理叶子结点内部的情况下得到当叶子结点数量达到30000时在我的笔记本NVIDIA GeForce GTX 1650 Ti上以1898x995分辨率渲染能维持32帧左右。
图元由轮廓包围的封闭图形和线条构成封闭图形中允许有空洞轮廓可以由直线、二阶贝塞尔曲线和三阶贝塞尔曲线组成。实验遍历一个图形的所有轮廓线判断是否有交点进而根据交点数判断点是否在图形内部的方法得到当轮廓数量达到600时在我的笔记本上以1898x995分辨率渲染只能维持13帧考虑将图形分割并建立加速结构。
使用3种操作来绘制任意图元
1. 对一块矩形区域填充一次
2. 对一块矩形区域擦除一次
3. 一块矩形区域中包含一条曲线该曲线在矩形区域中每一个x和y都一一对应且曲线的端点落在矩形端点在矩形区域中对曲线一侧的区域填充一次
对于每个像素维护一个int变量填充时对其+1擦除时对其-1最终该变量的取值应为0或11即表示像素点在图形内部。
对于任意图形,均可使用一系列上述三种操作来绘制,生成这些操作的方法有待验证。
一开始我们考虑将图形做三角划分再对划出的三角形建立BVH树下面为按该方式制定的二级编码即缓存结构
![image-20220817102607509](2st_encode.assets/triangulation.png)
compute shader接收的6个buffer
```glsl
layout(std430, binding = 1) buffer bvhBuffer
{
uint bvhLength;
uvec2 bvhChildren[];
};
layout(std430, binding = 2) buffer bvhBoundBuffer
{
vec4 bvhBound[];
};
layout(std430, binding = 3) buffer elementOffsetBuffer
layout(std430, binding = 1) buffer paintingOffsetBuffer
{
/**********************
** @x elementBvhRoot
** @y elementBvhLength
** @z pointsOffset
** @w linesOffset
** @x paintingBvhRoot
** @y paintingBvhLength
**********************/
uvec4 elementOffsets[];
uvec2 paintingOffsets[];
};
layout(std430, binding = 4) buffer elementIndexBuffer
layout(std430, binding = 2) buffer bvhBuffer
{
uint elementIndex[]; //线和面
uvec2 bvhChildren[];
};
layout(std430, binding = 5) buffer elementDataBuffer
layout(std430, binding = 3) buffer bvhBoundBuffer
{
float elementData[]; //点和Style
vec4 bvhBound[];
};
layout(std430, binding = 4) buffer elementOffsetBuffer
{
/**********************
** @[0] elementBvhRoot
** @[1] elementBvhLength
** @[2] pointsOffset
** @[3] linesOffset
** @[4] contoursOffset
**********************/
uint elementOffset[][5];
};
layout(std430, binding = 5) buffer elementIndexBuffer
{
uint elementIndexs[]; //线和面
};
layout(std430, binding = 6) buffer elementDataBuffer
{
float elementData[]; //点和Style
};
```
bvhLength为外部索引数组长度bvhChildren为每个结点的两个儿子x分量为左儿子y分量为右儿子。
传入示例:
提供工具类合并多张彩绘的buffer一张彩绘的参数示例
```c++
GLuint bvhChildren[] = {7/*rootBVH长度*/,0/*与显存对齐*/,
std::vector<GLuint> bvhChildren = {
//root
1,2,
1,2,
3,4, 5,6,
7,0, 7,30./360* 4294967296 /*右儿子用来表示旋转角度*/, 8,0, 7,0,
7,0, 7,GLuint(30. / 360 * 65536 + 1 * 65536) /*右儿子用来表示旋转角度和zIndex*/, 8,0, 7,0,
//elememt0
1,2,
5+28/*contour索引由于contour不定长这里需要给到contour在elementIndex中位置*/,5+12/*style索引在elementData中位置*/, 3,4,
5+36,5+12, 5+32,5+12,
5 + 0/*contour索引*/,5 + 12/*style索引在elementData中位置*/, 3,4,
5 + 2,5 + 12, 5 + 1,5 + 12,
//elememt1
1+0/*line索引element中第几条*/,1 + 25
1 + 0/*line索引element中第几条*/,1 + 25
};
QVector4D bvhBound[] = {
std::vector<QVector4D> bvhBounds = {
//root
QVector4D(-1,-1,1,1),
QVector4D(-0.9,-0.9,-0.1,0.9), QVector4D(0.1, -0.9,0.9,0.9),
QVector4D(-0.9,-0.9,-0.1,0.9), QVector4D(0.1, -0.9,0.9,0.9),
QVector4D(-0.8,-0.8,-0.2,-0.1), QVector4D(-0.7,0.2,-0.2,0.7), QVector4D(0.2,-0.8,0.8,-0.1), QVector4D(0.2,0.1,0.8,0.8),
//elememt0
QVector4D(-1,-1,1,1),
QVector4D(-1,-0.5,1,1), QVector4D(-1,-1,1,0.5),
QVector4D(-1,-1,1,-0.5), QVector4D(-1,-0.5,1,0.5),
//elememt1
QVector4D(-1,0,1,1),
//elememt1
QVector4D(-1,0,1,1),
};
GLuint elementOffset[] = {
std::vector<GLuint> elementOffset = {
//element0
7, //elementBvhRoot
5, //elementBvhLength
0, //pointsOffset
0, //linesOffset
28, //contoursOffset
//element1
12, //elementBvhRoot
1, //elementBvhLength
19, //pointsOffset
40, //linesOffset
44 //contoursOffset
};
GLuint elementIndex[] = {
std::vector<GLuint> elementIndex = {
//element0
//lines, 全部当作三阶贝塞尔, 每条线四个点索引
0,2,2,4,
4,2,2,0,
0,0,1,1,
1,1,4,4,
1,1,5,5,
4,4,5,5,
1,1,3,3,
3,3,5,5,
//contours, 第一个元素指明轮廓段数后面为lines索引
3, 0,1,2,
3, 2,3,4,
3, 3,5,6,
//contours, 每个轮廓三个线索引,若轮廓由两条线构成则第一第二元素相同
0,1,2,
2,3,4,
3,5,6,
//element2
//lines
0,1,2
};
GLfloat elementData[] = {
std::vector<GLfloat> elementData = {
//element0
//points
-1,0.5, -1,-0.5, 0,1, 0,-1, 1,0.5, 1,-0.5,
//fillStyle
//fill
0,
0,
//fillType
0, //单色
//fillColorMetallicRoughness
@ -130,3 +173,89 @@ bvhLength为外部索引数组长度bvhChildren为每个结点的两个儿子
};
```
fillStyle格式
第一个元素0代表填充封闭图形
第二个元素:填充方式
0单色
1按直线渐变
2按点渐变
后续元素:
对于单色5个元素分别为RGBMetallicRoughness
对于按直线渐变:起点坐标,终点坐标,段数,[{在直线中相对位置,颜色材质}, ...]
对于按点渐变:点数,[{坐标,权重,颜色材质}, ...]
strokeStyle格式
第一个元素1代表画线
第二个元素:线宽
第三个元素0圆角
1直角
2起点圆角终点直角
3起点直角终点圆角
第四个元素:线内填充方式
0单色
1按直线渐变
2按点渐变
3按当前线条渐变
第五元素:线外描边类型
0不描边
1双侧描边
2左侧描边
3右侧描边
第六个元素:线外描边宽度
第七个元素:线外描边方式
0单色
1分层设色
2渐变
后续元素:
线内填充数据:
对于单色5个元素分别为RGBMetallicRoughness
对于按直线渐变:起点坐标,终点坐标,段数,[{在直线中相对位置,权重,颜色材质}, ...]
对于按点渐变:点数,[{坐标,权重,颜色材质}, ...]
对于按当前线条渐变:段数,[{在线条中相对位置,权重,颜色材质}, ...]
线外描边数据:
对于单色5个元素分别为RGBMetallicRoughness
对于分层设色:层数,[{相对宽度,颜色材质}, ...]
对于渐变:层数,[{相对位置由里到外0~1权重颜色材质}, ...]

View File

@ -1,4 +1,13 @@
# 总体方案
一级编码(文件)为一张彩绘的最简表示,支持图层嵌套、迭代函数系统等操作;
二级编码缓存数个SSBO为实时渲染时所需的数据只接收图元及其位置变换信息和加速结构
读取一级编码后,须将所有嵌套和迭代解开,得到一系列组成图案的最原始的部件即图元及其位置变换,并对图元和图元内部都建立加速结构,处理得到二级编码。
# ArchitectureColoredPainting 编码方案
```
└─1st_encode 第一层编码
│ byte.md 二进制字节码编码方案