Skip to content

Commit

Permalink
Merge pull request #1318 from TP-David/IntersectTextTechnique
Browse files Browse the repository at this point in the history
Intersect text with PolytopeIntersector or LineSegmentIntersector
  • Loading branch information
robertosfield authored Nov 1, 2024
2 parents 23ab576 + 679daba commit 2a0ff8c
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 28 deletions.
19 changes: 19 additions & 0 deletions include/vsg/maths/transform.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,25 @@ namespace vsg
vsg::translate(-eye.x, -eye.y, -eye.z);
}

template<typename T>
constexpr t_mat4<T> computeBillboardMatrix(const t_vec3<T>& centerEye, T autoscaleDistance)
{
auto distance = -centerEye.z;

auto scale = (distance < autoscaleDistance) ? distance / autoscaleDistance : 1.0;
t_mat4<T> mS(scale, 0.0, 0.0, 0.0,
0.0, scale, 0.0, 0.0,
0.0, 0.0, scale, 0.0,
0.0, 0.0, 0.0, 1.0);

t_mat4<T> mT(1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
centerEye.x, centerEye.y, centerEye.z, 1.0);

return mT * mS;
}

/// Hint on axis, using Collada conventions, all Right Hand
enum class CoordinateConvention
{
Expand Down
2 changes: 2 additions & 0 deletions include/vsg/utils/Intersector.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ namespace vsg
void apply(const ushortArray& array) override;
void apply(const uintArray& array) override;

void apply(const TextTechnique& technique) override;

//
// provide virtual functions for concrete Intersector implementations to provide handling of intersection with mesh geometries
//
Expand Down
16 changes: 1 addition & 15 deletions src/vsg/state/ArrayState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,22 +496,8 @@ ref_ptr<const vec3Array> BillboardArrayState::vertexArray(uint32_t instanceIndex
{
const auto& mv = localToWorldStack.back();
const auto& inverse_mv = worldToLocalStack.back();

auto center_eye = mv * position;
double distance = -center_eye.z;

double scale = (distance < autoDistanceScale) ? distance / autoDistanceScale : 1.0;
dmat4 S(scale, 0.0, 0.0, 0.0,
0.0, scale, 0.0, 0.0,
0.0, 0.0, scale, 0.0,
0.0, 0.0, 0.0, 1.0);

dmat4 T(1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
center_eye.x, center_eye.y, center_eye.z, 1.0);

dmat4 billboard_mv = T * S;
auto billboard_mv = computeBillboardMatrix(center_eye, autoDistanceScale);
billboard_to_local = inverse_mv * billboard_mv;
}
else
Expand Down
76 changes: 75 additions & 1 deletion src/vsg/text/CpuLayoutTechnique.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,77 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI

using namespace vsg;

class VSG_DECLSPEC CpuLayoutTechniqueArrayState : public Inherit<ArrayState, CpuLayoutTechniqueArrayState>
{
public:
CpuLayoutTechniqueArrayState(const CpuLayoutTechnique* in_technique) :
technique(in_technique)
{
}

CpuLayoutTechniqueArrayState(const CpuLayoutTechniqueArrayState& rhs) :
Inherit(rhs),
technique(rhs.technique)
{
}

CpuLayoutTechniqueArrayState(const ArrayState& rhs) :
Inherit(rhs)
{
}

ref_ptr<ArrayState> cloneArrayState() override
{
return CpuLayoutTechniqueArrayState::create(*this);
}

ref_ptr<ArrayState> cloneArrayState(ref_ptr<ArrayState> arrayState) override
{
auto clone = CpuLayoutTechniqueArrayState::create(*arrayState);
clone->technique = technique;
return clone;
}

ref_ptr<const vec3Array> vertexArray(uint32_t instanceIndex) override
{
auto new_vertices = vsg::vec3Array::create(static_cast<uint32_t>(vertices->size()));
auto src_vertex_itr = vertices->begin();
size_t v_index = 0;
for (auto& v : *new_vertices)
{
const auto& sv = *(src_vertex_itr++);

// single value vs per vertex value
dvec4 centerAndAutoScaleDistance;
if (technique->centerAndAutoScaleDistances->size() == 1)
centerAndAutoScaleDistance = technique->centerAndAutoScaleDistances->at(0);
else
centerAndAutoScaleDistance = technique->centerAndAutoScaleDistances->at(v_index++);

// billboard effect
dmat4 billboard_to_local;
if (!localToWorldStack.empty() && !worldToLocalStack.empty())
{
const dmat4& mv = localToWorldStack.back();
const dmat4& inverse_mv = worldToLocalStack.back();
dvec3 center_eye = mv * centerAndAutoScaleDistance.xyz;
dmat4 billboard_mv = computeBillboardMatrix(center_eye, centerAndAutoScaleDistance.w);
billboard_to_local = inverse_mv * billboard_mv;
}
else
{
billboard_to_local = vsg::translate(centerAndAutoScaleDistance.xyz);
}

v = vec3(billboard_to_local * dvec3(sv));
}

return new_vertices;
}

const CpuLayoutTechnique* technique = nullptr;
};

void CpuLayoutTechnique::setup(Text* text, uint32_t minimumAllocation, ref_ptr<const Options> options)
{
if (!text || !(text->text) || !text->font || !text->layout) return;
Expand Down Expand Up @@ -290,8 +361,11 @@ ref_ptr<Node> CpuLayoutTechnique::createRenderingSubgraph(ref_ptr<ShaderSet> sha
drawCommands->addChild(bindVertexBuffers);
drawCommands->addChild(bindIndexBuffer);
drawCommands->addChild(drawIndexed);

stategroup->addChild(drawCommands);

// Assign ArrayState for CPU mapping of vertices for billboarding
if (billboard)
stategroup->prototypeArrayState = CpuLayoutTechniqueArrayState::create(this);
}
else
{
Expand Down
118 changes: 107 additions & 11 deletions src/vsg/text/GpuLayoutTechnique.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,104 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI

using namespace vsg;

class VSG_DECLSPEC GpuLayoutTechniqueArrayState : public Inherit<ArrayState, GpuLayoutTechniqueArrayState>
{
public:
GpuLayoutTechniqueArrayState(const GpuLayoutTechnique* in_technique, const Text* in_text, bool in_billboard) :
technique(in_technique),
text(in_text),
billboard(in_billboard)
{
}

GpuLayoutTechniqueArrayState(const GpuLayoutTechniqueArrayState& rhs) :
Inherit(rhs),
technique(rhs.technique),
text(rhs.text),
billboard(rhs.billboard)
{
}

explicit GpuLayoutTechniqueArrayState(const ArrayState& rhs) :
Inherit(rhs)
{
}

ref_ptr<ArrayState> cloneArrayState() override
{
return GpuLayoutTechniqueArrayState::create(*this);
}

ref_ptr<ArrayState> cloneArrayState(ref_ptr<ArrayState> arrayState) override
{
auto clone = GpuLayoutTechniqueArrayState::create(*arrayState);
clone->technique = technique;
clone->text = text;
clone->billboard = billboard;
return clone;
}

ref_ptr<const vec3Array> vertexArray(uint32_t instanceIndex) override
{
// compute the position of the glyph
float horiAdvance = 0.0;
float vertAdvance = 0.0;
for (uint32_t i = 0; i < instanceIndex; ++i)
{
uint32_t glyph_index = technique->textArray->at(i);
if (glyph_index == 0)
{
// treat as a newlline
vertAdvance -= 1.0;
horiAdvance = 0.0;
}
else
{
const GlyphMetrics& glyph_metrics = text->font->glyphMetrics->at(glyph_index);
horiAdvance += glyph_metrics.horiAdvance;
}
}

uint32_t glyph_index = technique->textArray->at(instanceIndex);
const GlyphMetrics& glyph_metrics = text->font->glyphMetrics->at(glyph_index);

// billboard effect
auto textLayout = technique->layoutValue->value();
dmat4 transform_to_local;
if (billboard && !localToWorldStack.empty() && !worldToLocalStack.empty())
{
const dmat4& mv = localToWorldStack.back();
const dmat4& inverse_mv = worldToLocalStack.back();
dvec3 center_eye = mv * dvec3(textLayout.position);
dmat4 billboard_mv = computeBillboardMatrix(center_eye, (double)textLayout.billboardAutoScaleDistance);
transform_to_local = inverse_mv * billboard_mv;
}
else
{
transform_to_local = vsg::translate(textLayout.position);
}

auto new_vertices = vsg::vec3Array::create(6);
auto src_vertex_itr = vertices->begin();
for (auto& v : *new_vertices)
{
const auto& sv = *(src_vertex_itr++);

// compute the position of vertex
vec3 pos = textLayout.horizontal * (horiAdvance + textLayout.horizontalAlignment + glyph_metrics.horiBearingX + sv.x * glyph_metrics.width) +
textLayout.vertical * (vertAdvance + textLayout.verticalAlignment + glyph_metrics.horiBearingY + (sv.y - 1.f) * glyph_metrics.height);

v = vec3(transform_to_local * dvec3(pos));
}

return new_vertices;
}

const GpuLayoutTechnique* technique = nullptr;
const Text* text = nullptr;
bool billboard = false;
};

template<typename T>
void assignValue(T& dest, const T& src, bool& updated)
{
Expand Down Expand Up @@ -176,18 +274,21 @@ void GpuLayoutTechnique::setup(Text* text, uint32_t minimumAllocation, ref_ptr<c

if (!vertices)
{
vertices = vec3Array::create(4);
vertices = vec3Array::create(6);

float leadingEdgeGradient = 0.1f;

vertices->set(0, vec3(0.0f, 1.0f, 2.0f * leadingEdgeGradient));
vertices->set(1, vec3(0.0f, 0.0f, leadingEdgeGradient));
vertices->set(2, vec3(1.0f, 1.0f, leadingEdgeGradient));
vertices->set(3, vec3(1.0f, 0.0f, 0.0f));

vertices->set(3, vec3(0.0f, 0.0f, leadingEdgeGradient));
vertices->set(4, vec3(1.0f, 0.0f, 0.0f));
vertices->set(5, vec3(1.0f, 1.0f, leadingEdgeGradient));
}

if (!draw)
draw = Draw::create(4, num_quads, 0, 0);
draw = Draw::create(6, num_quads, 0, 0);
else
draw->instanceCount = num_quads;

Expand Down Expand Up @@ -223,14 +324,6 @@ void GpuLayoutTechnique::setup(Text* text, uint32_t minimumAllocation, ref_ptr<c
config->assignDescriptor("textLayout", layoutValue);
config->assignDescriptor("text", textArray);

// Set the InputAssemblyState.topology
struct SetPipelineStates : public Visitor
{
void apply(Object& object) override { object.traverse(*this); }
void apply(InputAssemblyState& ias) override { ias.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; }
};
vsg::visit<SetPipelineStates>(config);

if (sharedObjects)
sharedObjects->share(config, [](auto gpc) { gpc->init(); });
else
Expand All @@ -245,6 +338,9 @@ void GpuLayoutTechnique::setup(Text* text, uint32_t minimumAllocation, ref_ptr<c
drawCommands->addChild(bindVertexBuffers);
drawCommands->addChild(draw);
stateGroup->addChild(drawCommands);

// Assign ArrayState for CPU mapping of vertices
stateGroup->prototypeArrayState = GpuLayoutTechniqueArrayState::create(this, text, billboard);
}
else
{
Expand Down
10 changes: 10 additions & 0 deletions src/vsg/utils/Intersector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
#include <vsg/nodes/VertexIndexDraw.h>
#include <vsg/state/GraphicsPipeline.h>
#include <vsg/utils/Intersector.h>
#include <vsg/text/CpuLayoutTechnique.h>
#include <vsg/text/GpuLayoutTechnique.h>

using namespace vsg;

Expand Down Expand Up @@ -204,6 +206,14 @@ void Intersector::apply(const uintArray& array)
uint_indices = &array;
}

void Intersector::apply(const TextTechnique& technique)
{
if (auto cpuTechnique = technique.cast<CpuLayoutTechnique>())
cpuTechnique->scenegraph->accept(*this);
if (auto gpuTechnique = technique.cast<GpuLayoutTechnique>())
gpuTechnique->scenegraph->accept(*this);
}

void Intersector::apply(const Draw& draw)
{
PushPopNode ppn(_nodePath, &draw);
Expand Down
6 changes: 5 additions & 1 deletion src/vsg/utils/PolytopeIntersector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ PolytopeIntersector::PolytopeIntersector(const Camera& camera, double xMin, doub
}

_polytopeStack.push_back(worldspace);

dmat4 eyeToWorld = inverse(viewMatrix);
localToWorldStack().push_back(viewMatrix);
worldToLocalStack().push_back(eyeToWorld);
}

PolytopeIntersector::Intersection::Intersection(const dvec3& in_localIntersection, const dvec3& in_worldIntersection, const dmat4& in_localToWorld, const NodePath& in_nodePath, const DataList& in_arrays, const std::vector<uint32_t>& in_indices, uint32_t in_instanceIndex) :
Expand Down Expand Up @@ -305,7 +309,7 @@ bool PolytopeIntersector::intersectDraw(uint32_t firstVertex, uint32_t vertexCou
auto& arrayState = *arrayStateStack.back();

vsg::PrimitiveFunctor<vsg::PolytopePrimitiveIntersection> printPrimitives(*this, arrayState, _polytopeStack.back());
if (ushort_indices) printPrimitives.draw(arrayState.topology, firstVertex, vertexCount, firstInstance, instanceCount);
printPrimitives.draw(arrayState.topology, firstVertex, vertexCount, firstInstance, instanceCount);

return intersections.size() != previous_size;
}
Expand Down

0 comments on commit 2a0ff8c

Please sign in to comment.