dev-LayerStyle
yang.yongquan 2023-03-15 11:25:14 +08:00
commit 73e63f3817
10 changed files with 1253 additions and 1003 deletions

View File

@ -893,7 +893,7 @@ bool angleLargeThanPi(vec2 a, vec2 b)
/************************************************************************************/ /************************************************************************************/
void drawLine(in float d, inout uint styleIndex, out vec4 elementColor, out vec2 metallicRoughness) void drawLine(in float d, uint styleIndex, out vec4 elementColor, out vec2 metallicRoughness)
{ {
elementColor = vec4(1); elementColor = vec4(1);
metallicRoughness = vec2(0.8); metallicRoughness = vec2(0.8);
@ -969,14 +969,38 @@ void drawLine(in float d, inout uint styleIndex, out vec4 elementColor, out vec2
} }
} }
bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, vec2 tangentBegin, vec2 tangentEndLast) void nextStyleIndex(inout uint styleIndex)
{
uint headUint = floatBitsToUint(style[styleIndex + 1]);
vec4 head = unpackUnorm4x8(headUint);
switch (int(head.a * 100) % 10)
{
/// Plain
case 0: {
styleIndex += 3;
break;
}
/// RadialGradient
case 1: {
uint size = headUint % (1 << 15);
styleIndex += 2 + size * 2;
break;
}
case 2: {
break;
}
}
}
bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast)
{ {
vec2 normal; vec2 normal;
if (onVeryBegin) if (onVeryBegin)
{ {
if (endType == 0) if (endType%2 == 0)
return true; return true;
else if (endType == 1) else if (endType%2 == 1)
normal = normalize(mat2(0, 1, -1, 0) * (-tangentBegin)); normal = normalize(mat2(0, 1, -1, 0) * (-tangentBegin));
} }
else else
@ -985,17 +1009,26 @@ bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, ve
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBegin)); vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBegin));
normal = normalLast + normalNow; normal = normalLast + normalNow;
} }
return angleLargeThanPi(normal, localUV - p3); return angleLargeThanPi(normal, localUV - p0);
} }
bool shouldFillEndCap(vec2 localUV, int endType, vec2 p0, vec2 tangentEnd) bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 tangentEnd, vec2 tangentBeginNext)
{ {
vec2 normal; vec2 normal;
if (endType == 0) if (onVeryEnd)
{
if ((endType/2)%2 == 0)
return true; return true;
else if (endType == 1) else if ((endType/2)%2 == 1)
normal = normalize(mat2(0, 1, -1, 0) * tangentEnd); normal = normalize(mat2(0, 1, -1, 0) * tangentEnd);
return angleLargeThanPi(localUV - p0, normal); }
else
{
vec2 normalLast = normalize(mat2(0, 1, -1, 0) * tangentEnd);
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBeginNext));
normal = normalLast + normalNow;
}
return angleLargeThanPi(localUV - p3, normal);
} }
void main() void main()
@ -1006,9 +1039,8 @@ void main()
vec4 color = vec4(0); vec4 color = vec4(0);
// if(isinf(path[0].x)) imageStore(gBaseColor, ivec2(pixelLocation), // if(isinf(path[0].x)) imageStore(gBaseColor, ivec2(pixelLocation),
// vec4(vec2(pixelLocation)/vec2(imageSize(gBaseColor)), 1,1)); return; // vec4(vec2(pixelLocation)/vec2(imageSize(gBaseColor)), 1,1)); return;
for (uint styleIndex = 0; styleIndex < styleSize; styleIndex++) for (uint styleIndex = 0; styleIndex < styleSize;)
{ {
styleIndex += 6; styleIndex += 6;
vec2 localUV = vec2(pixelLocation) / pixelRatio + leftTop; vec2 localUV = vec2(pixelLocation) / pixelRatio + leftTop;
@ -1047,6 +1079,7 @@ void main()
elementColor = vec4(unpackUnorm4x8(floatBitsToUint(style[++styleIndex])).rgb, 1); elementColor = vec4(unpackUnorm4x8(floatBitsToUint(style[++styleIndex])).rgb, 1);
} }
} }
} }
else // Stroke else // Stroke
{ {
@ -1055,21 +1088,22 @@ void main()
float lineType = floor(styleHead.b * 10); float lineType = floor(styleHead.b * 10);
// float lineType = 2; // float lineType = 2;
int endType = int(round(styleHead.b * 100)) % 10; int endType = int(round(styleHead.b * 100)) % 10;
//endType = 1; // endType = 1;
int debugBegin = 0; int debugBegin = 0;
bool onVeryBegin = false; bool onVeryBegin = false;
bool onVeryEnd = false;
vec2 tangentEndLast; vec2 tangentEndLast;
uint lastHitIndex = 0;
bool lastHitElement = false;
hitElement = false;
for (uint pathIndex = 0; pathIndex < pathSize; pathIndex++) for (uint pathIndex = 0; pathIndex < pathSize; pathIndex++)
// for (uint pathIndex = 0; pathIndex < 4; pathIndex++) //for (uint pathIndex = 0; pathIndex < 46; pathIndex++)
{ {
vec2 pTemp = path[pathIndex]; vec2 pTemp = path[pathIndex];
if (isinf(pTemp.x)) if (isinf(pTemp.x))
{ {
// TODO: ¼ì²âÊÇ·ñ·â±Õ²¢´¦Àí // TODO: ¼ì²âÊÇ·ñ·â±Õ²¢´¦Àí
if (hitElement && distance(localUV, p3Last) <= strokeWidth)
{
hitElement = shouldFillEndCap(localUV, endType, p3Last, tangentEndLast);
}
pBegin = path[++pathIndex]; pBegin = path[++pathIndex];
p3Last = pBegin; p3Last = pBegin;
@ -1079,10 +1113,32 @@ void main()
} }
mat4x2 p = mat4x2(p3Last, pTemp, path[++pathIndex], path[++pathIndex]); mat4x2 p = mat4x2(p3Last, pTemp, path[++pathIndex], path[++pathIndex]);
vec2 tangentBeginNext;
if (pathIndex + 1 < pathSize)
{
vec2 pTemp = path[pathIndex + 1];
if (isinf(pTemp.x))
{
onVeryEnd = true;
}
else
{
onVeryEnd = false;
vec2 pNext[3] = {p[3], pTemp, path[pathIndex + 2]};
if (pNext[0] != pNext[1])
tangentBeginNext = normalize(pNext[0] - pNext[1]);
else
tangentBeginNext = normalize(pNext[0] - pNext[2]);
}
}
else
onVeryEnd = true;
float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true); float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true);
if (d <= strokeWidth) if (d <= strokeWidth)
{ {
bool onBegin = distance(localUV, p[0]) <= strokeWidth && p3Last == p[0]; bool onBegin = distance(localUV, p[0]) <= strokeWidth;
bool onEnd = distance(localUV, p[3]) <= strokeWidth;
vec2 tangentBegin; vec2 tangentBegin;
vec2 tangentEnd; vec2 tangentEnd;
if (p[0] != p[1]) if (p[0] != p[1])
@ -1094,11 +1150,14 @@ void main()
else else
tangentEnd = normalize(p[3] - p[1]); tangentEnd = normalize(p[3] - p[1]);
if (onBegin ? shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, p3Last - p2Last) bool hit = d < minDistance;
: d < minDistance) if (onBegin)
hit = hit &&
shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, tangentEndLast);
if (onEnd)
hit = hit && shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, tangentBeginNext);
if (hit)
{ {
minDistance = min(minDistance, d);
bool reverse = p[3].y - p[0].y < 0.; bool reverse = p[3].y - p[0].y < 0.;
if (tangentBegin.y == 0.) if (tangentBegin.y == 0.)
@ -1111,13 +1170,14 @@ void main()
if (lineType == 2 || (intTest % 2 == int(lineType))) if (lineType == 2 || (intTest % 2 == int(lineType)))
{ {
minDistance = min(minDistance, d);
lastHitElement = hitElement;
lastHitIndex = pathIndex;
hitElement = true; hitElement = true;
// elementColor = vec4(1, 1, 0, 1); // elementColor = vec4(1, 1, 0, 1);
vec2 metallicRoughness; vec2 metallicRoughness;
drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness); drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness);
} }
else if (p3Last == p[0])
hitElement = false;
} }
tangentEndLast = tangentEnd; tangentEndLast = tangentEnd;
} }
@ -1125,14 +1185,11 @@ void main()
p2Last = p[2]; p2Last = p[2];
onVeryBegin = false; onVeryBegin = false;
} }
if (hitElement && distance(localUV, p3Last) <= strokeWidth) nextStyleIndex(styleIndex);
{
hitElement = shouldFillEndCap(localUV, endType, p3Last, tangentEndLast);
}
} }
if (hitElement) if (hitElement)
color = elementColor; color = elementColor;
styleIndex += 100;
} }
if (color.a != 0) if (color.a != 0)
imageStore(gBaseColor, ivec2(pixelLocation), color); imageStore(gBaseColor, ivec2(pixelLocation), color);

File diff suppressed because it is too large Load Diff

View File

@ -62,15 +62,15 @@ QPainterPath PainterPathUtil::monotonization(QPainterPath& painterPath) {
return resPath; return resPath;
} }
std::pair<QPainterPath, float> PainterPathUtil::normalized(const QPainterPath& path) std::pair<QPainterPath, float> PainterPathUtil::normalized(const QPainterPath& path, float width)
{ {
auto rect = path.boundingRect(); auto rect = path.boundingRect();
return { (QTransform::fromTranslate(-rect.center().x(), -rect.center().y()) * QTransform::fromScale(1 / (rect.width() / 1.999999), -1 / (rect.height() / 1.999999))).map(path), return { (QTransform::fromTranslate(-rect.center().x(), -rect.center().y()) * QTransform::fromScale(1 / (rect.width() / 1.999999), -1 / (rect.height() / 1.999999)) * QTransform::fromScale(1 / (1 + width),1 / (1 + width))).map(path),
rect.width() / rect.height() }; rect.width() / rect.height() };
} }
std::pair<std::vector<std::vector<Renderer::Point>>, float> PainterPathUtil::toNormalizedLines(const QPainterPath& path) std::pair<std::vector<std::vector<Renderer::Point>>, float> PainterPathUtil::toNormalizedLines(const QPainterPath& path, float width)
{ {
auto [p, ratio] = normalized(path); auto [p, ratio] = normalized(path, width);
return { transformToLines(p), ratio }; return { transformToLines(p), ratio };
} }

View File

@ -8,7 +8,7 @@ class PainterPathUtil
public: public:
static std::vector<std::vector<Renderer::Point>> transformToLines(const QPainterPath& painterPath); static std::vector<std::vector<Renderer::Point>> transformToLines(const QPainterPath& painterPath);
static QPainterPath monotonization(QPainterPath& painterPath); static QPainterPath monotonization(QPainterPath& painterPath);
static std::pair<QPainterPath, float> normalized(const QPainterPath& path); static std::pair<QPainterPath, float> normalized(const QPainterPath& path, float width = 0);
static std::pair<std::vector<std::vector<Renderer::Point>>, float> toNormalizedLines(const QPainterPath& path); static std::pair<std::vector<std::vector<Renderer::Point>>, float> toNormalizedLines(const QPainterPath& path, float width = 0);
}; };

View File

@ -15,6 +15,7 @@
#include "../Editor/util/SvgFileLoader.h" #include "../Editor/util/SvgFileLoader.h"
#include <ThirdPartyLib/qquick/qquicksvgparser_p.h> #include <ThirdPartyLib/qquick/qquicksvgparser_p.h>
#include <util/PaintingUtil.h> #include <util/PaintingUtil.h>
#include "Painting/MaterialStyleStroke.h"
using namespace Renderer; using namespace Renderer;
using std::vector; using std::vector;
@ -157,9 +158,8 @@ std::unique_ptr<Drawable> Model::processMesh(aiMesh* mesh, const aiScene* scene,
for (auto& v : vertices) for (auto& v : vertices)
{ {
//qDebug() << v.TexCoords.x << v.TexCoords.y;
v.TexCoords = (v.TexCoords - leftBottom) / (rightTop - leftBottom); v.TexCoords = (v.TexCoords - leftBottom) / (rightTop - leftBottom);
qDebug() << v.TexCoords.x << v.TexCoords.y; //qDebug() << v.TexCoords.x << v.TexCoords.y;
} }
mesh->vertices = vertices; mesh->vertices = vertices;

View File

@ -104,7 +104,11 @@ std::unique_ptr<MaterialStyle> Renderer::MaterialStyleStroke::clone() const
bool Renderer::MaterialStyleStroke::operator==(const MaterialStyle& m) const bool Renderer::MaterialStyleStroke::operator==(const MaterialStyle& m) const
{ {
return type() == m.type() && *materialStroke == *static_cast<const MaterialStyleStroke&>(m).materialStroke; return type() == m.type()
&& halfWidth == static_cast<const MaterialStyleStroke&>(m).halfWidth
&& strokeType == static_cast<const MaterialStyleStroke&>(m).strokeType
&& endType == static_cast<const MaterialStyleStroke&>(m).endType
&& *materialStroke == *static_cast<const MaterialStyleStroke&>(m).materialStroke;
} }
float Renderer::MaterialStyleStroke::getHalfWidth() const float Renderer::MaterialStyleStroke::getHalfWidth() const

View File

@ -43,7 +43,7 @@ namespace Renderer
}; };
enum class StrokeType { kBothSides = 2, kLeftSide = 1, kRightSide = 0 }; enum class StrokeType { kBothSides = 2, kLeftSide = 1, kRightSide = 0 };
enum class StrokeEndType { kRound = 0, kFlat = 1 }; enum class StrokeEndType { kRound = 0b00, kFlat = 0b11, kRoundFlat = 0b10, kFlatRound = 0b01 };
class MaterialStyleStroke : public MaterialStyle class MaterialStyleStroke : public MaterialStyle
{ {
@ -54,7 +54,7 @@ namespace Renderer
virtual std::unique_ptr<MaterialStyle> clone() const override; virtual std::unique_ptr<MaterialStyle> clone() const override;
virtual bool operator==(const MaterialStyle&) const override; virtual bool operator==(const MaterialStyle&) const override;
float getHalfWidth() const; float getHalfWidth() const;
//protected:
float halfWidth; float halfWidth;
StrokeType strokeType; StrokeType strokeType;
StrokeEndType endType; StrokeEndType endType;

View File

@ -77,6 +77,7 @@ std::vector<GLfloat> generateStyleBuffer(const std::vector<BaseStyle>& styles)
styleBuffer.push_back(glm::uintBitsToFloat(glm::packUnorm2x16(style.transform->flip))); styleBuffer.push_back(glm::uintBitsToFloat(glm::packUnorm2x16(style.transform->flip)));
auto encoded = style.material->encoded(); auto encoded = style.material->encoded();
styleBuffer.insert(styleBuffer.end(), encoded.begin(), encoded.end()); styleBuffer.insert(styleBuffer.end(), encoded.begin(), encoded.end());
qDebug() << "style size" << styleBuffer.size();
} }
return styleBuffer; return styleBuffer;
} }

View File

@ -12,9 +12,11 @@ Renderer::RendererWidget::RendererWidget(QWidget* parent)
auto openAction = new QAction(QStringLiteral("´ò¿ª"), menu); auto openAction = new QAction(QStringLiteral("´ò¿ª"), menu);
auto saveAction = new QAction(QStringLiteral("±£´æ"), menu); auto saveAction = new QAction(QStringLiteral("±£´æ"), menu);
auto testAction = new QAction(QStringLiteral("²âÊÔ"), menu); auto testAction = new QAction(QStringLiteral("²âÊÔ"), menu);
auto test2Action = new QAction(QStringLiteral("²âÊÔ2"), menu);
menu->addAction(openAction); menu->addAction(openAction);
menu->addAction(saveAction); menu->addAction(saveAction);
menu->addAction(testAction); menu->addAction(testAction);
menu->addAction(test2Action);
ui.openButton->setHaloVisible(false); ui.openButton->setHaloVisible(false);
ui.openButton->setOverlayStyle(::Material::TintedOverlay); ui.openButton->setOverlayStyle(::Material::TintedOverlay);
@ -47,7 +49,9 @@ Renderer::RendererWidget::RendererWidget(QWidget* parent)
QObject::connect(testAction, &QAction::triggered, [&] { QObject::connect(testAction, &QAction::triggered, [&] {
ui.openGLWidget->setModel("Models/Sponza/Sponza.gltf"); ui.openGLWidget->setModel("Models/Sponza/Sponza.gltf");
}); });
QObject::connect(test2Action, &QAction::triggered, [&] {
ui.openGLWidget->setModel("E:\\3D Objects\\Gate\\Gate.gltf");
});
ui.horizontalSlider->setValue(105); ui.horizontalSlider->setValue(105);
ui.horizontalSlider_2->setValue(80); ui.horizontalSlider_2->setValue(80);
ui.exposureSlider->setValue(60); ui.exposureSlider->setValue(60);

View File

@ -10,6 +10,8 @@ using namespace Renderer;
namespace UnitTest namespace UnitTest
{ {
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
TEST_CLASS(ElementRendererStokeTypeTest) TEST_CLASS(ElementRendererStokeTypeTest)
{ {
private: private:
@ -20,6 +22,7 @@ namespace UnitTest
TEST_METHOD_INITIALIZE(initialize) TEST_METHOD_INITIALIZE(initialize)
{ {
qInstallMessageHandler(messageHandler);
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
@ -108,6 +111,27 @@ namespace UnitTest
w.show(); w.show();
a.exec(); a.exec();
} }
TEST_METHOD(TestRightSideFlatRound)
{
QApplication a(argc, argv);
class StyleStrokeRadialGradient : public Renderer::ElementStyle
{
virtual std::vector<Renderer::BaseStyle> toBaseStyles() const override
{
std::map<float, Material> materialMap = {
{0.20, Material{QColor(255,255,255)}},
{0.60, Material{QColor(165,176,207)}},
{1.00, Material{QColor(58,64,151)}}
};
return { BaseStyle(std::make_shared<TransformStyle>(),
std::make_shared<MaterialStyleStroke>(160, StrokeType::kRightSide, StrokeEndType::kFlatRound,
std::make_shared<StrokeRadialGradient>(materialMap, false))) };
}
} style;
TestGLWidget w(style);
w.show();
a.exec();
}
}; };
TEST_CLASS(ElementRendererStokeMaterialTest) TEST_CLASS(ElementRendererStokeMaterialTest)