Support triangle and hexagon shapes, add shape support to overlays.

This commit is contained in:
Brad Davis 2016-07-12 09:10:21 -07:00
parent cf1c954edc
commit 03cb6175ab
10 changed files with 298 additions and 12 deletions

View file

@ -22,6 +22,7 @@
#include "Image3DOverlay.h"
#include "Circle3DOverlay.h"
#include "Cube3DOverlay.h"
#include "Shape3DOverlay.h"
#include "ImageOverlay.h"
#include "Line3DOverlay.h"
#include "LocalModelsOverlay.h"
@ -157,6 +158,8 @@ unsigned int Overlays::addOverlay(const QString& type, const QVariant& propertie
thisOverlay = std::make_shared<TextOverlay>();
} else if (type == Text3DOverlay::TYPE) {
thisOverlay = std::make_shared<Text3DOverlay>();
} else if (type == Shape3DOverlay::TYPE) {
thisOverlay = std::make_shared<Shape3DOverlay>();
} else if (type == Cube3DOverlay::TYPE) {
thisOverlay = std::make_shared<Cube3DOverlay>();
} else if (type == Sphere3DOverlay::TYPE) {

View file

@ -0,0 +1,130 @@
//
// Shape3DOverlay.cpp
// interface/src/ui/overlays
//
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// include this before QGLWidget, which includes an earlier version of OpenGL
#include "Shape3DOverlay.h"
#include <SharedUtil.h>
#include <StreamUtils.h>
#include <GeometryCache.h>
#include <DependencyManager.h>
QString const Shape3DOverlay::TYPE = "shape";
Shape3DOverlay::Shape3DOverlay(const Shape3DOverlay* Shape3DOverlay) :
Volume3DOverlay(Shape3DOverlay)
{
}
void Shape3DOverlay::render(RenderArgs* args) {
if (!_visible) {
return; // do nothing if we're not visible
}
float alpha = getAlpha();
xColor color = getColor();
const float MAX_COLOR = 255.0f;
glm::vec4 cubeColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
// TODO: handle registration point??
glm::vec3 position = getPosition();
glm::vec3 dimensions = getDimensions();
glm::quat rotation = getRotation();
auto batch = args->_batch;
if (batch) {
Transform transform;
transform.setTranslation(position);
transform.setRotation(rotation);
auto geometryCache = DependencyManager::get<GeometryCache>();
auto pipeline = args->_pipeline;
if (!pipeline) {
pipeline = _isSolid ? geometryCache->getShapePipeline() : geometryCache->getWireShapePipeline();
}
transform.setScale(dimensions);
batch->setModelTransform(transform);
if (_isSolid) {
geometryCache->renderSolidShapeInstance(*batch, _shape, cubeColor, pipeline);
} else {
geometryCache->renderWireShapeInstance(*batch, _shape, cubeColor, pipeline);
}
}
}
const render::ShapeKey Shape3DOverlay::getShapeKey() {
auto builder = render::ShapeKey::Builder();
if (getAlpha() != 1.0f) {
builder.withTranslucent();
}
if (!getIsSolid()) {
builder.withUnlit().withDepthBias();
}
return builder.build();
}
Shape3DOverlay* Shape3DOverlay::createClone() const {
return new Shape3DOverlay(this);
}
static const std::array<QString, GeometryCache::Shape::NUM_SHAPES> shapeStrings { {
"Line",
"Triangle",
"Quad",
"Hexagon",
"Octagon",
"Circle",
"Cube",
"Sphere",
"Tetrahedron",
"Octahedron",
"Dodecahedron",
"Icosahedron",
"Torus",
"Cone",
"Cylinder"
} };
void Shape3DOverlay::setProperties(const QVariantMap& properties) {
Volume3DOverlay::setProperties(properties);
auto shape = properties["shape"];
if (shape.isValid()) {
const QString shapeStr = shape.toString();
for (size_t i = 0; i < shapeStrings.size(); ++i) {
if (shapeStr == shapeStrings[i]) {
this->_shape = static_cast<GeometryCache::Shape>(i);
break;
}
}
}
auto borderSize = properties["borderSize"];
if (borderSize.isValid()) {
float value = borderSize.toFloat();
setBorderSize(value);
}
}
QVariant Shape3DOverlay::getProperty(const QString& property) {
if (property == "borderSize") {
return _borderSize;
}
if (property == "shape") {
return shapeStrings[_shape];
}
return Volume3DOverlay::getProperty(property);
}

View file

@ -0,0 +1,46 @@
//
// Shape3DOverlay.h
// interface/src/ui/overlays
//
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_Shape3DOverlay_h
#define hifi_Shape3DOverlay_h
#include "Volume3DOverlay.h"
#include <GeometryCache.h>
class Shape3DOverlay : public Volume3DOverlay {
Q_OBJECT
public:
static QString const TYPE;
virtual QString getType() const override { return TYPE; }
Shape3DOverlay() {}
Shape3DOverlay(const Shape3DOverlay* Shape3DOverlay);
virtual void render(RenderArgs* args) override;
virtual const render::ShapeKey getShapeKey() override;
virtual Shape3DOverlay* createClone() const override;
float getBorderSize() const { return _borderSize; }
void setBorderSize(float value) { _borderSize = value; }
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
private:
float _borderSize;
GeometryCache::Shape _shape { GeometryCache::Hexagon };
};
#endif // hifi_Shape3DOverlay_h

View file

@ -23,9 +23,11 @@
// is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down.
static const float SPHERE_ENTITY_SCALE = 0.5f;
static GeometryCache::Shape MAPPING[entity::NUM_SHAPES] = {
static std::array<GeometryCache::Shape, entity::NUM_SHAPES> MAPPING { {
GeometryCache::Triangle,
GeometryCache::Quad,
GeometryCache::Hexagon,
GeometryCache::Octagon,
GeometryCache::Circle,
GeometryCache::Cube,
GeometryCache::Sphere,
@ -36,7 +38,7 @@ static GeometryCache::Shape MAPPING[entity::NUM_SHAPES] = {
GeometryCache::Torus,
GeometryCache::Cone,
GeometryCache::Cylinder,
};
} };
RenderableShapeEntityItem::Pointer RenderableShapeEntityItem::baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties) {

View file

@ -20,17 +20,19 @@
#include "ShapeEntityItem.h"
namespace entity {
static const std::vector<QString> shapeStrings { {
static const std::array<QString, Shape::NUM_SHAPES> shapeStrings { {
"Triangle",
"Quad",
"Circle",
"Hexagon",
"Octagon",
"Circle",
"Cube",
"Sphere",
"Tetrahedron",
"Octahedron",
"Dodecahedron",
"Icosahedron",
"Torus",
"Torus",
"Cone",
"Cylinder"
} };

View file

@ -15,6 +15,8 @@ namespace entity {
enum Shape {
Triangle,
Quad,
Hexagon,
Octagon,
Circle,
Cube,
Sphere,

View file

@ -97,7 +97,8 @@ public:
ICEServerHeartbeatACK,
NegotiateAudioFormat,
SelectedAudioFormat,
LAST_PACKET_TYPE = SelectedAudioFormat
MoreEntityShapes,
LAST_PACKET_TYPE = MoreEntityShapes
};
};

View file

@ -60,6 +60,18 @@ static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3);
static const gpu::Type SHAPE_INDEX_TYPE = gpu::UINT32;
static const uint SHAPE_INDEX_SIZE = sizeof(gpu::uint32);
template <size_t SIDES>
std::vector<vec3> polygon() {
std::vector<vec3> result;
result.reserve(SIDES);
double angleIncrement = 2.0 * M_PI / SIDES;
for (size_t i = 0; i < SIDES; ++i) {
double angle = (double)i * angleIncrement;
result.push_back(vec3{ cos(angle) * 0.5, 0.0, sin(angle) * 0.5 });
}
return result;
}
void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices) {
vertexBuffer->append(vertices);
@ -239,6 +251,75 @@ void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
}
template <uint32_t N>
void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
using namespace geometry;
Index baseVertex = (Index)(vertexBuffer->getSize() / SHAPE_VERTEX_STRIDE);
VertexVector vertices;
IndexVector solidIndices, wireIndices;
// Top and bottom faces
std::vector<vec3> shape = polygon<N>();
for (const vec3& v : shape) {
vertices.push_back(vec3(v.x, 0.5f, v.z));
vertices.push_back(vec3(0, 1, 0));
}
for (const vec3& v : shape) {
vertices.push_back(vec3(v.x, -0.5f, v.z));
vertices.push_back(vec3(0, -1, 0));
}
for (uint32_t i = 2; i < N; ++i) {
solidIndices.push_back(baseVertex + 0);
solidIndices.push_back(baseVertex + i);
solidIndices.push_back(baseVertex + i - 1);
solidIndices.push_back(baseVertex + N);
solidIndices.push_back(baseVertex + i + N - 1);
solidIndices.push_back(baseVertex + i + N);
}
for (uint32_t i = 1; i <= N; ++i) {
wireIndices.push_back(baseVertex + (i % N));
wireIndices.push_back(baseVertex + i - 1);
wireIndices.push_back(baseVertex + (i % N) + N);
wireIndices.push_back(baseVertex + (i - 1) + N);
}
// Now do the sides
baseVertex += 2 * N;
for (uint32_t i = 0; i < N; ++i) {
vec3 left = shape[i];
vec3 right = shape[(i + 1) % N];
vec3 normal = glm::normalize(left + right);
vec3 topLeft = vec3(left.x, 0.5f, left.z);
vec3 topRight = vec3(right.x, 0.5f, right.z);
vec3 bottomLeft = vec3(left.x, -0.5f, left.z);
vec3 bottomRight = vec3(right.x, -0.5f, right.z);
vertices.push_back(topLeft);
vertices.push_back(normal);
vertices.push_back(bottomLeft);
vertices.push_back(normal);
vertices.push_back(topRight);
vertices.push_back(normal);
vertices.push_back(bottomRight);
vertices.push_back(normal);
solidIndices.push_back(baseVertex + 0);
solidIndices.push_back(baseVertex + 2);
solidIndices.push_back(baseVertex + 1);
solidIndices.push_back(baseVertex + 1);
solidIndices.push_back(baseVertex + 2);
solidIndices.push_back(baseVertex + 3);
wireIndices.push_back(baseVertex + 0);
wireIndices.push_back(baseVertex + 1);
wireIndices.push_back(baseVertex + 3);
wireIndices.push_back(baseVertex + 2);
baseVertex += 4;
}
shapeData.setupVertices(vertexBuffer, vertices);
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
}
// FIXME solids need per-face vertices, but smooth shaded
// components do not. Find a way to support using draw elements
@ -285,10 +366,13 @@ void GeometryCache::buildShapes() {
// Not implememented yet:
//Triangle,
extrudePolygon<3>(_shapes[Triangle], _shapeVertices, _shapeIndices);
//Hexagon,
extrudePolygon<6>(_shapes[Hexagon], _shapeVertices, _shapeIndices);
//Octagon,
extrudePolygon<8>(_shapes[Octagon], _shapeVertices, _shapeIndices);
//Quad,
//Circle,
//Octahetron,
//Dodecahedron,
//Torus,
//Cone,
//Cylinder,
@ -1757,6 +1841,11 @@ void GeometryCache::renderSolidShapeInstance(gpu::Batch& batch, GeometryCache::S
renderInstances(batch, color, false, pipeline, shape);
}
void GeometryCache::renderWireShapeInstance(gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
renderInstances(batch, color, true, pipeline, shape);
}
void GeometryCache::renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
renderInstances(batch, color, false, pipeline, GeometryCache::Sphere);
}

View file

@ -132,6 +132,8 @@ public:
Line,
Triangle,
Quad,
Hexagon,
Octagon,
Circle,
Cube,
Sphere,
@ -139,10 +141,9 @@ public:
Octahedron,
Dodecahedron,
Icosahedron,
Torus,
Cone,
Cylinder,
Torus, // not yet implemented
Cone, // not yet implemented
Cylinder, // not yet implemented
NUM_SHAPES,
};
@ -170,6 +171,13 @@ public:
renderSolidShapeInstance(batch, shape, glm::vec4(color, 1.0f), pipeline);
}
void renderWireShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1),
const render::ShapePipelinePointer& pipeline = _simplePipeline);
void renderWireShapeInstance(gpu::Batch& batch, Shape shape, const glm::vec3& color,
const render::ShapePipelinePointer& pipeline = _simplePipeline) {
renderWireShapeInstance(batch, shape, glm::vec4(color, 1.0f), pipeline);
}
void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color,
const render::ShapePipelinePointer& pipeline = _simplePipeline);
void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec3& color,

View file

@ -1354,6 +1354,9 @@
<option value="Octahedron">Octahedron</option>
<option value="Icosahedron">Icosahedron</option>
<option value="Dodecahedron">Dodecahedron</option>
<option value="Hexagon">Hexagon</option>
<option value="Triangle">Triangle</option>
<option value="Octagon">Octagon</option>
</select>
</div>
<div class="property text">