editor: paint tool - vertexpaint, hairlength #94; hairparticle update;

This commit is contained in:
turanszkij
2020-03-26 22:43:20 +00:00
parent 8b059485fe
commit 730fcd0587
12 changed files with 408 additions and 225 deletions
+6 -191
View File
@@ -793,6 +793,7 @@ void EditorComponent::Update(float dt)
animWnd->Update();
weatherWnd->Update();
paintToolWnd->Update(dt);
selectionOutlineTimer += dt;
@@ -888,16 +889,8 @@ void EditorComponent::Update(float dt)
cinemaModeCheckBox->SetCheck(false);
}
// by default, paint tool is on center of screen, this makes it easy to tweak radius with GUI:
paintToolWnd->pos.x = wiRenderer::GetDevice()->GetScreenWidth() * 0.5f;
paintToolWnd->pos.y = wiRenderer::GetDevice()->GetScreenHeight() * 0.5f;
if (!wiBackLog::isActive() && !GetGUI().HasFocus())
{
XMFLOAT4 currentMouse = wiInput::GetPointer();
paintToolWnd->pos.x = currentMouse.x;
paintToolWnd->pos.y = currentMouse.y;
// Camera control:
static XMFLOAT4 originalMouse = XMFLOAT4(0, 0, 0, 0);
static bool camControlStart = true;
@@ -906,6 +899,7 @@ void EditorComponent::Update(float dt)
originalMouse = wiInput::GetPointer();
}
XMFLOAT4 currentMouse = wiInput::GetPointer();
float xDif = 0, yDif = 0;
if (wiInput::Down(wiInput::MOUSE_BUTTON_MIDDLE))
@@ -1195,189 +1189,8 @@ void EditorComponent::Update(float dt)
}
// Use Paint Tool or interact, but not both:
if (paintToolWnd->GetMode() != PaintToolWindow::MODE_DISABLED)
{
auto mode = paintToolWnd->GetMode();
switch (mode)
{
case PaintToolWindow::MODE_SOFTBODY_PINNING:
case PaintToolWindow::MODE_SOFTBODY_PHYSICS:
{
for (size_t i = 0; i < scene.softbodies.GetCount(); ++i)
{
SoftBodyPhysicsComponent& softbody = scene.softbodies[i];
if (softbody.vertex_positions_simulation.empty())
continue;
// Painting:
if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT))
{
const float radius = paintToolWnd->GetRadius();
const XMVECTOR C = XMLoadFloat2(&paintToolWnd->pos);
const XMMATRIX VP = camera.GetViewProjection();
const XMVECTOR MUL = XMVectorSet(0.5f, -0.5f, 1, 1);
const XMVECTOR ADD = XMVectorSet(0.5f, 0.5f, 0, 0);
const XMVECTOR SCREEN = XMVectorSet((float)wiRenderer::GetDevice()->GetScreenWidth(), (float)wiRenderer::GetDevice()->GetScreenHeight(), 1, 1);
size_t j = 0;
for (auto& ind : softbody.physicsToGraphicsVertexMapping)
{
XMVECTOR P = softbody.vertex_positions_simulation[ind].LoadPOS();
P = XMVector3TransformCoord(P, VP);
P = P * MUL + ADD;
P = P * SCREEN;
const float z = XMVectorGetZ(P);
if (z >= 0 && z <= 1 && XMVectorGetX(XMVector2Length(C - P)) <= radius)
{
softbody.weights[j] = (mode == PaintToolWindow::MODE_SOFTBODY_PINNING ? 0.0f : 1.0f);
softbody._flags |= SoftBodyPhysicsComponent::FORCE_RESET;
}
j++;
}
}
// Visualizing:
Entity entity = scene.softbodies.GetEntity(i);
const MeshComponent& mesh = *scene.meshes.GetComponent(entity);
const XMMATRIX W = XMLoadFloat4x4(&softbody.worldMatrix);
for (size_t j = 0; j < mesh.indices.size(); j += 3)
{
const uint32_t graphicsIndex0 = mesh.indices[j + 0];
const uint32_t graphicsIndex1 = mesh.indices[j + 1];
const uint32_t graphicsIndex2 = mesh.indices[j + 2];
const uint32_t physicsIndex0 = softbody.graphicsToPhysicsVertexMapping[graphicsIndex0];
const uint32_t physicsIndex1 = softbody.graphicsToPhysicsVertexMapping[graphicsIndex1];
const uint32_t physicsIndex2 = softbody.graphicsToPhysicsVertexMapping[graphicsIndex2];
const float weight0 = softbody.weights[physicsIndex0];
const float weight1 = softbody.weights[physicsIndex1];
const float weight2 = softbody.weights[physicsIndex2];
wiRenderer::RenderableTriangle tri;
if (softbody.vertex_positions_simulation.empty())
{
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh.vertex_positions[graphicsIndex0]), W));
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh.vertex_positions[graphicsIndex1]), W));
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh.vertex_positions[graphicsIndex2]), W));
}
else
{
tri.positionA = softbody.vertex_positions_simulation[graphicsIndex0].pos;
tri.positionB = softbody.vertex_positions_simulation[graphicsIndex1].pos;
tri.positionC = softbody.vertex_positions_simulation[graphicsIndex2].pos;
}
if (weight0 == 0)
tri.colorA = XMFLOAT4(1, 1, 0, 1);
else
tri.colorA = XMFLOAT4(1, 1, 1, 0.5f);
if (weight1 == 0)
tri.colorB = XMFLOAT4(1, 1, 0, 1);
else
tri.colorB = XMFLOAT4(1, 1, 1, 0.5f);
if (weight2 == 0)
tri.colorC = XMFLOAT4(1, 1, 0, 1);
else
tri.colorC = XMFLOAT4(1, 1, 1, 0.5f);
wiRenderer::DrawTriangle(tri, true);
if (weight0 == 0 && weight1 == 0 && weight2 == 0)
{
tri.colorA = tri.colorB = tri.colorC = XMFLOAT4(1, 0, 0, 0.8f);
wiRenderer::DrawTriangle(tri);
}
}
}
}
break;
case PaintToolWindow::MODE_HAIRPARTICLE_ADD_TRIANGLE:
case PaintToolWindow::MODE_HAIRPARTICLE_REMOVE_TRIANGLE:
{
for (size_t i = 0; i < scene.hairs.GetCount(); ++i)
{
wiHairParticle& hair = scene.hairs[i];
if (hair.meshID == INVALID_ENTITY)
continue;
MeshComponent* mesh = scene.meshes.GetComponent(hair.meshID);
if (mesh == nullptr)
continue;
Entity entity = scene.hairs.GetEntity(i);
const TransformComponent* transform = scene.transforms.GetComponent(entity);
if (transform == nullptr)
continue;
const XMMATRIX W = XMLoadFloat4x4(&transform->world);
const bool painting = wiInput::Down(wiInput::MOUSE_BUTTON_LEFT);
const float radius = paintToolWnd->GetRadius();
const XMVECTOR C = XMLoadFloat2(&paintToolWnd->pos);
const XMMATRIX VP = camera.GetViewProjection();
const XMVECTOR MUL = XMVectorSet(0.5f, -0.5f, 1, 1);
const XMVECTOR ADD = XMVectorSet(0.5f, 0.5f, 0, 0);
const XMVECTOR SCREEN = XMVectorSet((float)wiRenderer::GetDevice()->GetScreenWidth(), (float)wiRenderer::GetDevice()->GetScreenHeight(), 1, 1);
for (size_t j = 0; j < mesh->indices.size(); j += 3)
{
const uint32_t triangle[] = {
mesh->indices[j + 0],
mesh->indices[j + 1],
mesh->indices[j + 2],
};
if (painting)
{
bool hit = false;
for (int k = 0; k < arraysize(triangle); ++k)
{
const XMFLOAT3& pos = mesh->vertex_positions[triangle[k]];
XMVECTOR P = XMLoadFloat3(&pos);
P = XMVector3Transform(P, W);
P = XMVector3TransformCoord(P, VP);
P = P * MUL + ADD;
P = P * SCREEN;
const float z = XMVectorGetZ(P);
if (z >= 0 && z <= 1 && XMVectorGetX(XMVector2Length(C - P)) <= radius)
{
if (mode == PaintToolWindow::MODE_HAIRPARTICLE_ADD_TRIANGLE)
{
hair.vertex_lengths[triangle[k]] = 1.0f;
}
else if (mode == PaintToolWindow::MODE_HAIRPARTICLE_REMOVE_TRIANGLE)
{
hair.vertex_lengths[triangle[k]] = 0;
}
hair._flags |= wiHairParticle::REBUILD_BUFFERS;
}
}
}
wiRenderer::RenderableTriangle tri;
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[0]]), W));
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[1]]), W));
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[2]]), W));
wiRenderer::DrawTriangle(tri, true);
}
for (size_t j = 0; j < hair.indices.size(); j += 3)
{
const uint32_t triangle[] = {
hair.indices[j + 0],
hair.indices[j + 1],
hair.indices[j + 2],
};
wiRenderer::RenderableTriangle tri;
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[0]]), W));
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[1]]), W));
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[2]]), W));
tri.colorA = tri.colorB = tri.colorC = XMFLOAT4(1, 0, 1, 0.9f);
wiRenderer::DrawTriangle(tri, false);
}
}
}
break;
}
}
else
// Interactions only when paint tool is disabled:
if (paintToolWnd->GetMode() == PaintToolWindow::MODE_DISABLED)
{
// Interact:
if (hovered.entity != INVALID_ENTITY)
@@ -1625,6 +1438,7 @@ void EditorComponent::Update(float dt)
envProbeWnd->SetEntity(INVALID_ENTITY);
forceFieldWnd->SetEntity(INVALID_ENTITY);
cameraWnd->SetEntity(INVALID_ENTITY);
paintToolWnd->SetEntity(INVALID_ENTITY);
}
else
{
@@ -1650,6 +1464,7 @@ void EditorComponent::Update(float dt)
envProbeWnd->SetEntity(picked.entity);
forceFieldWnd->SetEntity(picked.entity);
cameraWnd->SetEntity(picked.entity);
paintToolWnd->SetEntity(picked.entity);
if (picked.subsetIndex >= 0)
{
+2 -15
View File
@@ -158,17 +158,6 @@ MaterialWindow::MaterialWindow(wiGUI* gui) : GUI(gui)
});
materialWindow->AddWidget(metalnessSlider);
alphaSlider = new wiSlider(0, 1, 1.0f, 1000, "Alpha: ");
alphaSlider->SetTooltip("Adjusts the overall transparency of the surface. No effect when BlendMode is set to OPAQUE.");
alphaSlider->SetSize(XMFLOAT2(100, 30));
alphaSlider->SetPos(XMFLOAT2(x, y += step));
alphaSlider->OnSlide([&](wiEventArgs args) {
MaterialComponent* material = wiScene::GetScene().materials.GetComponent(entity);
if (material != nullptr)
material->SetOpacity(args.fValue);
});
materialWindow->AddWidget(alphaSlider);
alphaRefSlider = new wiSlider(0, 1, 1.0f, 1000, "AlphaRef: ");
alphaRefSlider->SetTooltip("Adjust the alpha cutoff threshold. Some performance optimizations will be disabled.");
alphaRefSlider->SetSize(XMFLOAT2(100, 30));
@@ -311,8 +300,7 @@ MaterialWindow::MaterialWindow(wiGUI* gui) : GUI(gui)
MaterialComponent* material = wiScene::GetScene().materials.GetComponent(entity);
if (material != nullptr)
{
XMFLOAT3 col = args.color.toFloat3();
material->SetBaseColor(XMFLOAT4(col.x, col.y, col.z, material->GetOpacity()));
material->SetBaseColor(args.color.toFloat4());
}
});
materialWindow->AddWidget(baseColorPicker);
@@ -791,7 +779,6 @@ void MaterialWindow::SetEntity(Entity entity)
roughnessSlider->SetValue(material->roughness);
reflectanceSlider->SetValue(material->reflectance);
metalnessSlider->SetValue(material->metalness);
alphaSlider->SetValue(material->GetOpacity());
refractionIndexSlider->SetValue(material->refractionIndex);
emissiveSlider->SetValue(material->emissiveColor.w);
sssSlider->SetValue(material->subsurfaceScattering);
@@ -807,7 +794,7 @@ void MaterialWindow::SetEntity(Entity entity)
baseColorPicker->SetEnabled(true);
baseColorPicker->SetPickColor(wiColor::fromFloat4(material->baseColor));
emissiveColorPicker->SetEnabled(true);
emissiveColorPicker->SetPickColor(wiColor::fromFloat4(material->emissiveColor));
emissiveColorPicker->SetPickColor(wiColor::fromFloat3(XMFLOAT3(material->emissiveColor.x, material->emissiveColor.y, material->emissiveColor.z)));
blendModeComboBox->SetSelected((int)material->userBlendMode);
shaderTypeComboBox->SetSelected(max(0, material->GetCustomShaderID() + 1));
-1
View File
@@ -35,7 +35,6 @@ public:
wiSlider* roughnessSlider;
wiSlider* reflectanceSlider;
wiSlider* metalnessSlider;
wiSlider* alphaSlider;
wiSlider* refractionIndexSlider;
wiSlider* emissiveSlider;
wiSlider* sssSlider;
+345 -9
View File
@@ -1,7 +1,8 @@
#include "stdafx.h"
#include "PaintToolWindow.h"
#include "wiRenderer.h"
using namespace wiECS;
using namespace wiScene;
using namespace wiGraphics;
PaintToolWindow::PaintToolWindow(wiGUI* gui) : GUI(gui)
@@ -9,7 +10,7 @@ PaintToolWindow::PaintToolWindow(wiGUI* gui) : GUI(gui)
assert(GUI && "Invalid GUI!");
window = new wiWindow(GUI, "Paint Tool Window");
window->SetSize(XMFLOAT2(400, 300));
window->SetSize(XMFLOAT2(400, 500));
GUI->AddWidget(window);
float x = 100;
@@ -21,10 +22,12 @@ PaintToolWindow::PaintToolWindow(wiGUI* gui) : GUI(gui)
modeComboBox->SetPos(XMFLOAT2(x, y += step));
modeComboBox->SetSize(XMFLOAT2(200, 28));
modeComboBox->AddItem("Disabled");
modeComboBox->AddItem("Vertexcolor");
modeComboBox->AddItem("Softbody - Pinning");
modeComboBox->AddItem("Softbody - Physics");
modeComboBox->AddItem("Hairparticle - Add Triangle");
modeComboBox->AddItem("Hairparticle - Remove Triangle");
modeComboBox->AddItem("Hairparticle - Length (Alpha)");
modeComboBox->SetSelected(0);
window->AddWidget(modeComboBox);
@@ -36,6 +39,27 @@ PaintToolWindow::PaintToolWindow(wiGUI* gui) : GUI(gui)
radiusSlider->SetPos(XMFLOAT2(x, y += step));
window->AddWidget(radiusSlider);
amountSlider = new wiSlider(0, 1, 1, 10000, "Brush Amount: ");
amountSlider->SetTooltip("Set the brush amount. 0 = minimum affection, 1 = maximum affection");
amountSlider->SetSize(XMFLOAT2(200, 20));
amountSlider->SetPos(XMFLOAT2(x, y += step));
window->AddWidget(amountSlider);
falloffSlider = new wiSlider(0, 16, 0, 10000, "Brush Falloff: ");
falloffSlider->SetTooltip("Set the brush power. 0 = no falloff, 1 = linear falloff, more = falloff power");
falloffSlider->SetSize(XMFLOAT2(200, 20));
falloffSlider->SetPos(XMFLOAT2(x, y += step));
window->AddWidget(falloffSlider);
backfaceCheckBox = new wiCheckBox("Backfaces: ");
backfaceCheckBox->SetTooltip("Set whether to paint on backfaces of geometry or not");
backfaceCheckBox->SetPos(XMFLOAT2(x, y += step));
window->AddWidget(backfaceCheckBox);
colorPicker = new wiColorPicker(GUI, "Color", false);
colorPicker->SetPos(XMFLOAT2(10, y += step));
window->AddWidget(colorPicker);
window->Translate(XMFLOAT3((float)wiRenderer::GetDevice()->GetScreenWidth() - 550, 50, 0));
window->SetVisible(false);
}
@@ -46,12 +70,326 @@ PaintToolWindow::~PaintToolWindow()
delete window;
}
void PaintToolWindow::DrawBrush() const
void PaintToolWindow::Update(float dt)
{
if (GetMode() == MODE_DISABLED)
rot -= dt;
// by default, paint tool is on center of screen, this makes it easy to tweak radius with GUI:
pos.x = wiRenderer::GetDevice()->GetScreenWidth() * 0.5f;
pos.y = wiRenderer::GetDevice()->GetScreenHeight() * 0.5f;
if (GUI->HasFocus() || wiBackLog::isActive() || entity == INVALID_ENTITY)
return;
const float radius = GetRadius();
auto pointer = wiInput::GetPointer();
pos.x = pointer.x;
pos.y = pointer.y;
const bool pointer_moved = wiMath::Distance(pos, posPrev) > 1.0f;
const bool painting = pointer_moved && wiInput::Down(wiInput::MOUSE_BUTTON_LEFT);
if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT))
{
posPrev = pos;
}
else
{
posPrev = XMFLOAT2(0, 0);
}
const MODE mode = GetMode();
const float radius = radiusSlider->GetValue();
const float amount = amountSlider->GetValue();
const float falloff = falloffSlider->GetValue();
const wiColor color = colorPicker->GetPickColor();
const XMFLOAT4 color_float = color.toFloat4();
const bool backfaces = backfaceCheckBox->GetCheck();
Scene& scene = wiScene::GetScene();
const CameraComponent& camera = wiRenderer::GetCamera();
const XMVECTOR C = XMLoadFloat2(&pos);
const XMMATRIX VP = camera.GetViewProjection();
const XMVECTOR MUL = XMVectorSet(0.5f, -0.5f, 1, 1);
const XMVECTOR ADD = XMVectorSet(0.5f, 0.5f, 0, 0);
const XMVECTOR SCREEN = XMVectorSet((float)wiRenderer::GetDevice()->GetScreenWidth(), (float)wiRenderer::GetDevice()->GetScreenHeight(), 1, 1);
switch (mode)
{
case MODE_VERTEXCOLOR:
{
ObjectComponent* object = scene.objects.GetComponent(entity);
if (object == nullptr || object->meshID == INVALID_ENTITY)
break;
MeshComponent* mesh = scene.meshes.GetComponent(object->meshID);
if (mesh == nullptr)
break;
const TransformComponent* transform = scene.transforms.GetComponent(entity);
if (transform == nullptr)
break;
const XMMATRIX W = XMLoadFloat4x4(&transform->world);
bool rebuild = false;
for (size_t j = 0; j < mesh->indices.size(); j += 3)
{
const uint32_t triangle[] = {
mesh->indices[j + 0],
mesh->indices[j + 1],
mesh->indices[j + 2],
};
if (painting)
{
XMVECTOR P[arraysize(triangle)];
for (int k = 0; k < arraysize(triangle); ++k)
{
const XMFLOAT3& pos = mesh->vertex_positions[triangle[k]];
P[k] = XMLoadFloat3(&pos);
P[k] = XMVector3Transform(P[k], W);
P[k] = XMVector3TransformCoord(P[k], VP);
P[k] = P[k] * MUL + ADD;
P[k] = P[k] * SCREEN;
}
bool culled = false;
if (!backfaces)
{
const XMVECTOR N = XMVector3Normalize(XMVector3Cross(P[1] - P[0], P[2] - P[1]));
culled = XMVectorGetZ(N) > 0;
}
if (!culled)
{
for (int k = 0; k < arraysize(triangle); ++k)
{
const float z = XMVectorGetZ(P[k]);
const float dist = XMVectorGetX(XMVector2Length(C - P[k]));
if (z >= 0 && z <= 1 && dist <= radius)
{
if (mesh->vertex_colors.empty())
{
mesh->vertex_colors.resize(mesh->vertex_positions.size());
std::fill(mesh->vertex_colors.begin(), mesh->vertex_colors.end(), 0xFFFFFFFF); // fill white
}
wiColor vcol = mesh->vertex_colors[triangle[k]];
const float affection = amount * std::powf(1 - (dist / radius), falloff);
vcol = wiColor::lerp(vcol, color, affection);
mesh->vertex_colors[triangle[k]] = vcol.rgba;
rebuild = true;
}
}
}
}
wiRenderer::RenderableTriangle tri;
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[0]]), W));
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[1]]), W));
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[2]]), W));
tri.colorA.w = 0.8f;
tri.colorB.w = 0.8f;
tri.colorC.w = 0.8f;
wiRenderer::DrawTriangle(tri, true);
}
if (rebuild)
{
mesh->CreateRenderData();
}
}
break;
case MODE_SOFTBODY_PINNING:
case MODE_SOFTBODY_PHYSICS:
{
ObjectComponent* object = scene.objects.GetComponent(entity);
if (object == nullptr || object->meshID == INVALID_ENTITY)
break;
const MeshComponent* mesh = scene.meshes.GetComponent(object->meshID);
if (mesh == nullptr)
break;
SoftBodyPhysicsComponent* softbody = scene.softbodies.GetComponent(object->meshID);
if (softbody == nullptr || softbody->vertex_positions_simulation.empty())
break;
// Painting:
if (pointer_moved && wiInput::Down(wiInput::MOUSE_BUTTON_LEFT))
{
size_t j = 0;
for (auto& ind : softbody->physicsToGraphicsVertexMapping)
{
XMVECTOR P = softbody->vertex_positions_simulation[ind].LoadPOS();
P = XMVector3TransformCoord(P, VP);
P = P * MUL + ADD;
P = P * SCREEN;
const float z = XMVectorGetZ(P);
if (z >= 0 && z <= 1 && XMVectorGetX(XMVector2Length(C - P)) <= radius)
{
softbody->weights[j] = (mode == MODE_SOFTBODY_PINNING ? 0.0f : 1.0f);
softbody->_flags |= SoftBodyPhysicsComponent::FORCE_RESET;
}
j++;
}
}
// Visualizing:
const XMMATRIX W = XMLoadFloat4x4(&softbody->worldMatrix);
for (size_t j = 0; j < mesh->indices.size(); j += 3)
{
const uint32_t graphicsIndex0 = mesh->indices[j + 0];
const uint32_t graphicsIndex1 = mesh->indices[j + 1];
const uint32_t graphicsIndex2 = mesh->indices[j + 2];
const uint32_t physicsIndex0 = softbody->graphicsToPhysicsVertexMapping[graphicsIndex0];
const uint32_t physicsIndex1 = softbody->graphicsToPhysicsVertexMapping[graphicsIndex1];
const uint32_t physicsIndex2 = softbody->graphicsToPhysicsVertexMapping[graphicsIndex2];
const float weight0 = softbody->weights[physicsIndex0];
const float weight1 = softbody->weights[physicsIndex1];
const float weight2 = softbody->weights[physicsIndex2];
wiRenderer::RenderableTriangle tri;
if (softbody->vertex_positions_simulation.empty())
{
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[graphicsIndex0]), W));
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[graphicsIndex1]), W));
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[graphicsIndex2]), W));
}
else
{
tri.positionA = softbody->vertex_positions_simulation[graphicsIndex0].pos;
tri.positionB = softbody->vertex_positions_simulation[graphicsIndex1].pos;
tri.positionC = softbody->vertex_positions_simulation[graphicsIndex2].pos;
}
if (weight0 == 0)
tri.colorA = XMFLOAT4(1, 1, 0, 1);
else
tri.colorA = XMFLOAT4(1, 1, 1, 1);
if (weight1 == 0)
tri.colorB = XMFLOAT4(1, 1, 0, 1);
else
tri.colorB = XMFLOAT4(1, 1, 1, 1);
if (weight2 == 0)
tri.colorC = XMFLOAT4(1, 1, 0, 1);
else
tri.colorC = XMFLOAT4(1, 1, 1, 1);
wiRenderer::DrawTriangle(tri, true);
if (weight0 == 0 && weight1 == 0 && weight2 == 0)
{
tri.colorA = tri.colorB = tri.colorC = XMFLOAT4(1, 0, 0, 0.8f);
wiRenderer::DrawTriangle(tri);
}
}
}
break;
case MODE_HAIRPARTICLE_ADD_TRIANGLE:
case MODE_HAIRPARTICLE_REMOVE_TRIANGLE:
case MODE_HAIRPARTICLE_LENGTH:
{
wiHairParticle* hair = scene.hairs.GetComponent(entity);
if (hair == nullptr || hair->meshID == INVALID_ENTITY)
break;
MeshComponent* mesh = scene.meshes.GetComponent(hair->meshID);
if (mesh == nullptr)
break;
const TransformComponent* transform = scene.transforms.GetComponent(entity);
if (transform == nullptr)
break;
const XMMATRIX W = XMLoadFloat4x4(&transform->world);
for (size_t j = 0; j < mesh->indices.size(); j += 3)
{
const uint32_t triangle[] = {
mesh->indices[j + 0],
mesh->indices[j + 1],
mesh->indices[j + 2],
};
if (painting)
{
XMVECTOR P[arraysize(triangle)];
for (int k = 0; k < arraysize(triangle); ++k)
{
const XMFLOAT3& pos = mesh->vertex_positions[triangle[k]];
P[k] = XMLoadFloat3(&pos);
P[k] = XMVector3Transform(P[k], W);
P[k] = XMVector3TransformCoord(P[k], VP);
P[k] = P[k] * MUL + ADD;
P[k] = P[k] * SCREEN;
}
bool culled = false;
if (!backfaces)
{
const XMVECTOR N = XMVector3Normalize(XMVector3Cross(P[1] - P[0], P[2] - P[1]));
culled = XMVectorGetZ(N) > 0;
}
if (!culled)
{
for (int k = 0; k < arraysize(triangle); ++k)
{
const float z = XMVectorGetZ(P[k]);
const float dist = XMVectorGetX(XMVector2Length(C - P[k]));
if (z >= 0 && z <= 1 && dist <= radius)
{
switch (mode)
{
case MODE_HAIRPARTICLE_ADD_TRIANGLE:
hair->vertex_lengths[triangle[k]] = 1.0f;
break;
case MODE_HAIRPARTICLE_REMOVE_TRIANGLE:
hair->vertex_lengths[triangle[k]] = 0;
break;
case MODE_HAIRPARTICLE_LENGTH:
const float affection = amount * std::powf(1 - (dist / radius), falloff);
hair->vertex_lengths[triangle[k]] = wiMath::Lerp(hair->vertex_lengths[triangle[k]], color_float.w, affection);
// don't let it "remove" the vertex by keeping its length above zero:
// (because if removed, distribution also changes which might be distracting)
hair->vertex_lengths[triangle[k]] = wiMath::Clamp(hair->vertex_lengths[triangle[k]], 1.0f / 255.0f, 1.0f);
break;
}
hair->_flags |= wiHairParticle::REBUILD_BUFFERS;
}
}
}
}
wiRenderer::RenderableTriangle tri;
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[0]]), W));
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[1]]), W));
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[2]]), W));
wiRenderer::DrawTriangle(tri, true);
}
for (size_t j = 0; j < hair->indices.size(); j += 3)
{
const uint32_t triangle[] = {
hair->indices[j + 0],
hair->indices[j + 1],
hair->indices[j + 2],
};
wiRenderer::RenderableTriangle tri;
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[0]]), W));
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[1]]), W));
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[2]]), W));
tri.colorA = tri.colorB = tri.colorC = XMFLOAT4(1, 0, 1, 0.9f);
wiRenderer::DrawTriangle(tri, false);
}
}
break;
}
}
void PaintToolWindow::DrawBrush() const
{
if (GetMode() == MODE_DISABLED || entity == INVALID_ENTITY || wiBackLog::isActive())
return;
const float radius = radiusSlider->GetValue();
const int segmentcount = 36;
for (int i = 0; i < segmentcount; i += 1)
{
@@ -66,8 +404,6 @@ void PaintToolWindow::DrawBrush() const
wiRenderer::DrawLine(line);
}
static float rot = 0;
rot -= 0.008f;
for (int i = 0; i < segmentcount; i += 2)
{
const float angle0 = rot + (float)i / (float)segmentcount * XM_2PI;
@@ -85,7 +421,7 @@ PaintToolWindow::MODE PaintToolWindow::GetMode() const
{
return (MODE)modeComboBox->GetSelected();
}
float PaintToolWindow::GetRadius() const
void PaintToolWindow::SetEntity(wiECS::Entity value)
{
return radiusSlider->GetValue();
entity = value;
}
+11 -1
View File
@@ -12,16 +12,24 @@ class wiButton;
class PaintToolWindow
{
float rot = 0;
XMFLOAT2 posPrev = XMFLOAT2(0, 0);
public:
PaintToolWindow(wiGUI* gui);
~PaintToolWindow();
wiGUI* GUI;
wiECS::Entity entity = wiECS::INVALID_ENTITY;
wiWindow* window;
wiComboBox* modeComboBox;
wiSlider* radiusSlider;
wiSlider* amountSlider;
wiSlider* falloffSlider;
wiCheckBox* backfaceCheckBox;
wiColorPicker* colorPicker;
void Update(float dt);
void DrawBrush() const;
XMFLOAT2 pos = XMFLOAT2(0, 0);
@@ -29,11 +37,13 @@ public:
enum MODE
{
MODE_DISABLED,
MODE_VERTEXCOLOR,
MODE_SOFTBODY_PINNING,
MODE_SOFTBODY_PHYSICS,
MODE_HAIRPARTICLE_ADD_TRIANGLE,
MODE_HAIRPARTICLE_REMOVE_TRIANGLE,
MODE_HAIRPARTICLE_LENGTH,
};
MODE GetMode() const;
float GetRadius() const;
void SetEntity(wiECS::Entity value);
};
-1
View File
@@ -57,7 +57,6 @@ VertexToPixel main(uint fakeIndex : SV_VERTEXID)
float len = (binormal_length >> 24) & 0x000000FF;
len /= 255.0f;
len += 1;
len *= xLength;
// expand the particle into a billboard cross section, the patch:
+6 -1
View File
@@ -6,6 +6,7 @@ RWSTRUCTUREDBUFFER(simulationBuffer, PatchSimulationData, 1);
TYPEDBUFFER(meshIndexBuffer, uint, TEXSLOT_ONDEMAND0);
RAWBUFFER(meshVertexBuffer_POS, TEXSLOT_ONDEMAND1);
TYPEDBUFFER(meshVertexBuffer_length, float, TEXSLOT_ONDEMAND2);
#define NUM_LDS_FORCEFIELDS 32
struct LDS_ForceField
@@ -55,6 +56,9 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn
float3 nor0 = unpack_unitvector(asuint(pos_nor0.w));
float3 nor1 = unpack_unitvector(asuint(pos_nor1.w));
float3 nor2 = unpack_unitvector(asuint(pos_nor2.w));
float length0 = meshVertexBuffer_length[i0];
float length1 = meshVertexBuffer_length[i1];
float length2 = meshVertexBuffer_length[i2];
// random barycentric coords:
float f = rand(seed, uv);
@@ -71,6 +75,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn
float3 target = normalize(nor0 + f * (nor1 - nor0) + g * (nor2 - nor0));
float3 tangent = normalize((rand(seed, uv) < 0.5f ? pos_nor0.xyz : pos_nor2.xyz) - pos_nor1.xyz);
float3 binormal = cross(target, tangent);
float strand_length = length0 + f * (length1 - length0) + g * (length2 - length0);
uint tangent_random = 0;
tangent_random |= (uint)((uint)(tangent.x * 127.5f + 127.5f) << 0);
@@ -82,7 +87,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn
binormal_length |= (uint)((uint)(binormal.x * 127.5f + 127.5f) << 0);
binormal_length |= (uint)((uint)(binormal.y * 127.5f + 127.5f) << 8);
binormal_length |= (uint)((uint)(binormal.z * 127.5f + 127.5f) << 16);
binormal_length |= (uint)(rand(seed, uv) * 255 * saturate(xHairRandomness)) << 24;
binormal_length |= (uint)(lerp(1, rand(seed, uv), saturate(xHairRandomness)) * strand_length * 255) << 24;
// Identifies the hair strand root particle:
const uint strandID = DTid.x * xHairSegmentCount;
+20
View File
@@ -107,8 +107,27 @@ void wiHairParticle::UpdateCPU(const TransformComponent& transform, const MeshCo
}
}
if (!vertex_lengths.empty())
{
std::vector<uint8_t> ulengths;
ulengths.reserve(vertex_lengths.size());
for (auto& x : vertex_lengths)
{
ulengths.push_back(uint8_t(wiMath::Clamp(x, 0, 1) * 255.0f));
}
bd.MiscFlags = 0;
bd.BindFlags = BIND_SHADER_RESOURCE;
bd.Format = FORMAT_R8_UNORM;
bd.StructureByteStride = sizeof(uint8_t);
bd.ByteWidth = bd.StructureByteStride * (uint32_t)ulengths.size();
SubresourceData initData;
initData.pSysMem = ulengths.data();
device->CreateBuffer(&bd, &initData, &vertexBuffer_length);
}
if (!indices.empty())
{
bd.MiscFlags = 0;
bd.BindFlags = BIND_SHADER_RESOURCE;
bd.Format = FORMAT_R32_UINT;
bd.StructureByteStride = sizeof(uint32_t);
@@ -163,6 +182,7 @@ void wiHairParticle::UpdateGPU(const MeshComponent& mesh, const MaterialComponen
const GPUResource* res[] = {
indexBuffer.IsValid() ? &indexBuffer : &mesh.indexBuffer,
mesh.streamoutBuffer_POS.IsValid() ? &mesh.streamoutBuffer_POS : &mesh.vertexBuffer_POS,
&vertexBuffer_length
};
device->BindResources(CS, res, TEXSLOT_ONDEMAND0, arraysize(res), cmd);
+1 -1
View File
@@ -51,7 +51,7 @@ public:
XMFLOAT4X4 world;
XMFLOAT4X4 worldPrev;
AABB aabb;
std::vector<uint32_t> indices;
std::vector<uint32_t> indices; // it is dependent on vertex_lengths and contains triangles with non-zero lengths
void Serialize(wiArchive& archive, uint32_t seed = 0);
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wiVersion
// minor features, major updates
const int minor = 39;
// minor bug fixes, alterations, refactors, updates
const int revision = 27;
const int revision = 28;
long GetVersion()
+15 -4
View File
@@ -1800,6 +1800,16 @@ wiColorPicker::wiColorPicker(wiGUI* gui, const std::string& name, bool window_co
FireEvents();
});
AddWidget(text_V);
alphaSlider = new wiSlider(0, 255, 255, 255, "");
alphaSlider->SetPos(XMFLOAT2(20, 230));
alphaSlider->SetSize(XMFLOAT2(150, 18));
alphaSlider->SetText("A: ");
alphaSlider->SetTooltip("Value for ALPHA - TRANSPARENCY channel (0-255)");
alphaSlider->OnSlide([this](wiEventArgs args) {
FireEvents();
});
AddWidget(alphaSlider);
}
static const float colorpicker_center = 120;
static const float colorpicker_radius_triangle = 68;
@@ -2132,11 +2142,9 @@ void wiColorPicker::Render(const wiGUI* gui, CommandList cmd) const
float _width = 20;
Vertex vertices[] = {
{ XMFLOAT4(-_width, -_width, 0, 1),XMFLOAT4(1,1,1,1) },
{ XMFLOAT4(_width, -_width, 0, 1),XMFLOAT4(1,1,1,1) },
{ XMFLOAT4(-_width, _width, 0, 1),XMFLOAT4(1,1,1,1) },
{ XMFLOAT4(_width, _width, 0, 1),XMFLOAT4(1,1,1,1) },
{ XMFLOAT4(-_width, -_width, 0, 1),XMFLOAT4(1,1,1,1) },
{ XMFLOAT4(_width, _width, 0, 1),XMFLOAT4(1,1,1,1) },
{ XMFLOAT4(_width, -_width, 0, 1),XMFLOAT4(1,1,1,1) },
};
GPUBufferDesc desc;
@@ -2326,7 +2334,7 @@ wiColor wiColorPicker::GetPickColor() const
source.s = saturation;
source.v = luminance;
rgb result = hsv2rgb(source);
return wiColor::fromFloat3(XMFLOAT3(result.r, result.g, result.b));
return wiColor::fromFloat4(XMFLOAT4(result.r, result.g, result.b, alphaSlider->GetValue() / 255.0f));
}
void wiColorPicker::SetPickColor(wiColor value)
{
@@ -2344,9 +2352,12 @@ void wiColorPicker::SetPickColor(wiColor value)
}
saturation = result.s;
luminance = result.v;
alphaSlider->SetValue((float)value.getA());
}
void wiColorPicker::FireEvents()
{
if (onColorChanged == nullptr)
return;
wiEventArgs args;
args.color = GetPickColor();
onColorChanged(args);
+1
View File
@@ -317,6 +317,7 @@ protected:
wiTextInputField* text_H = nullptr;
wiTextInputField* text_S = nullptr;
wiTextInputField* text_V = nullptr;
wiSlider* alphaSlider = nullptr;
void FireEvents();
public: