实现解析svg path

dev-VirtualTexture
wuyize 2022-10-07 00:01:19 +08:00
parent e849479236
commit 4f9611c385
14 changed files with 149 additions and 61 deletions

View File

@ -58,6 +58,16 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
<ClCompile> <ClCompile>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
@ -97,6 +107,7 @@
<ClCompile Include="RendererWidget.cpp" /> <ClCompile Include="RendererWidget.cpp" />
<ClCompile Include="ShortCutTree.cpp" /> <ClCompile Include="ShortCutTree.cpp" />
<ClCompile Include="StraightLine.cpp" /> <ClCompile Include="StraightLine.cpp" />
<ClCompile Include="SvgParser.cpp" />
<QtRcc Include="MainWindow.qrc" /> <QtRcc Include="MainWindow.qrc" />
<QtUic Include="MainWindow.ui" /> <QtUic Include="MainWindow.ui" />
<QtMoc Include="MainWindow.h" /> <QtMoc Include="MainWindow.h" />
@ -137,6 +148,7 @@
<ClInclude Include="PaintingMesh.h" /> <ClInclude Include="PaintingMesh.h" />
<ClInclude Include="ShortCutTree.h" /> <ClInclude Include="ShortCutTree.h" />
<ClInclude Include="StraightLine.h" /> <ClInclude Include="StraightLine.h" />
<ClInclude Include="SvgParser.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')"> <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">

View File

@ -79,6 +79,9 @@
<ClCompile Include="StraightLine.cpp"> <ClCompile Include="StraightLine.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="SvgParser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtMoc Include="RendererWidget.h"> <QtMoc Include="RendererWidget.h">
@ -172,5 +175,8 @@
<ClInclude Include="StraightLine.h"> <ClInclude Include="StraightLine.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="SvgParser.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -10,7 +10,7 @@
#include <vector> #include <vector>
#include <cmath> #include <cmath>
using std::tr1::shared_ptr; using std::shared_ptr;
struct BvhTreeData { struct BvhTreeData {
QVector4D bound; QVector4D bound;
@ -59,7 +59,7 @@ struct BvhNode {
~BvhNode() {} ~BvhNode() {}
}; };
typedef std::tr1::shared_ptr<BvhNode> BvhPtr; typedef std::shared_ptr<BvhNode> BvhPtr;
class BvhTree class BvhTree
{ {

View File

@ -8,11 +8,11 @@ float CubicBezier::getLineValueByT(float t, bool isY) {
return pt * pt * pt * p[0] + 3 * t * pt * pt * p[1] + 3 * t * t * pt * p[2] + t * t * t * p[3]; return pt * pt * pt * p[0] + 3 * t * pt * pt * p[1] + 3 * t * t * pt * p[2] + t * t * t * p[3];
} }
point CubicBezier::getPointByT(point a, point b, float t) { Point CubicBezier::getPointByT(Point a, Point b, float t) {
return { a.x * (1 - t) + b.x * t, a.y * (1 - t) + b.y * t }; return { a.x * (1 - t) + b.x * t, a.y * (1 - t) + b.y * t };
} }
point CubicBezier::calculateControlPoint(point a, point b) { Point CubicBezier::calculateControlPoint(Point a, Point b) {
return { return {
a.x + 2 * (b.x - a.x) / 3, a.x + 2 * (b.x - a.x) / 3,
a.y + 2 * (b.y - a.y) / 3 a.y + 2 * (b.y - a.y) / 3
@ -47,7 +47,7 @@ void CubicBezier::findPointsOfDivison(vector<float> &p, vector<float>& res) {
void CubicBezier::transformToCubic() { void CubicBezier::transformToCubic() {
if (siz == 4) return; if (siz == 4) return;
point p[3] = { Point p[3] = {
getPointByIndex(0), getPointByIndex(0),
getPointByIndex(1), getPointByIndex(1),
getPointByIndex(2) getPointByIndex(2)
@ -61,10 +61,10 @@ void CubicBezier::transformToCubic() {
void CubicBezier::splitBezierCubic(float t, vector<LinePtr>& res) { void CubicBezier::splitBezierCubic(float t, vector<LinePtr>& res) {
LinePtr Lf(new CubicBezier()); LinePtr Lf(new CubicBezier());
float pt = 1 - t; float pt = 1 - t;
point pointE = { getLineValueByT(t, false), getLineValueByT(t, true) }; Point pointE = { getLineValueByT(t, false), getLineValueByT(t, true) };
point pointF = getPointByT(getPointByIndex(0), getPointByIndex(1), t); Point pointF = getPointByT(getPointByIndex(0), getPointByIndex(1), t);
point pointG = getPointByT(getPointByIndex(1), getPointByIndex(2), t); Point pointG = getPointByT(getPointByIndex(1), getPointByIndex(2), t);
point pointH = getPointByT(getPointByIndex(2), getPointByIndex(3), t); Point pointH = getPointByT(getPointByIndex(2), getPointByIndex(3), t);
Lf->push_back(getPointByIndex(0)); Lf->push_back(getPointByIndex(0));
Lf->push_back(pointF); Lf->push_back(pointF);
Lf->push_back(getPointByT(pointF, pointG, t)); Lf->push_back(getPointByT(pointF, pointG, t));

View File

@ -6,8 +6,8 @@ class CubicBezier : public Line
{ {
using Line::Line; using Line::Line;
private: private:
static point getPointByT(point a, point b, float t); static Point getPointByT(Point a, Point b, float t);
static point calculateControlPoint(point a, point b); static Point calculateControlPoint(Point a, Point b);
static void findPointsOfDivison(vector<float> &p, vector<float>& res); static void findPointsOfDivison(vector<float> &p, vector<float>& res);
void splitBezierCubic(float t, vector<LinePtr>& res); void splitBezierCubic(float t, vector<LinePtr>& res);
public: public:

View File

@ -1,8 +1,8 @@
#include "Line.h" #include "Line.h"
Line::Line(vector<point> Vp) { Line::Line(vector<Point> Vp) {
siz = Vp.size(); siz = Vp.size();
for (point now : Vp) { for (Point now : Vp) {
vX.push_back(now.x); vX.push_back(now.x);
vY.push_back(now.y); vY.push_back(now.y);
} }
@ -12,23 +12,23 @@ int Line::size() {
return siz; return siz;
} }
vector<point> Line::toPointVector() const { vector<Point> Line::toPointVector() const {
vector<point> vL; vector<Point> vL;
for (int i = 0; i < siz; i++) { for (int i = 0; i < siz; i++) {
vL.push_back({vX[i], vY[i]}); vL.push_back({vX[i], vY[i]});
} }
return vL; return vL;
} }
point Line::operator[](int index) const { Point Line::operator[](int index) const {
return { vX[index], vY[index] }; return { vX[index], vY[index] };
} }
point Line::getPointByIndex(int index) const { Point Line::getPointByIndex(int index) const {
return operator[](index); return operator[](index);
} }
void Line::setPointByIndex(int index, point now) { void Line::setPointByIndex(int index, Point now) {
vX[index] = now.x; vX[index] = now.x;
vY[index] = now.y; vY[index] = now.y;
} }
@ -38,7 +38,7 @@ void Line::clear() {
vY.clear(); vY.clear();
} }
void Line::push_back(point now) { void Line::push_back(Point now) {
siz++; siz++;
vX.push_back(now.x); vX.push_back(now.x);
vY.push_back(now.y); vY.push_back(now.y);
@ -52,11 +52,11 @@ bool Line::isLineContained(QVector4D bound) {
else return false; else return false;
} }
point Line::getBegin() { Point Line::getBegin() {
return { *vX.begin(), *vY.begin() }; return { *vX.begin(), *vY.begin() };
} }
point Line::getEnd() { Point Line::getEnd() {
return { *vX.rbegin(), *vY.rbegin() }; return { *vX.rbegin(), *vY.rbegin() };
} }

View File

@ -12,20 +12,20 @@ using std::pair;
using std::min; using std::min;
using std::max; using std::max;
using std::sort; using std::sort;
using std::tr1::shared_ptr; using std::shared_ptr;
using std::tr1::make_shared; using std::make_shared;
using std::swap; using std::swap;
const float eps = 1e-6; const float eps = 1e-6;
struct point { struct Point {
float x, y; float x, y;
point operator - (const point a) { return { x - a.x, y - a.y }; } Point operator - (const Point a) { return { x - a.x, y - a.y }; }
float operator * (const point a) { return x * a.y - y * a.x; } float operator * (const Point a) { return x * a.y - y * a.x; }
bool operator== (const point& a) const { bool operator== (const Point& a) const {
return fabs(x - a.x) <= eps && fabs(y - a.y) <= eps; return fabs(x - a.x) <= eps && fabs(y - a.y) <= eps;
} }
bool operator< (const point& a) const { bool operator< (const Point& a) const {
return fabs(x - a.x) <= eps ? y < a.y : x < a.x; return fabs(x - a.x) <= eps ? y < a.y : x < a.x;
} }
void show() { void show() {
@ -41,22 +41,22 @@ protected:
public: public:
typedef shared_ptr<Line> LinePtr; typedef shared_ptr<Line> LinePtr;
Line() :siz(0) {} Line() :siz(0) {}
Line(vector<point> Vp); Line(vector<Point> Vp);
int size(); int size();
void clear(); void clear();
point getBegin(); Point getBegin();
point getEnd(); Point getEnd();
int direction(bool isY); int direction(bool isY);
virtual float getLineValueByT(float t, bool isY) = 0; virtual float getLineValueByT(float t, bool isY) = 0;
virtual void monotonization(vector <LinePtr>& res) = 0; virtual void monotonization(vector <LinePtr>& res) = 0;
virtual int judgeBoundIntersection(float xy, float l, float r, bool isY) = 0; virtual int judgeBoundIntersection(float xy, float l, float r, bool isY) = 0;
virtual bool judgeIntersection(QVector4D bound); virtual bool judgeIntersection(QVector4D bound);
bool isLineContained(QVector4D bound); bool isLineContained(QVector4D bound);
point operator[](int index) const; Point operator[](int index) const;
point getPointByIndex(int index) const; Point getPointByIndex(int index) const;
vector<point> toPointVector() const; vector<Point> toPointVector() const;
void setPointByIndex(int index, point now); void setPointByIndex(int index, Point now);
void push_back(point now); void push_back(Point now);
virtual ~Line() {} virtual ~Line() {}
}; };

View File

@ -8,6 +8,7 @@
#include <QtMath> #include <QtMath>
#include "BvhTree.h" #include "BvhTree.h"
#include "ShortCutTree.h" #include "ShortCutTree.h"
#include "SvgParser.h"
Model::Model(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram) Model::Model(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram)
: context(context) : context(context)
@ -188,9 +189,18 @@ Drawable* Model::processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 mod
initBound.push_back(QVector4D(0.7, 0.7, 0.8, 0.8));*/ initBound.push_back(QVector4D(0.7, 0.7, 0.8, 0.8));*/
//bvhTree.buildBvhTree(initBound.data(), initBound.size()); //bvhTree.buildBvhTree(initBound.data(), initBound.size());
//vector<vector<point>> lineSet = { {point{-1,-1}, point{1,-1}},{point{1,-1}, point{1,1}}, {point{1,1}, point{-1,1}},{point{-1,1}, point{-1,-1}} };
vector<vector<point>> lineSet = { {point{-1,-1}, point{1,-1}},{point{1,-1}, point{1,1}}, {point{1,1}, point{-1,1}},{point{-1,1}, point{-1,-1}} }; vector<vector<Point>> lineSet = SvgParser::parse("M100,100C-.5,100,0,100.5,0,0L40,.07C40,59.5,39.5,60,100,60Z", 100,100);
ShortCutTree shortCutTree; for (vector<Point> line : lineSet)
{
for (Point p : line)
p.show();
std::cout << std::endl;
}
//vector<vector<Point>> lineSet = { {Point{-1,-1}, Point{1,-1}},{Point{1,-1}, Point{1,1}}, {Point{1,1}, Point{-1,1}},{Point{-1,1}, Point{-1,-1}} };
//vector<vector<Point>> lineSet = { {Point{-1,-1}, Point{1,-1}},{Point{1,-1}, Point{1,1}}, {Point{1,1}, Point{-1,1}},{Point{-1,1}, Point{-1,-1}} };
ShortCutTree shortCutTree(5);
shortCutTree.buildShortCutTree(lineSet); shortCutTree.buildShortCutTree(lineSet);
vector<float> pointVector; vector<float> pointVector;
vector<GLuint> lineVector; vector<GLuint> lineVector;

View File

@ -8,7 +8,7 @@ void ShortCutTree::init() {
numLine = numPoint = 0; numLine = numPoint = 0;
} }
int ShortCutTree::getPointIndex(point nowPoint) { int ShortCutTree::getPointIndex(Point nowPoint) {
auto iter = pointMap.find(nowPoint); auto iter = pointMap.find(nowPoint);
if (iter != pointMap.end()) { if (iter != pointMap.end()) {
return iter->second; return iter->second;
@ -44,7 +44,7 @@ void ShortCutTree::monotonization(vector<PointVector>& inL, vector<LinePtr>& out
} }
void ShortCutTree::generateShortCutsegmentement(ShortCutNode& nowTreeNode) { void ShortCutTree::generateShortCutsegmentement(ShortCutNode& nowTreeNode) {
point p = {0, 0}; Point p = {0, 0};
vector<int> v; vector<int> v;
for (int & lineIndex : nowTreeNode.lineSet) { for (int & lineIndex : nowTreeNode.lineSet) {
int type = allLine[lineIndex]->judgeBoundIntersection(nowTreeNode.bound.z(), nowTreeNode.bound.y(), nowTreeNode.bound.w(), false), be, en; int type = allLine[lineIndex]->judgeBoundIntersection(nowTreeNode.bound.z(), nowTreeNode.bound.y(), nowTreeNode.bound.w(), false), be, en;
@ -112,7 +112,7 @@ void ShortCutTree::simplifyLineVector() {
numLine = allLine.size(); numLine = allLine.size();
for (auto& nowLine : allLine) { for (auto& nowLine : allLine) {
PointVector pointVector = nowLine->toPointVector(); PointVector pointVector = nowLine->toPointVector();
for (point& p : pointVector) { for (Point& p : pointVector) {
int pointIndex = getPointIndex(p); int pointIndex = getPointIndex(p);
lineIndexs.push_back(pointIndex); lineIndexs.push_back(pointIndex);
if (pointVector.size() == 2) if (pointVector.size() == 2)
@ -216,7 +216,10 @@ void ShortCutTree::buildShortCutTree(vector<PointVector>& lineSet) {
} }
vector<BvhTreeData> ShortCutTree::getPointLineAndBvhTree(vector<float>& resPoints, vector<GLuint>& resLines) { vector<BvhTreeData> ShortCutTree::getPointLineAndBvhTree(vector<float>& resPoints, vector<GLuint>& resLines) {
vector<pair<GLuint, point> > tmpPoints; tmpPoints.clear(); vector<pair<GLuint, Point> > tmpPoints; tmpPoints.clear();
for (auto& now : restOfTreeNodes) {
std::cout << now.windingIncrement << ' ';
}
for (auto& mapIter : pointMap) { for (auto& mapIter : pointMap) {
tmpPoints.push_back({ mapIter.second , mapIter.first}); tmpPoints.push_back({ mapIter.second , mapIter.first});
} }

View File

@ -9,7 +9,7 @@ using std::map;
using std::for_each; using std::for_each;
struct ShortCutNode { struct ShortCutNode {
typedef vector<point> vectorPoint; typedef vector<Point> vectorPoint;
int windingIncrement; int windingIncrement;
bool divided; bool divided;
/* type 代表进入广度优先搜索队列的节点种类: /* type 代表进入广度优先搜索队列的节点种类:
@ -27,16 +27,16 @@ struct ShortCutNode {
}; };
class ShortCutTree class ShortCutTree
{ {
typedef vector<point> PointVector; typedef vector<Point> PointVector;
typedef vector<int> PointIndexVector; typedef vector<int> PointIndexVector;
private: private:
vector<ShortCutNode> restOfTreeNodes; vector<ShortCutNode> restOfTreeNodes;
vector<LinePtr> allLine; vector<LinePtr> allLine;
int RequiredLineMin, numPoint, numLine; int RequiredLineMin, numPoint, numLine;
map<point, int> pointMap; map<Point, int> pointMap;
vector<int> lineIndexs; vector<int> lineIndexs;
int getPointIndex(point nowPoint); int getPointIndex(Point nowPoint);
void generateShortCutsegmentement(ShortCutNode& nowTreeNode); void generateShortCutsegmentement(ShortCutNode& nowTreeNode);
bool handleShortCutNode(ShortCutNode& fa, ShortCutNode& nowTreeNode, float yValue, vector<ShortCutNode>& v, int& sumIncrement); bool handleShortCutNode(ShortCutNode& fa, ShortCutNode& nowTreeNode, float yValue, vector<ShortCutNode>& v, int& sumIncrement);
void spliteToShortCutTree(); void spliteToShortCutTree();
@ -48,7 +48,7 @@ public:
//lineMin最小线数目即划分终止条件 //lineMin最小线数目即划分终止条件
ShortCutTree(int lineMin = 3) ShortCutTree(int lineMin = 3)
:RequiredLineMin(lineMin), numPoint(0), numLine(0) {} :RequiredLineMin(lineMin), numPoint(0), numLine(0) {}
// 传入一个vector<vector<point> > 作为所有输入的线 // 传入一个vector<vector<Point> > 作为所有输入的线
void buildShortCutTree(vector<PointVector>& lineSet); void buildShortCutTree(vector<PointVector>& lineSet);
// 获得点集合和线集合 返回输入BvhTree的数据集合 // 获得点集合和线集合 返回输入BvhTree的数据集合
vector<BvhTreeData> getPointLineAndBvhTree(vector<float> &pointSet, vector<GLuint> &lineSet); vector<BvhTreeData> getPointLineAndBvhTree(vector<float> &pointSet, vector<GLuint> &lineSet);

View File

@ -14,7 +14,7 @@ float StraightLine::getLineValueByT(float t, bool isY) {
} }
float StraightLine::findTByValue(float value, bool isY) { float StraightLine::findTByValue(float value, bool isY) {
point be = getPointByIndex(0), en = getPointByIndex(1); Point be = getPointByIndex(0), en = getPointByIndex(1);
if (!isY) { if (!isY) {
if(fabs(be.x - en.x) <= eps) return 0; if(fabs(be.x - en.x) <= eps) return 0;
return (value - be.x) / (en.x - be.x); return (value - be.x) / (en.x - be.x);
@ -26,7 +26,7 @@ float StraightLine::findTByValue(float value, bool isY) {
} }
int StraightLine::judgeBoundIntersection(float xy, float l, float r, bool isY) { int StraightLine::judgeBoundIntersection(float xy, float l, float r, bool isY) {
point be = getBegin(), en = getEnd(); Point be = getBegin(), en = getEnd();
if (isY) { if (isY) {
swap(be.x, be.y); swap(be.x, be.y);
swap(en.x, en.y); swap(en.x, en.y);

View File

@ -0,0 +1,44 @@
#include "SvgParser.h"
#include <algorithm>
vector<vector<Point>> SvgParser::parse(const std::string path, float width, float height)
{
std::string tmp;
vector<float> point;
vector<Point> line;
vector<vector<Point>> lines;
for (char c : path.substr(1))
{
if ((c >= '0' && c <= '9') || c == '.' || c == '-' || c == '+')
{
tmp += c;
}
else
{
if (tmp != "")
{
point.push_back(std::stof(tmp));
tmp = "";
if (point.size() == 2)
{
line.push_back(Point{ std::clamp(point[0] / width * 2 - 1, -1.f, 1.f) , std::clamp(1 - point[1] / height * 2 , -1.f, 1.f)});
point.clear();
}
}
if (c != ',' && c != ' ')
{
lines.push_back(line);
line.erase(line.begin(), line.end() - 1);
if (c == 'Z')
{
line.push_back(lines[0][0]);
lines.push_back(line);
break;
}
}
}
}
lines.erase(lines.begin());
return lines;
}

View File

@ -0,0 +1,10 @@
#pragma once
#include <string>
#include "Line.h"
class SvgParser
{
public:
static vector<vector<Point>> parse(const std::string path, float width, float height);
};

View File

@ -1,17 +1,20 @@
# ArchitectureColoredPainting # ArchitectureColoredPainting
vs2022项目 qt5.15.2 msvc 2019 64-bit 古建筑彩绘计算机辅助设计系统
采用pbr材质现在有一个随时间变化的方向光并添加了阴影 ## 依赖
把一块布替换成了待完成的彩绘管线见PaintingMesh类以及painting着色器 - Qt 5.15.2 (MSVC 2019 64-bit)
- Assimp (x64-windows)
TODO ## 构建
- [x] 改用延迟渲染 使用 Visual Studio 2022 打开项目编译运行。
- [x] 指定一块材质使用独立管线进行纹理采样 ## 进度
- [ ] 彩绘的表示、读取、采样... 采用 PBR (金属度-粗糙度) 材质模型,场景中存在一个方向光,可拖动滑动条调整光源方向观察材质效果。
- [x] PCF Shadow Map 已实现BVH加速结构的建立
基本实现单图元的拆分,即划分网格并生成快捷段和缠绕增量,尚未验证正确性