This commit is contained in:
SamGondelman 2018-03-16 10:56:56 -07:00
parent 96e48a0162
commit 984a48316d
2 changed files with 45 additions and 111 deletions

View file

@ -135,10 +135,10 @@ static gpu::Stream::FormatPointer SOLID_STREAM_FORMAT;
static gpu::Stream::FormatPointer INSTANCED_SOLID_STREAM_FORMAT; static gpu::Stream::FormatPointer INSTANCED_SOLID_STREAM_FORMAT;
static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT; static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT;
static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 3 + sizeof(glm::vec2); // position, normal, texcoords, tangent static const uint SHAPE_VERTEX_STRIDE = sizeof(GeometryCache::ShapeVertex); // position, normal, texcoords, tangent
static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3); static const uint SHAPE_NORMALS_OFFSET = offsetof(GeometryCache::ShapeVertex, normal);
static const uint SHAPE_TEXCOORD0_OFFSET = sizeof(glm::vec3) * 2; static const uint SHAPE_TEXCOORD0_OFFSET = offsetof(GeometryCache::ShapeVertex, uv);
static const uint SHAPE_TANGENT_OFFSET = sizeof(glm::vec3) * 2 + sizeof(glm::vec2); static const uint SHAPE_TANGENT_OFFSET = offsetof(GeometryCache::ShapeVertex, tangent);
void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) { void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) {
@ -197,22 +197,11 @@ std::vector<vec3> polygon() {
return result; return result;
} }
void addVec3ToVector(std::vector<float>& vertices, glm::vec3 vec) { void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const std::vector<ShapeVertex>& vertices) {
vertices.push_back(vec.x);
vertices.push_back(vec.y);
vertices.push_back(vec.z);
}
void addVec2ToVector(std::vector<float>& vertices, glm::vec2 vec) {
vertices.push_back(vec.x);
vertices.push_back(vec.y);
}
void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const std::vector<float>& vertices) {
gpu::Buffer::Size offset = vertexBuffer->getSize(); gpu::Buffer::Size offset = vertexBuffer->getSize();
vertexBuffer->append(vertices); 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, _positionView = gpu::BufferView(vertexBuffer, offset,
viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT); viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT);
@ -315,14 +304,14 @@ static IndexPair indexToken(geometry::Index a, geometry::Index b) {
template <size_t N> template <size_t N>
void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) { void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
using namespace geometry; using namespace geometry;
std::vector<float> vertices; std::vector<GeometryCache::ShapeVertex> vertices;
IndexVector solidIndices, wireIndices; IndexVector solidIndices, wireIndices;
IndexPairs wireSeenIndices; IndexPairs wireSeenIndices;
size_t faceCount = shape.faces.size(); size_t faceCount = shape.faces.size();
size_t faceIndexCount = triangulatedFaceIndexCount<N>(); size_t faceIndexCount = triangulatedFaceIndexCount<N>();
vertices.reserve(N * faceCount * 2); vertices.reserve(N * faceCount);
solidIndices.reserve(faceIndexCount * faceCount); solidIndices.reserve(faceIndexCount * faceCount);
Index baseVertex = 0; Index baseVertex = 0;
@ -359,10 +348,7 @@ void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N
// Create the vertices for the face // Create the vertices for the face
for (Index i = 0; i < N; i++) { for (Index i = 0; i < N; i++) {
Index originalIndex = face[i]; Index originalIndex = face[i];
addVec3ToVector(vertices, shape.vertices[originalIndex]); vertices.emplace_back(shape.vertices[originalIndex], faceNormal, shape.texCoords[f * N + i], faceTangent);
addVec3ToVector(vertices, faceNormal);
addVec2ToVector(vertices, shape.texCoords[f * N + i]);
addVec3ToVector(vertices, faceTangent);
} }
// Create the wire indices for unseen edges // Create the wire indices for unseen edges
@ -400,8 +386,10 @@ vec2 calculateSphereTexCoord(const vec3& vertex) {
return vec2(u, v); return vec2(u, v);
} }
const float M_PI_TIMES_2 = 2.0f * (float)M_PI;
vec3 calculateSphereTangent(float u) { vec3 calculateSphereTangent(float u) {
float phi = u * (float)M_PI * 2.0f; float phi = u * M_PI_TIMES_2;
return -glm::normalize(glm::vec3(glm::sin(phi), 0.0f, glm::cos(phi))); return -glm::normalize(glm::vec3(glm::sin(phi), 0.0f, glm::cos(phi)));
} }
@ -409,14 +397,11 @@ template <size_t N>
void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) { void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
using namespace geometry; using namespace geometry;
std::vector<float> vertices; std::vector<GeometryCache::ShapeVertex> vertices;
vertices.reserve(shape.vertices.size() * SHAPE_VERTEX_STRIDE / sizeof(float)); vertices.reserve(shape.vertices.size());
for (const auto& vertex : shape.vertices) { for (const auto& vertex : shape.vertices) {
addVec3ToVector(vertices, vertex);
addVec3ToVector(vertices, vertex);
addVec2ToVector(vertices, calculateSphereTexCoord(vertex));
// We'll fill in the correct tangents later, once we correct the UVs // We'll fill in the correct tangents later, once we correct the UVs
addVec3ToVector(vertices, vec3(0.0f)); 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/ // We need to fix up the sphere's UVs because it's actually a tesselated icosahedron. See http://mft-dev.dk/uv-mapping-sphere/
@ -424,9 +409,9 @@ void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid
for (size_t f = 0; f < faceCount; f++) { for (size_t f = 0; f < faceCount; f++) {
// Fix zipper // Fix zipper
{ {
float& u1 = vertices[shape.faces[f][0] * SHAPE_VERTEX_STRIDE / sizeof(float) + SHAPE_TEXCOORD0_OFFSET / sizeof(float)]; float& u1 = vertices[shape.faces[f][0]].uv.x;
float& u2 = vertices[shape.faces[f][1] * SHAPE_VERTEX_STRIDE / sizeof(float) + SHAPE_TEXCOORD0_OFFSET / sizeof(float)]; float& u2 = vertices[shape.faces[f][1]].uv.x;
float& u3 = vertices[shape.faces[f][2] * SHAPE_VERTEX_STRIDE / sizeof(float) + SHAPE_TEXCOORD0_OFFSET / sizeof(float)]; float& u3 = vertices[shape.faces[f][2]].uv.x;
if (glm::isnan(u1)) { if (glm::isnan(u1)) {
u1 = (u2 + u3) / 2.0f; u1 = (u2 + u3) / 2.0f;
@ -461,21 +446,19 @@ void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid
if (shape.vertices[originalIndex].y == 1.0f || shape.vertices[originalIndex].y == -1.0f) { if (shape.vertices[originalIndex].y == 1.0f || shape.vertices[originalIndex].y == -1.0f) {
float uSum = 0.0f; float uSum = 0.0f;
for (Index i2 = 1; i2 <= N - 1; i2++) { for (Index i2 = 1; i2 <= N - 1; i2++) {
float u = vertices[shape.faces[f][(i + i2) % N] * SHAPE_VERTEX_STRIDE / sizeof(float) + SHAPE_TEXCOORD0_OFFSET / sizeof(float)]; float u = vertices[shape.faces[f][(i + i2) % N]].uv.x;
uSum += u; uSum += u;
} }
uSum /= (float)(N - 1); uSum /= (float)(N - 1);
vertices[originalIndex * SHAPE_VERTEX_STRIDE / sizeof(float) + SHAPE_TEXCOORD0_OFFSET / sizeof(float)] = uSum; vertices[originalIndex].uv.x = uSum;
break; break;
} }
} }
// Fill in tangents // Fill in tangents
for (Index i = 0; i < N; i++) { for (Index i = 0; i < N; i++) {
vec3 tangent = calculateSphereTangent(vertices[shape.faces[f][i] * SHAPE_VERTEX_STRIDE / sizeof(float) + SHAPE_TEXCOORD0_OFFSET / sizeof(float)]); vec3 tangent = calculateSphereTangent(vertices[shape.faces[f][i]].uv.x);
vertices[shape.faces[f][i] * SHAPE_VERTEX_STRIDE / sizeof(float) + SHAPE_TANGENT_OFFSET / sizeof(float)] = tangent.x; vertices[shape.faces[f][i]].tangent = tangent;
vertices[shape.faces[f][i] * SHAPE_VERTEX_STRIDE / sizeof(float) + SHAPE_TANGENT_OFFSET / sizeof(float) + 1] = tangent.y;
vertices[shape.faces[f][i] * SHAPE_VERTEX_STRIDE / sizeof(float) + SHAPE_TANGENT_OFFSET / sizeof(float) + 2] = tangent.z;
} }
} }
@ -516,31 +499,22 @@ void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid
template <uint32_t N> template <uint32_t N>
void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer, bool isConical = false) { void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer, bool isConical = false) {
using namespace geometry; using namespace geometry;
std::vector<float> vertices; std::vector<GeometryCache::ShapeVertex> vertices;
IndexVector solidIndices, wireIndices; IndexVector solidIndices, wireIndices;
// Top (if not conical) and bottom faces // Top (if not conical) and bottom faces
std::vector<vec3> shape = polygon<N>(); std::vector<vec3> shape = polygon<N>();
if (isConical) { if (isConical) {
for (uint32_t i = 0; i < N; i++) { for (uint32_t i = 0; i < N; i++) {
addVec3ToVector(vertices, vec3(0.0f, 0.5f, 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));
addVec3ToVector(vertices, vec3(0.0f, 1.0f, 0.0f));
addVec2ToVector(vertices, vec2(i / (float)N, 1.0f));
addVec3ToVector(vertices, vec3(0.0f));
} }
} else { } else {
for (const vec3& v : shape) { for (const vec3& v : shape) {
addVec3ToVector(vertices, vec3(v.x, 0.5f, v.z)); 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));
addVec3ToVector(vertices, vec3(0.0f, 1.0f, 0.0f));
addVec2ToVector(vertices, vec2(v.x, v.z) + vec2(0.5f));
addVec3ToVector(vertices, vec3(1.0f, 0.0f, 0.0f));
} }
} }
for (const vec3& v : shape) { for (const vec3& v : shape) {
addVec3ToVector(vertices, vec3(v.x, -0.5f, v.z)); 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));
addVec3ToVector(vertices, vec3(0.0f, -1.0f, 0.0f));
addVec2ToVector(vertices, vec2(-v.x, v.z) + vec2(0.5f));
addVec3ToVector(vertices, vec3(-1.0f, 0.0f, 0.0f));
} }
Index baseVertex = 0; Index baseVertex = 0;
for (uint32_t i = 2; i < N; i++) { for (uint32_t i = 2; i < N; i++) {
@ -572,25 +546,13 @@ void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& ver
vec3 tangent = glm::normalize(bottomLeft - bottomRight); vec3 tangent = glm::normalize(bottomLeft - bottomRight);
// Our tex coords go in the opposite direction as our vertices // Our tex coords go in the opposite direction as our vertices
float u = 1.0f - i / (float)N; float u = 1.0f - (float)i / (float)N;
float u2 = 1.0f - (i + 1) / (float)N; float u2 = 1.0f - (float)(i + 1) / (float)N;
addVec3ToVector(vertices, topLeft); vertices.emplace_back(topLeft, normal, vec2(u, 0.0f), tangent);
addVec3ToVector(vertices, normal); vertices.emplace_back(bottomLeft, normal, vec2(u, 1.0f), tangent);
addVec2ToVector(vertices, vec2(u, 0.0f)); vertices.emplace_back(topRight, normal, vec2(u2, 0.0f), tangent);
addVec3ToVector(vertices, tangent); vertices.emplace_back(bottomRight, normal, vec2(u2, 1.0f), tangent);
addVec3ToVector(vertices, bottomLeft);
addVec3ToVector(vertices, normal);
addVec2ToVector(vertices, vec2(u, 1.0f));
addVec3ToVector(vertices, tangent);
addVec3ToVector(vertices, topRight);
addVec3ToVector(vertices, normal);
addVec2ToVector(vertices, vec2(u2, 0.0f));
addVec3ToVector(vertices, tangent);
addVec3ToVector(vertices, bottomRight);
addVec3ToVector(vertices, normal);
addVec2ToVector(vertices, vec2(u2, 1.0f));
addVec3ToVector(vertices, tangent);
solidIndices.push_back(baseVertex + 0); solidIndices.push_back(baseVertex + 0);
solidIndices.push_back(baseVertex + 2); solidIndices.push_back(baseVertex + 2);
@ -609,43 +571,6 @@ void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& ver
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices); 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;
std::vector<float> vertices;
IndexVector solidIndices, wireIndices;
const int NUM_CIRCLE_VERTICES = 64;
std::vector<vec3> shape = polygon<NUM_CIRCLE_VERTICES>();
for (const vec3& v : shape) {
addVec3ToVector(vertices, vec3(v.x, 0.0f, v.z));
addVec3ToVector(vertices, vec3(0.0f, 0.0f, 0.0f));
addVec2ToVector(vertices, vec2(v.x, v.z) + vec2(0.5f));
addVec3ToVector(vertices, vec3(1.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 // FIXME solids need per-face vertices, but smooth shaded
// components do not. Find a way to support using draw elements // components do not. Find a way to support using draw elements
// or draw arrays as appropriate // or draw arrays as appropriate
@ -678,9 +603,9 @@ void GeometryCache::buildShapes() {
// Line // Line
{ {
ShapeData& shapeData = _shapes[Line]; ShapeData& shapeData = _shapes[Line];
shapeData.setupVertices(_shapeVertices, std::vector<float> { shapeData.setupVertices(_shapeVertices, std::vector<ShapeVertex> {
-0.5f, 0.0f, 0.0f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 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)),
0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 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; IndexVector wireIndices;
// Only two indices // Only two indices

View file

@ -354,6 +354,15 @@ public:
/// Set a batch to the simple pipeline, returning the previous pipeline /// Set a batch to the simple pipeline, returning the previous pipeline
void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false); 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 { struct ShapeData {
gpu::BufferView _positionView; gpu::BufferView _positionView;
gpu::BufferView _normalView; gpu::BufferView _normalView;
@ -362,7 +371,7 @@ public:
gpu::BufferView _indicesView; gpu::BufferView _indicesView;
gpu::BufferView _wireIndicesView; gpu::BufferView _wireIndicesView;
void setupVertices(gpu::BufferPointer& vertexBuffer, const std::vector<float>& 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 setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices);
void setupBatch(gpu::Batch& batch) const; void setupBatch(gpu::Batch& batch) const;
void draw(gpu::Batch& batch) const; void draw(gpu::Batch& batch) const;