Merge pull request #12588 from SamGondelman/shapeTex

Materials on primitives
This commit is contained in:
John Conklin II 2018-03-21 12:08:24 -07:00 committed by GitHub
commit 2d63afbe28
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 388 additions and 254 deletions

View file

@ -9,6 +9,7 @@
#include "RenderableMaterialEntityItem.h"
#include "RenderPipelines.h"
#include "GeometryCache.h"
using namespace render;
using namespace render::entities;
@ -90,138 +91,6 @@ ShapeKey MaterialEntityRenderer::getShapeKey() {
return builder.build();
}
glm::vec3 MaterialEntityRenderer::getVertexPos(float phi, float theta) {
return glm::vec3(glm::sin(theta) * glm::cos(phi), glm::cos(theta), glm::sin(theta) * glm::sin(phi));
}
glm::vec3 MaterialEntityRenderer::getTangent(float phi, float theta) {
return glm::vec3(-glm::cos(theta) * glm::cos(phi), glm::sin(theta), -glm::cos(theta) * glm::sin(phi));
}
void MaterialEntityRenderer::addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv) {
buffer.push_back(pos.x); buffer.push_back(pos.y); buffer.push_back(pos.z);
buffer.push_back(tan.x); buffer.push_back(tan.y); buffer.push_back(tan.z);
buffer.push_back(uv.x); buffer.push_back(uv.y);
}
void MaterialEntityRenderer::addTriangleFan(std::vector<float>& buffer, int stack, int step) {
float v1 = ((float)stack) / STACKS;
float theta1 = v1 * (float)M_PI;
glm::vec3 tip = getVertexPos(0, theta1);
float v2 = ((float)(stack + step)) / STACKS;
float theta2 = v2 * (float)M_PI;
for (int i = 0; i < SLICES; i++) {
float u1 = ((float)i) / SLICES;
float u2 = ((float)(i + step)) / SLICES;
float phi1 = u1 * M_PI_TIMES_2;
float phi2 = u2 * M_PI_TIMES_2;
/* (flipped for negative step)
p1
/ \
/ \
/ \
p3 ------ p2
*/
glm::vec3 pos2 = getVertexPos(phi2, theta2);
glm::vec3 pos3 = getVertexPos(phi1, theta2);
glm::vec3 tan1 = getTangent(0, theta1);
glm::vec3 tan2 = getTangent(phi2, theta2);
glm::vec3 tan3 = getTangent(phi1, theta2);
glm::vec2 uv1 = glm::vec2((u1 + u2) / 2.0f, v1);
glm::vec2 uv2 = glm::vec2(u2, v2);
glm::vec2 uv3 = glm::vec2(u1, v2);
addVertex(buffer, tip, tan1, uv1);
addVertex(buffer, pos2, tan2, uv2);
addVertex(buffer, pos3, tan3, uv3);
_numVertices += 3;
}
}
int MaterialEntityRenderer::_numVertices = 0;
std::shared_ptr<gpu::Stream::Format> MaterialEntityRenderer::_streamFormat = nullptr;
std::shared_ptr<gpu::BufferStream> MaterialEntityRenderer::_stream = nullptr;
std::shared_ptr<gpu::Buffer> MaterialEntityRenderer::_verticesBuffer = nullptr;
void MaterialEntityRenderer::generateMesh() {
_streamFormat = std::make_shared<gpu::Stream::Format>();
_stream = std::make_shared<gpu::BufferStream>();
_verticesBuffer = std::make_shared<gpu::Buffer>();
const int NUM_POS_COORDS = 3;
const int NUM_TANGENT_COORDS = 3;
const int VERTEX_TANGENT_OFFSET = NUM_POS_COORDS * sizeof(float);
const int VERTEX_TEXCOORD_OFFSET = VERTEX_TANGENT_OFFSET + NUM_TANGENT_COORDS * sizeof(float);
_streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
_streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
_streamFormat->setAttribute(gpu::Stream::TANGENT, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_TANGENT_OFFSET);
_streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET);
_stream->addBuffer(_verticesBuffer, 0, _streamFormat->getChannels().at(0)._stride);
std::vector<float> vertexBuffer;
// Top
addTriangleFan(vertexBuffer, 0, 1);
// Middle section
for (int j = 1; j < STACKS - 1; j++) {
float v1 = ((float)j) / STACKS;
float v2 = ((float)(j + 1)) / STACKS;
float theta1 = v1 * (float)M_PI;
float theta2 = v2 * (float)M_PI;
for (int i = 0; i < SLICES; i++) {
float u1 = ((float)i) / SLICES;
float u2 = ((float)(i + 1)) / SLICES;
float phi1 = u1 * M_PI_TIMES_2;
float phi2 = u2 * M_PI_TIMES_2;
/*
p2 ---- p3
| / |
| / |
| / |
p1 ---- p4
*/
glm::vec3 pos1 = getVertexPos(phi1, theta2);
glm::vec3 pos2 = getVertexPos(phi1, theta1);
glm::vec3 pos3 = getVertexPos(phi2, theta1);
glm::vec3 pos4 = getVertexPos(phi2, theta2);
glm::vec3 tan1 = getTangent(phi1, theta2);
glm::vec3 tan2 = getTangent(phi1, theta1);
glm::vec3 tan3 = getTangent(phi2, theta1);
glm::vec3 tan4 = getTangent(phi2, theta2);
glm::vec2 uv1 = glm::vec2(u1, v2);
glm::vec2 uv2 = glm::vec2(u1, v1);
glm::vec2 uv3 = glm::vec2(u2, v1);
glm::vec2 uv4 = glm::vec2(u2, v2);
addVertex(vertexBuffer, pos1, tan1, uv1);
addVertex(vertexBuffer, pos2, tan2, uv2);
addVertex(vertexBuffer, pos3, tan3, uv3);
addVertex(vertexBuffer, pos3, tan3, uv3);
addVertex(vertexBuffer, pos4, tan4, uv4);
addVertex(vertexBuffer, pos1, tan1, uv1);
_numVertices += 6;
}
}
// Bottom
addTriangleFan(vertexBuffer, STACKS, -1);
_verticesBuffer->append(vertexBuffer.size() * sizeof(float), (gpu::Byte*) vertexBuffer.data());
}
void MaterialEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableMaterialEntityItem::render");
Q_ASSERT(args->_batch);
@ -252,14 +121,7 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
args->_details._materialSwitches++;
// Draw!
if (_numVertices == 0) {
generateMesh();
}
DependencyManager::get<GeometryCache>()->renderSphere(batch);
batch.setInputFormat(_streamFormat);
batch.setInputStream(0, *_stream);
batch.draw(gpu::TRIANGLES, _numVertices, 0);
const int NUM_VERTICES_PER_TRIANGLE = 3;
args->_details._trianglesRendered += _numVertices / NUM_VERTICES_PER_TRIANGLE;
args->_details._trianglesRendered += (int)DependencyManager::get<GeometryCache>()->getSphereTriangleCount();
}

View file

@ -40,20 +40,6 @@ private:
Transform _renderTransform;
std::shared_ptr<NetworkMaterial> _drawMaterial;
static int _numVertices;
static std::shared_ptr<gpu::Stream::Format> _streamFormat;
static std::shared_ptr<gpu::BufferStream> _stream;
static std::shared_ptr<gpu::Buffer> _verticesBuffer;
void generateMesh();
void addTriangleFan(std::vector<float>& buffer, int stack, int step);
static glm::vec3 getVertexPos(float phi, float theta);
static glm::vec3 getTangent(float phi, float theta);
static void addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv);
const int SLICES = 15;
const int STACKS = 9;
const float M_PI_TIMES_2 = 2.0f * (float)M_PI;
};
} }

View file

@ -19,6 +19,8 @@
#include "render-utils/simple_vert.h"
#include "render-utils/simple_frag.h"
#include "RenderPipelines.h"
//#define SHAPE_ENTITY_USE_FADE_EFFECT
#ifdef SHAPE_ENTITY_USE_FADE_EFFECT
#include <FadeEffect.h>
@ -108,11 +110,94 @@ bool ShapeEntityRenderer::isTransparent() const {
if (_procedural.isEnabled() && _procedural.isFading()) {
return Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) < 1.0f;
}
// return _entity->getLocalRenderAlpha() < 1.0f || Parent::isTransparent();
auto mat = _materials.find("0");
if (mat != _materials.end()) {
if (mat->second.top().material) {
auto matKey = mat->second.top().material->getKey();
if (matKey.isTranslucent()) {
return true;
}
}
}
return Parent::isTransparent();
}
ItemKey ShapeEntityRenderer::getKey() {
ItemKey::Builder builder;
builder.withTypeShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
withReadLock([&] {
if (isTransparent()) {
builder.withTransparent();
}
});
return builder.build();
}
bool ShapeEntityRenderer::useMaterialPipeline() const {
bool proceduralReady = resultWithReadLock<bool>([&] {
return _procedural.isReady();
});
if (proceduralReady) {
return false;
}
graphics::MaterialKey drawMaterialKey;
auto mat = _materials.find("0");
if (mat != _materials.end() && mat->second.top().material) {
drawMaterialKey = mat->second.top().material->getKey();
}
if (drawMaterialKey.isEmissive() || drawMaterialKey.isUnlit() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
return true;
}
// If the material is using any map, we need to use a material ShapeKey
for (int i = 0; i < graphics::Material::MapChannel::NUM_MAP_CHANNELS; i++) {
if (drawMaterialKey.isMapChannel(graphics::Material::MapChannel(i))) {
return true;
}
}
return false;
}
ShapeKey ShapeEntityRenderer::getShapeKey() {
if (useMaterialPipeline()) {
graphics::MaterialKey drawMaterialKey;
if (_materials["0"].top().material) {
drawMaterialKey = _materials["0"].top().material->getKey();
}
bool isTranslucent = drawMaterialKey.isTranslucent();
bool hasTangents = drawMaterialKey.isNormalMap();
bool hasLightmap = drawMaterialKey.isLightmapMap();
bool isUnlit = drawMaterialKey.isUnlit();
ShapeKey::Builder builder;
builder.withMaterial();
if (isTranslucent) {
builder.withTranslucent();
}
if (hasTangents) {
builder.withTangents();
}
if (hasLightmap) {
builder.withLightmap();
}
if (isUnlit) {
builder.withUnlit();
}
return builder.build();
} else {
return Parent::getShapeKey();
}
}
void ShapeEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
Q_ASSERT(args->_batch);
@ -149,7 +234,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
} else {
geometryCache->renderShape(batch, geometryShape, outColor);
}
} else {
} else if (!useMaterialPipeline()) {
// FIXME, support instanced multi-shape rendering using multidraw indirect
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
auto pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
@ -158,6 +243,11 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
} else {
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
}
} else {
RenderPipelines::bindMaterial(mat, batch, args->_enableTexturing);
args->_details._materialSwitches++;
geometryCache->renderShape(batch, geometryShape);
}
const auto triCount = geometryCache->getShapeTriangleCount(geometryShape);

View file

@ -24,6 +24,10 @@ public:
virtual scriptable::ScriptableModelBase getScriptableModel() override;
protected:
ItemKey getKey() override;
ShapeKey getShapeKey() override;
private:
virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
@ -32,6 +36,8 @@ private:
virtual void doRender(RenderArgs* args) override;
virtual bool isTransparent() const override;
bool useMaterialPipeline() const;
Procedural _procedural;
QString _lastUserData;
Transform _renderTransform;

View file

@ -100,6 +100,8 @@ static const int VERTICES_PER_TRIANGLE = 3;
static const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element TEXCOORD0_ELEMENT { gpu::VEC2, gpu::FLOAT, gpu::UV };
static const gpu::Element TANGENT_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA };
static const gpu::Element TEXCOORD4_ELEMENT { gpu::VEC4, gpu::FLOAT, gpu::XYZW };
@ -107,8 +109,10 @@ static gpu::Stream::FormatPointer SOLID_STREAM_FORMAT;
static gpu::Stream::FormatPointer INSTANCED_SOLID_STREAM_FORMAT;
static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT;
static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normals
static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3);
static const uint SHAPE_VERTEX_STRIDE = sizeof(GeometryCache::ShapeVertex); // position, normal, texcoords, tangent
static const uint SHAPE_NORMALS_OFFSET = offsetof(GeometryCache::ShapeVertex, normal);
static const uint SHAPE_TEXCOORD0_OFFSET = offsetof(GeometryCache::ShapeVertex, uv);
static const uint SHAPE_TANGENT_OFFSET = offsetof(GeometryCache::ShapeVertex, tangent);
void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) {
@ -167,16 +171,20 @@ std::vector<vec3> polygon() {
return result;
}
void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices) {
void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const std::vector<ShapeVertex>& vertices) {
gpu::Buffer::Size offset = vertexBuffer->getSize();
vertexBuffer->append(vertices);
gpu::Buffer::Size viewSize = vertices.size() * sizeof(glm::vec3);
gpu::Buffer::Size viewSize = vertices.size() * sizeof(ShapeVertex);
_positionView = gpu::BufferView(vertexBuffer, offset,
viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT);
_normalView = gpu::BufferView(vertexBuffer, offset + SHAPE_NORMALS_OFFSET,
viewSize, SHAPE_VERTEX_STRIDE, NORMAL_ELEMENT);
_texCoordView = gpu::BufferView(vertexBuffer, offset + SHAPE_TEXCOORD0_OFFSET,
viewSize, SHAPE_VERTEX_STRIDE, TEXCOORD0_ELEMENT);
_tangentView = gpu::BufferView(vertexBuffer, offset + SHAPE_TANGENT_OFFSET,
viewSize, SHAPE_VERTEX_STRIDE, TANGENT_ELEMENT);
}
void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices) {
@ -202,6 +210,8 @@ void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, con
void GeometryCache::ShapeData::setupBatch(gpu::Batch& batch) const {
batch.setInputBuffer(gpu::Stream::POSITION, _positionView);
batch.setInputBuffer(gpu::Stream::NORMAL, _normalView);
batch.setInputBuffer(gpu::Stream::TEXCOORD, _texCoordView);
batch.setInputBuffer(gpu::Stream::TANGENT, _tangentView);
batch.setIndexBuffer(_indicesView);
}
@ -268,14 +278,14 @@ static IndexPair indexToken(geometry::Index a, geometry::Index b) {
template <size_t N>
void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
using namespace geometry;
VertexVector vertices;
std::vector<GeometryCache::ShapeVertex> vertices;
IndexVector solidIndices, wireIndices;
IndexPairs wireSeenIndices;
size_t faceCount = shape.faces.size();
size_t faceIndexCount = triangulatedFaceIndexCount<N>();
vertices.reserve(N * faceCount * 2);
vertices.reserve(N * faceCount);
solidIndices.reserve(faceIndexCount * faceCount);
Index baseVertex = 0;
@ -284,11 +294,35 @@ void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N
// Compute the face normal
vec3 faceNormal = shape.getFaceNormal(f);
// Find two points on this face with the same Y tex coords, and find the vector going from the one with the smaller X tex coord to the one with the larger X tex coord
vec3 faceTangent = vec3(0.0f);
Index i1 = 0;
Index i2 = i1 + 1;
while (i1 < N) {
if (shape.texCoords[f * N + i1].y == shape.texCoords[f * N + i2].y) {
break;
}
if (i2 == N - 1) {
i1++;
i2 = i1 + 1;
} else {
i2++;
}
}
if (i1 < N && i2 < N) {
vec3 p1 = shape.vertices[face[i1]];
vec3 p2 = shape.vertices[face[i2]];
faceTangent = glm::normalize(p1 - p2);
if (shape.texCoords[f * N + i1].x < shape.texCoords[f * N + i2].x) {
faceTangent *= -1.0f;
}
}
// Create the vertices for the face
for (Index i = 0; i < N; i++) {
Index originalIndex = face[i];
vertices.push_back(shape.vertices[originalIndex]);
vertices.push_back(faceNormal);
vertices.emplace_back(shape.vertices[originalIndex], faceNormal, shape.texCoords[f * N + i], faceTangent);
}
// Create the wire indices for unseen edges
@ -316,21 +350,95 @@ void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
}
vec2 calculateSphereTexCoord(const vec3& vertex) {
float u = 1.0f - (std::atan2(-vertex.z, -vertex.x) / ((float)M_PI) + 1.0f) * 0.5f;
if (vertex.y == 1.0f || vertex.y == -1.0f) {
// Remember points at the top so we don't treat them as being along the seam
u = NAN;
}
float v = 0.5f - std::asin(vertex.y) / (float)M_PI;
return vec2(u, v);
}
const float M_PI_TIMES_2 = 2.0f * (float)M_PI;
vec3 calculateSphereTangent(float u) {
float phi = u * M_PI_TIMES_2;
return -glm::normalize(glm::vec3(glm::sin(phi), 0.0f, glm::cos(phi)));
}
template <size_t N>
void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
using namespace geometry;
VertexVector vertices;
vertices.reserve(shape.vertices.size() * 2);
std::vector<GeometryCache::ShapeVertex> vertices;
vertices.reserve(shape.vertices.size());
for (const auto& vertex : shape.vertices) {
vertices.push_back(vertex);
vertices.push_back(vertex);
// We'll fill in the correct tangents later, once we correct the UVs
vertices.emplace_back(vertex, vertex, calculateSphereTexCoord(vertex), vec3(0.0f));
}
// We need to fix up the sphere's UVs because it's actually a tesselated icosahedron. See http://mft-dev.dk/uv-mapping-sphere/
size_t faceCount = shape.faces.size();
for (size_t f = 0; f < faceCount; f++) {
// Fix zipper
{
float& u1 = vertices[shape.faces[f][0]].uv.x;
float& u2 = vertices[shape.faces[f][1]].uv.x;
float& u3 = vertices[shape.faces[f][2]].uv.x;
if (glm::isnan(u1)) {
u1 = (u2 + u3) / 2.0f;
}
if (glm::isnan(u2)) {
u2 = (u1 + u3) / 2.0f;
}
if (glm::isnan(u3)) {
u3 = (u1 + u2) / 2.0f;
}
const float U_THRESHOLD = 0.25f;
float max = glm::max(u1, glm::max(u2, u3));
float min = glm::min(u1, glm::min(u2, u3));
if (max - min > U_THRESHOLD) {
if (u1 < U_THRESHOLD) {
u1 += 1.0f;
}
if (u2 < U_THRESHOLD) {
u2 += 1.0f;
}
if (u3 < U_THRESHOLD) {
u3 += 1.0f;
}
}
}
// Fix swirling at poles
for (Index i = 0; i < N; i++) {
Index originalIndex = shape.faces[f][i];
if (shape.vertices[originalIndex].y == 1.0f || shape.vertices[originalIndex].y == -1.0f) {
float uSum = 0.0f;
for (Index i2 = 1; i2 <= N - 1; i2++) {
float u = vertices[shape.faces[f][(i + i2) % N]].uv.x;
uSum += u;
}
uSum /= (float)(N - 1);
vertices[originalIndex].uv.x = uSum;
break;
}
}
// Fill in tangents
for (Index i = 0; i < N; i++) {
vec3 tangent = calculateSphereTangent(vertices[shape.faces[f][i]].uv.x);
vertices[shape.faces[f][i]].tangent = tangent;
}
}
IndexVector solidIndices, wireIndices;
IndexPairs wireSeenIndices;
size_t faceCount = shape.faces.size();
size_t faceIndexCount = triangulatedFaceIndexCount<N>();
solidIndices.reserve(faceIndexCount * faceCount);
@ -365,25 +473,22 @@ void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid
template <uint32_t N>
void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer, bool isConical = false) {
using namespace geometry;
VertexVector vertices;
std::vector<GeometryCache::ShapeVertex> vertices;
IndexVector solidIndices, wireIndices;
// Top (if not conical) and bottom faces
std::vector<vec3> shape = polygon<N>();
if (isConical) {
for (uint32_t i = 0; i < N; i++) {
vertices.push_back(vec3(0.0f, 0.5f, 0.0f));
vertices.push_back(vec3(0.0f, 1.0f, 0.0f));
vertices.emplace_back(vec3(0.0f, 0.5f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec2((float)i / (float)N, 1.0f), vec3(0.0f));
}
} else {
for (const vec3& v : shape) {
vertices.push_back(vec3(v.x, 0.5f, v.z));
vertices.push_back(vec3(0.0f, 1.0f, 0.0f));
vertices.emplace_back(vec3(v.x, 0.5f, v.z), vec3(0.0f, 1.0f, 0.0f), vec2(v.x, v.z) + vec2(0.5f), vec3(1.0f, 0.0f, 0.0f));
}
}
for (const vec3& v : shape) {
vertices.push_back(vec3(v.x, -0.5f, v.z));
vertices.push_back(vec3(0.0f, -1.0f, 0.0f));
vertices.emplace_back(vec3(v.x, -0.5f, v.z), vec3(0.0f, -1.0f, 0.0f), vec2(-v.x, v.z) + vec2(0.5f), vec3(-1.0f, 0.0f, 0.0f));
}
Index baseVertex = 0;
for (uint32_t i = 2; i < N; i++) {
@ -412,15 +517,16 @@ void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& ver
vec3 topRight = (isConical ? vec3(0.0f, 0.5f, 0.0f) : 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);
vec3 tangent = glm::normalize(bottomLeft - bottomRight);
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);
// Our tex coords go in the opposite direction as our vertices
float u = 1.0f - (float)i / (float)N;
float u2 = 1.0f - (float)(i + 1) / (float)N;
vertices.emplace_back(topLeft, normal, vec2(u, 0.0f), tangent);
vertices.emplace_back(bottomLeft, normal, vec2(u, 1.0f), tangent);
vertices.emplace_back(topRight, normal, vec2(u2, 0.0f), tangent);
vertices.emplace_back(bottomRight, normal, vec2(u2, 1.0f), tangent);
solidIndices.push_back(baseVertex + 0);
solidIndices.push_back(baseVertex + 2);
@ -439,41 +545,6 @@ void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& ver
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
}
void drawCircle(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
// Draw a circle with radius 1/4th the size of the bounding box
using namespace geometry;
VertexVector vertices;
IndexVector solidIndices, wireIndices;
const int NUM_CIRCLE_VERTICES = 64;
std::vector<vec3> shape = polygon<NUM_CIRCLE_VERTICES>();
for (const vec3& v : shape) {
vertices.push_back(vec3(v.x, 0.0f, v.z));
vertices.push_back(vec3(0.0f, 0.0f, 0.0f));
}
Index baseVertex = 0;
for (uint32_t i = 2; i < NUM_CIRCLE_VERTICES; i++) {
solidIndices.push_back(baseVertex + 0);
solidIndices.push_back(baseVertex + i);
solidIndices.push_back(baseVertex + i - 1);
solidIndices.push_back(baseVertex + NUM_CIRCLE_VERTICES);
solidIndices.push_back(baseVertex + i + NUM_CIRCLE_VERTICES - 1);
solidIndices.push_back(baseVertex + i + NUM_CIRCLE_VERTICES);
}
for (uint32_t i = 1; i <= NUM_CIRCLE_VERTICES; i++) {
wireIndices.push_back(baseVertex + (i % NUM_CIRCLE_VERTICES));
wireIndices.push_back(baseVertex + i - 1);
wireIndices.push_back(baseVertex + (i % NUM_CIRCLE_VERTICES) + NUM_CIRCLE_VERTICES);
wireIndices.push_back(baseVertex + (i - 1) + NUM_CIRCLE_VERTICES);
}
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
// or draw arrays as appropriate
@ -506,9 +577,9 @@ void GeometryCache::buildShapes() {
// Line
{
ShapeData& shapeData = _shapes[Line];
shapeData.setupVertices(_shapeVertices, VertexVector {
vec3(-0.5f, 0.0f, 0.0f), vec3(-0.5f, 0.0f, 0.0f),
vec3(0.5f, 0.0f, 0.0f), vec3(0.5f, 0.0f, 0.0f)
shapeData.setupVertices(_shapeVertices, std::vector<ShapeVertex> {
ShapeVertex(vec3(-0.5f, 0.0f, 0.0f), vec3(-0.5f, 0.0f, 0.0f), vec2(0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f)),
ShapeVertex(vec3(0.5f, 0.0f, 0.0f), vec3(0.5f, 0.0f, 0.0f), vec2(0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f))
});
IndexVector wireIndices;
// Only two indices
@ -572,6 +643,8 @@ gpu::Stream::FormatPointer& getSolidStreamFormat() {
SOLID_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD0, gpu::Stream::TEXCOORD0, TEXCOORD0_ELEMENT);
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TANGENT, gpu::Stream::TANGENT, TANGENT_ELEMENT);
}
return SOLID_STREAM_FORMAT;
}
@ -581,6 +654,8 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat() {
INSTANCED_SOLID_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD0, gpu::Stream::TEXCOORD0, TEXCOORD0_ELEMENT);
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TANGENT, gpu::Stream::TANGENT, TANGENT_ELEMENT);
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
}
return INSTANCED_SOLID_STREAM_FORMAT;
@ -591,6 +666,8 @@ gpu::Stream::FormatPointer& getInstancedSolidFadeStreamFormat() {
INSTANCED_SOLID_FADE_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD0, gpu::Stream::TEXCOORD0, TEXCOORD0_ELEMENT);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TANGENT, gpu::Stream::TANGENT, TANGENT_ELEMENT);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD2, gpu::Stream::TEXCOORD2, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD3, gpu::Stream::TEXCOORD3, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
@ -893,6 +970,7 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, con
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET);
// TODO: circle3D overlays use this to define their vertices, so they need tex coords
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);

View file

@ -354,13 +354,24 @@ public:
/// Set a batch to the simple pipeline, returning the previous pipeline
void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false);
struct ShapeVertex {
ShapeVertex(const vec3& pos, const vec3& normal, const vec2& uv, const vec3& tangent) : pos(pos), normal(normal), uv(uv), tangent(tangent) {}
vec3 pos;
vec3 normal;
vec2 uv;
vec3 tangent;
};
struct ShapeData {
gpu::BufferView _positionView;
gpu::BufferView _normalView;
gpu::BufferView _texCoordView;
gpu::BufferView _tangentView;
gpu::BufferView _indicesView;
gpu::BufferView _wireIndicesView;
void setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices);
void setupVertices(gpu::BufferPointer& vertexBuffer, const std::vector<ShapeVertex>& vertices);
void setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices);
void setupBatch(gpu::Batch& batch) const;
void draw(gpu::Batch& batch) const;

View file

@ -148,25 +148,25 @@ vec3 fetchLightmapMap(vec2 uv) {
}
<@endfunc@>
<@func tangentToViewSpace(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
<@func evalMaterialNormal(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
{
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);
vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz);
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
vec3 normalizedBitangent = cross(normalizedNormal, normalizedTangent);
vec3 localNormal = <$fetchedNormal$>;
<$normal$> = vec3(normalizedTangent * localNormal.x + normalizedNormal * localNormal.y + normalizedBitangent * localNormal.z);
<$normal$> = vec3(normalizedBitangent * localNormal.x + normalizedNormal * localNormal.y + normalizedTangent * localNormal.z);
}
<@endfunc@>
<@func tangentToViewSpaceLOD(fragPos, fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
<@func evalMaterialNormalLOD(fragPos, fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
{
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);
vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz);
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
vec3 normalizedBitangent = cross(normalizedNormal, normalizedTangent);
// attenuate the normal map divergence from the mesh normal based on distance
// THe attenuation range [20,100] meters from the eye is arbitrary for now
// The attenuation range [20,100] meters from the eye is arbitrary for now
vec3 localNormal = mix(<$fetchedNormal$>, vec3(0.0, 1.0, 0.0), smoothstep(20.0, 100.0, (-<$fragPos$>).z));
<$normal$> = vec3(normalizedTangent * localNormal.x + normalizedNormal * localNormal.y + normalizedBitangent * localNormal.z);
<$normal$> = vec3(normalizedBitangent * localNormal.x + normalizedNormal * localNormal.y + normalizedTangent * localNormal.z);
}
<@endfunc@>

View file

@ -58,7 +58,7 @@ void main(void) {
vec3 fragPosition = _position.xyz;
vec3 fragNormal;
<$tangentToViewSpace(normalTex, _normal, _tangent, fragNormal)$>
<$evalMaterialNormal(normalTex, _normal, _tangent, fragNormal)$>
TransformCamera cam = getTransformCamera();

View file

@ -33,11 +33,11 @@ void main(void) {
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, normalTexel, metallicTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
vec3 viewNormal;
<$tangentToViewSpaceLOD(_position, normalTexel, _normal, _tangent, viewNormal)$>
vec3 fragNormal;
<$evalMaterialNormalLOD(_position, normalTexel, _normal, _tangent, fragNormal)$>
packDeferredFragmentLightmap(
normalize(viewNormal.xyz),
normalize(fragNormal.xyz),
evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a),
getMaterialAlbedo(mat) * albedo.rgb * _color,
getMaterialRoughness(mat) * roughness,

View file

@ -43,11 +43,11 @@ void main(void) {
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, normalTexel, metallicTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
vec3 viewNormal;
<$tangentToViewSpaceLOD(_position, normalTexel, _normal, _tangent, viewNormal)$>
vec3 fragNormal;
<$evalMaterialNormalLOD(_position, normalTexel, _normal, _tangent, fragNormal)$>
packDeferredFragmentLightmap(
normalize(viewNormal.xyz),
normalize(fragNormal.xyz),
evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a),
getMaterialAlbedo(mat) * albedo.rgb * _color,
getMaterialRoughness(mat) * roughness,

View file

@ -46,8 +46,8 @@ void main(void) {
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
vec3 viewNormal;
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$>
vec3 fragNormal;
<$evalMaterialNormalLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
float metallic = getMaterialMetallic(mat);
<$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>;
@ -56,7 +56,7 @@ void main(void) {
<$evalMaterialScattering(scatteringTex, scattering, matKey, scattering)$>;
packDeferredFragment(
normalize(viewNormal.xyz),
normalize(fragNormal.xyz),
opacity,
albedo,
roughness,

View file

@ -56,8 +56,8 @@ void main(void) {
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
vec3 viewNormal;
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$>
vec3 fragNormal;
<$evalMaterialNormalLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
float metallic = getMaterialMetallic(mat);
<$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>;
@ -65,7 +65,7 @@ void main(void) {
float scattering = getMaterialScattering(mat);
packDeferredFragment(
normalize(viewNormal.xyz),
normalize(fragNormal.xyz),
opacity,
albedo,
roughness,

View file

@ -61,7 +61,7 @@ void main(void) {
vec3 fragPosition = _position.xyz;
vec3 fragNormal;
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
<$evalMaterialNormalLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
TransformCamera cam = getTransformCamera();
vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));

View file

@ -71,7 +71,7 @@ void main(void) {
vec3 fragPosition = _position.xyz;
// Lighting is done in world space
vec3 fragNormal;
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
<$evalMaterialNormalLOD(_position, normalTex, _normal, _tangent, fragNormal)$>
TransformCamera cam = getTransformCamera();
vec3 fragEyeVector = vec3(cam._viewInverse * vec4(-fragPosition, 0.0));

View file

@ -8,8 +8,11 @@
#include "Shapes.h"
#include "qmath.h"
namespace geometry {
using glm::vec2;
using glm::vec3;
// The golden ratio
@ -19,8 +22,8 @@ Solid<3> tesselate(const Solid<3>& solid_, int count) {
Solid<3> solid = solid_;
float length = glm::length(solid.vertices[0]);
for (int i = 0; i < count; ++i) {
Solid<3> result { solid.vertices, {} };
result.vertices.reserve(solid.vertices.size() + solid.faces.size() * 3);
Solid<3> result { solid.vertices, {}, {} };
result.vertices.reserve(solid.vertices.size() + solid.faces.size() * 6);
for (size_t f = 0; f < solid.faces.size(); ++f) {
Index baseVertex = (Index)result.vertices.size();
const Face<3>& oldFace = solid.faces[f];
@ -30,13 +33,26 @@ Solid<3> tesselate(const Solid<3>& solid_, int count) {
vec3 ab = glm::normalize(a + b) * length;
vec3 bc = glm::normalize(b + c) * length;
vec3 ca = glm::normalize(c + a) * length;
result.vertices.push_back(a);
result.vertices.push_back(ab);
result.vertices.push_back(ca);
result.faces.push_back(Face<3>{ { baseVertex, baseVertex + 1, baseVertex + 2 } });
result.vertices.push_back(ab);
result.vertices.push_back(b);
result.vertices.push_back(bc);
result.faces.push_back(Face<3>{ { baseVertex + 3, baseVertex + 4, baseVertex + 5 } });
result.vertices.push_back(bc);
result.vertices.push_back(c);
result.vertices.push_back(ca);
result.faces.push_back(Face<3>{ { baseVertex + 6, baseVertex + 7, baseVertex + 8 } });
result.vertices.push_back(ab);
result.vertices.push_back(bc);
result.vertices.push_back(ca);
result.faces.push_back(Face<3>{ { oldFace[0], baseVertex, baseVertex + 2 } });
result.faces.push_back(Face<3>{ { baseVertex, oldFace[1], baseVertex + 1 } });
result.faces.push_back(Face<3>{ { baseVertex + 1, oldFace[2], baseVertex + 2 } });
result.faces.push_back(Face<3>{ { baseVertex, baseVertex + 1, baseVertex + 2 } });
result.faces.push_back(Face<3>{ { baseVertex + 9, baseVertex + 10, baseVertex + 11 } });
}
solid = result;
}
@ -50,6 +66,10 @@ const Solid<3>& tetrahedron() {
static const auto D = vec3(-1, -1, 1);
static const Solid<3> TETRAHEDRON = Solid<3>{
{ A, B, C, D },
{ vec2(0.75f, 0.5f), vec2(0.5f, 0.0f), vec2(0.25f, 0.5f),
vec2(0.5f, 1.0f), vec2(1.0f, 1.0f), vec2(0.75f, 0.5f),
vec2(0.25f, 0.5f), vec2(0.5f, 1.0f), vec2(0.75f, 0.5f),
vec2(0.25f, 0.5f), vec2(0.0f, 1.0f), vec2(0.5f, 1.0f) },
FaceVector<3>{
Face<3> { { 0, 1, 2 } },
Face<3> { { 3, 1, 0 } },
@ -65,8 +85,15 @@ const Solid<4>& cube() {
static const auto B = vec3(-1, 1, 1);
static const auto C = vec3(-1, 1, -1);
static const auto D = vec3(1, 1, -1);
static const float THIRD = 1.0f / 3.0f;
static const Solid<4> CUBE = Solid<4>{
{ A, B, C, D, -A, -B, -C, -D },
{ vec2(0.5f, 0.0f), vec2(0.25f, 0.0f), vec2(0.25f, THIRD), vec2(0.5f, THIRD),
vec2(0.5f, THIRD), vec2(0.25f, THIRD), vec2(0.25f, 2.0f * THIRD), vec2(0.5f, 2.0f * THIRD),
vec2(0.25f, THIRD), vec2(0.0f, THIRD), vec2(0.0f, 2.0f * THIRD), vec2(0.25f, 2.0f * THIRD),
vec2(1.0f, THIRD), vec2(0.75f, THIRD), vec2(0.75f, 2.0f * THIRD), vec2(1.0f, 2.0f * THIRD),
vec2(0.75f, THIRD), vec2(0.5f, THIRD), vec2(0.5f, 2.0f * THIRD), vec2(0.75f, 2.0f * THIRD),
vec2(0.25f, 1.0f), vec2(0.5f, 1.0f), vec2(0.5f, 2.0f * THIRD), vec2(0.25f, 2.0f * THIRD) },
FaceVector<4>{
Face<4> { { 3, 2, 1, 0 } },
Face<4> { { 0, 1, 7, 6 } },
@ -86,8 +113,18 @@ const Solid<3>& octahedron() {
static const auto D = vec3(0, 0, -1);
static const auto E = vec3(1, 0, 0);
static const auto F = vec3(-1, 0, 0);
static const float THIRD = 1.0f / 3.0f;
static const float SEVENTH = 1.0f / 7.0f;
static const Solid<3> OCTAHEDRON = Solid<3>{
{ A, B, C, D, E, F},
{ vec2(2.0f * SEVENTH, THIRD), vec2(SEVENTH, 2.0f * THIRD), vec2(3.0f * SEVENTH, 2.0f * THIRD),
vec2(2.0f * SEVENTH, THIRD), vec2(3.0f * SEVENTH, 2.0f * THIRD), vec2(4.0f * SEVENTH, THIRD),
vec2(5.0f * SEVENTH, 0.0f), vec2(4.0f * SEVENTH, THIRD), vec2(6.0f * SEVENTH, THIRD),
vec2(2.0f * SEVENTH, THIRD), vec2(0.0f, THIRD), vec2(1.0f * SEVENTH, 2.0f * THIRD),
vec2(2.0f * SEVENTH, 1.0f), vec2(3.0f * SEVENTH, 2.0f * THIRD), vec2(1.0f * SEVENTH, 2.0f * THIRD),
vec2(5.0f * SEVENTH, 2.0f * THIRD), vec2(4.0f * SEVENTH, THIRD), vec2(3.0f * SEVENTH, 2.0f * THIRD),
vec2(5.0f * SEVENTH, 2.0f * THIRD), vec2(6.0f * SEVENTH, THIRD), vec2(4.0f * SEVENTH, THIRD),
vec2(5.0f * SEVENTH, 2.0f * THIRD), vec2(1.0f, 2.0f * THIRD), vec2(6.0f * SEVENTH, THIRD) },
FaceVector<3> {
Face<3> { { 0, 2, 4, } },
Face<3> { { 0, 4, 3, } },
@ -116,11 +153,52 @@ const Solid<5>& dodecahedron() {
static const vec3 I = vec3(0, -IP, P);
static const vec3 J = vec3(P, 0, IP);
/* _
/ \ |
/ \ y2
/ \ |
/ \ _
\ / |
\ / y1
\ / |
___________ _
|x3|- - x1 - -||x3|
|- - - - x2- - - -|
*/
// x1, x2, and x3 are the solutions to the following system of equations:
// 1 = 3 * x1 + 3 * x2 + x3
// x1 + 2 * x3 = (golden ratio) * x1
// x2 = x1 + 2 * x3
static const float x1 = 4.0f / (17.0f + 7.0f * sqrtf(5.0f));
static const float x2 = (1.0f / 11.0f) * (5.0f * sqrtf(5.0f) - 9.0f);
static const float x2_2 = x2 / 2.0f;
static const float x3 = (1.0f / 11.0f) * (6.0f * sqrtf(5.0f) - 13.0f);
// y1 and y2 are the solutions to the following system of equations (x is the sidelength, but is different than x1 because the scale in the y direction is different):
// 1 = 3 * y1 + 2 * y2
// y1 = sin(108 deg) * x
// y1 + y2 = x * sqrtf(5 + 2 * sqrtf(5)) / 2
static const float y1 = sqrtf(2.0f * (5.0f + sqrtf(5.0f))) / (sqrtf(2.0f * (5.0f + sqrtf(5.0f))) + 4.0f * sqrtf(5.0f + 2.0f * sqrtf(5.0f)));
static const float y2 = -(sqrtf(2.0f * (5.0f + sqrtf(5.0f))) - 2.0f * sqrtf(5.0f + 2.0f * sqrtf(5.0f))) / (sqrtf(2.0f * (5.0f + sqrtf(5.0f))) + 4.0f * sqrtf(5.0f + 2.0f * sqrtf(5.0f)));
static const Solid<5> DODECAHEDRON = Solid<5>{
{
A, B, C, D, E, F, G, H, I, J,
-A, -B, -C, -D, -E, -F, -G, -H, -I, -J,
},
{ vec2(x1 + x2_2, 0.0f), vec2(x2_2, 0.0f), vec2(x2_2 - x3, y1), vec2(x3 + x1, y1 + y2), vec2(x3 + x1 + x2_2, y1),
vec2(1.0f - (x2 - x3 + x2_2), 0.0f), vec2(1.0f - (x2 + x1 + x3), y2), vec2(1.0f - (x2 + x1), y1 + y2), vec2(1.0f - x2, y1 + y2), vec2(1.0f - (x2 - x3), y2),
vec2(1.0f - x2_2, y1), vec2(1.0f - x2, y1 + y2), vec2(1.0f - (x3 + x1), y1 + y2 + y1), vec2(1.0f - x3, y1 + y2 + y1), vec2(1.0f, y1 + y2),
vec2(x3, y1 + y2), vec2(0.0f, y1 + y2 + y1), vec2(x2_2, y1 + y2 + y1 + y2), vec2(x2, y1 + y2 + y1), vec2(x1 + x3, y1 + y2),
vec2(x3 + x1, y1 + y2), vec2(x2, y1 + y2 + y1), vec2(x2 + x1, y1 + y2 + y1), vec2(x3 + x1 + x2, y1 + y2), vec2(x3 + x1 + x2_2, y1),
vec2(x3 + x1 + x2_2, y1), vec2(x3 + x1 + x2, y1 + y2), vec2(x3 + x1 + x2 + x2_2, y1), vec2(x1 + x2 + x2_2, 0.0f), vec2(x3 + x1 + x2_2 + x3, 0.0f),
vec2(1.0f - (x3 + x1 + x2_2), 1.0f - y1), vec2(1.0f - (x3 + x1 + x2), 1.0f - (y1 + y2)), vec2(1.0f - (x3 + x1 + x2 + x2_2), 1.0f - y1), vec2(1.0f - (x1 + x2 + x2_2), 1.0f), vec2(1.0f - (x3 + x1 + x2_2 + x3), 1.0f),
vec2(x2 + x1 + x3, 1.0f - y2), vec2(x2 + x1, 1.0f - (y1 + y2)), vec2(x2, 1.0f - (y1 + y2)), vec2(x2 - x3, 1.0f - y2), vec2(x2 - x3 + x2_2, 1.0f),
vec2(x2 + x1 + x2, y1 + y2 + y1), vec2(x3 + x1 + x2 + x1, y1 + y2), vec2(x3 + x1 + x2, y1 + y2), vec2(x2 + x1, y1 + y2 + y1), vec2(x2 + x1 + x2_2, y1 + y2 + y1 + y2),
vec2(1.0f - (x3 + x1 + x2), y1 + y2 + y1), vec2(1.0f - (x2 + x1), y1 + y2), vec2(1.0f - (x2 + x1 + x2_2), y1), vec2(1.0f - (x2 + x1 + x2), y1 + y2), vec2(1.0f - (x3 + x1 + x2 + x1), y1 + y2 + y1),
vec2(1.0f - (x3 + x1 + x2_2), y1 + y2 + y1 + y2), vec2(1.0f - (x3 + x1), y1 + y2 + y1), vec2(1.0f - x2, y1 + y2), vec2(1.0f - (x2 + x1), y2 + y1), vec2(1.0f - (x3 + x1 + x2), y1 + y2 + y1),
vec2(1.0f - (x1 + x2_2), 1.0f), vec2(1.0f - x2_2, 1.0f), vec2(1.0f - (x2_2 - x3), 1.0f - y1), vec2(1.0f - (x1 + x3), 1.0f - (y1 + y2)), vec2(1.0f - (x3 + x1 + x2_2), 1.0f - y1) },
FaceVector<5> {
Face<5> { { 0, 1, 2, 3, 4 } },
Face<5> { { 0, 5, 18, 6, 1 } },
@ -148,12 +226,33 @@ const Solid<3>& icosahedron() {
static const auto D = vec3(P, 0, N);
static const auto E = vec3(P, 0, -N);
static const auto F = vec3(0, N, -P);
static const float THIRD = 1.0f / 3.0f;
static const float ELEVENTH = 1.0f / 11.0f;
static const Solid<3> ICOSAHEDRON = Solid<3> {
{
A, B, C, D, E, F,
-A, -B, -C, -D, -E, -F,
},
{ vec2(3.0f * ELEVENTH, 0.0f), vec2(2.0f * ELEVENTH, THIRD), vec2(4.0f * ELEVENTH, THIRD),
vec2(2.0f * ELEVENTH, THIRD), vec2(3.0f * ELEVENTH, 2.0f * THIRD), vec2(4.0f * ELEVENTH, THIRD),
vec2(3.0f * ELEVENTH, 2.0f * THIRD), vec2(5.0f * ELEVENTH, 2.0f * THIRD), vec2(4.0f * ELEVENTH, THIRD),
vec2(5.0f * ELEVENTH, 2.0f * THIRD), vec2(6.0f * ELEVENTH, THIRD), vec2(4.0f * ELEVENTH, THIRD),
vec2(6.0f * ELEVENTH, THIRD), vec2(5.0f * ELEVENTH, 0.0f), vec2(4.0f * ELEVENTH, THIRD),
vec2(1.0f * ELEVENTH, 0.0f), vec2(0.0f, THIRD), vec2(2.0f * ELEVENTH, THIRD),
vec2(1.0f * ELEVENTH, 2.0f * THIRD), vec2(2.0f * ELEVENTH, THIRD), vec2(0.0f, THIRD),
vec2(2.0f * ELEVENTH, THIRD), vec2(1.0f * ELEVENTH, 2.0f * THIRD), vec2(3.0f * ELEVENTH, 2.0f * THIRD),
vec2(2.0f * ELEVENTH, 1.0f), vec2(3.0f * ELEVENTH, 2.0f * THIRD), vec2(1.0f * ELEVENTH, 2.0f * THIRD),
vec2(3.0f * ELEVENTH, 2.0f * THIRD), vec2(4.0f * ELEVENTH, 1.0f), vec2(5.0f * ELEVENTH, 2.0f * THIRD),
vec2(7.0f * ELEVENTH, 2.0f * THIRD), vec2(5.0f * ELEVENTH, 2.0f * THIRD), vec2(6.0f * ELEVENTH, 1.0f),
vec2(5.0f * ELEVENTH, 2.0f * THIRD), vec2(7.0f * ELEVENTH, 2.0f * THIRD), vec2(6.0f * ELEVENTH, THIRD),
vec2(8.0f * ELEVENTH, THIRD), vec2(6.0f * ELEVENTH, THIRD), vec2(7.0f * ELEVENTH, 2.0f * THIRD),
vec2(6.0f * ELEVENTH, THIRD), vec2(8.0f * ELEVENTH, THIRD), vec2(7.0f * ELEVENTH, 0.0f),
vec2(10.0f * ELEVENTH, THIRD), vec2(9.0f * ELEVENTH, 0.0f), vec2(8.0f * ELEVENTH, THIRD),
vec2(7.0f * ELEVENTH, 2.0f * THIRD), vec2(8.0f * ELEVENTH, 1.0f), vec2(9.0f * ELEVENTH, 2.0f * THIRD),
vec2(8.0f * ELEVENTH, THIRD), vec2(7.0f * ELEVENTH, 2.0f * THIRD), vec2(9.0f * ELEVENTH, 2.0f * THIRD),
vec2(10.0f * ELEVENTH, THIRD), vec2(8.0f * ELEVENTH, THIRD), vec2(9.0f * ELEVENTH, 2.0f * THIRD),
vec2(1.0f, 2.0f * THIRD), vec2(10.0f * ELEVENTH, THIRD), vec2(9.0f * ELEVENTH, 2.0f * THIRD),
vec2(10.0f * ELEVENTH, 1.0f), vec2(1.0f, 2.0f * THIRD), vec2(9.0f * ELEVENTH, 2.0f * THIRD) },
FaceVector<3> {
Face<3> { { 1, 2, 0 } },
Face<3> { { 2, 3, 0 } },

View file

@ -22,6 +22,7 @@ namespace geometry {
using Index = uint32_t;
using Vec = glm::vec3;
using VertexVector = std::vector<Vec>;
using TexCoordVector = std::vector<glm::vec2>;
using IndexVector = std::vector<Index>;
template <size_t N>
@ -33,6 +34,7 @@ namespace geometry {
template <size_t N>
struct Solid {
VertexVector vertices;
TexCoordVector texCoords;
FaceVector<N> faces;
Solid<N>& fitDimension(float newMaxDimension) {