mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:23:54 +02:00
Merge pull request #12588 from SamGondelman/shapeTex
Materials on primitives
This commit is contained in:
commit
2d63afbe28
16 changed files with 388 additions and 254 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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@>
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 } },
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue