mirror of
https://github.com/overte-org/overte.git
synced 2025-04-16 13:56:24 +02:00
Merge pull request #5840 from jherico/bart
Instanced rendering for Box entities
This commit is contained in:
commit
ec87502f49
17 changed files with 1139 additions and 898 deletions
|
@ -16,7 +16,7 @@ var PARTICLE_MAX_SIZE = 2.50;
|
|||
var LIFETIME = 600;
|
||||
var boxes = [];
|
||||
|
||||
var ids = Entities.findEntities({ x: 512, y: 512, z: 512 }, 50);
|
||||
var ids = Entities.findEntities(MyAvatar.position, 50);
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
var id = ids[i];
|
||||
var properties = Entities.getEntityProperties(id);
|
||||
|
@ -33,10 +33,10 @@ for (var x = 0; x < SIDE_SIZE; x++) {
|
|||
var gray = Math.random() * 155;
|
||||
var cube = Math.random() > 0.5;
|
||||
var color = { red: 100 + gray, green: 100 + gray, blue: 100 + gray };
|
||||
var position = { x: 512 + x * 0.2, y: 512 + y * 0.2, z: 512 + z * 0.2};
|
||||
var position = Vec3.sum(MyAvatar.position, { x: x * 0.2, y: y * 0.2, z: z * 0.2});
|
||||
var radius = Math.random() * 0.1;
|
||||
boxes.push(Entities.addEntity({
|
||||
type: cube ? "Box" : "Sphere",
|
||||
type: cube ? "Box" : "Box",
|
||||
name: "PerfTest",
|
||||
position: position,
|
||||
dimensions: { x: radius, y: radius, z: radius },
|
||||
|
|
|
@ -39,9 +39,6 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
|
|||
PerformanceTimer perfTimer("RenderableBoxEntityItem::render");
|
||||
Q_ASSERT(getType() == EntityTypes::Box);
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well
|
||||
glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
|
||||
if (!_procedural) {
|
||||
_procedural.reset(new Procedural(this->getUserData()));
|
||||
|
@ -54,11 +51,15 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
|
|||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
}
|
||||
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
|
||||
if (_procedural->ready()) {
|
||||
batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well
|
||||
_procedural->prepare(batch, this->getDimensions());
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(batch, 1.0f, _procedural->getColor(cubeColor));
|
||||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(batch, 1.0f, cubeColor);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCubeInstance(batch, getTransformToCenter(), cubeColor);
|
||||
}
|
||||
|
||||
RenderableDebugableEntityItem::render(this, args);
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include <string.h>
|
||||
|
||||
#include "Batch.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(NSIGHT_FOUND)
|
||||
#include "nvToolsExt.h"
|
||||
|
||||
|
@ -302,4 +302,28 @@ void Batch::enableSkybox(bool enable) {
|
|||
|
||||
bool Batch::isSkyboxEnabled() const {
|
||||
return _enableSkybox;
|
||||
}
|
||||
}
|
||||
|
||||
void Batch::setupNamedCalls(const std::string& instanceName, NamedBatchData::Function function) {
|
||||
NamedBatchData& instance = _namedData[instanceName];
|
||||
++instance._count;
|
||||
instance._function = function;
|
||||
}
|
||||
|
||||
BufferPointer Batch::getNamedBuffer(const std::string& instanceName, uint8_t index) {
|
||||
NamedBatchData& instance = _namedData[instanceName];
|
||||
if (instance._buffers.size() <= index) {
|
||||
instance._buffers.resize(index + 1);
|
||||
}
|
||||
if (!instance._buffers[index]) {
|
||||
instance._buffers[index].reset(new Buffer());
|
||||
}
|
||||
return instance._buffers[index];
|
||||
}
|
||||
|
||||
void Batch::preExecute() {
|
||||
for (auto& mapItem : _namedData) {
|
||||
mapItem.second.process(*this);
|
||||
}
|
||||
_namedData.clear();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#define hifi_gpu_Batch_h
|
||||
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <functional>
|
||||
|
||||
#include "Framebuffer.h"
|
||||
#include "Pipeline.h"
|
||||
|
@ -38,16 +40,42 @@ enum ReservedSlot {
|
|||
TRANSFORM_CAMERA_SLOT = 7,
|
||||
};
|
||||
|
||||
// The named batch data provides a mechanism for accumulating data into buffers over the course
|
||||
// of many independent calls. For instance, two objects in the scene might both want to render
|
||||
// a simple box, but are otherwise unaware of each other. The common code that they call to render
|
||||
// the box can create buffers to store the rendering parameters for each box and register a function
|
||||
// that will be called with the accumulated buffer data when the batch commands are finally
|
||||
// executed against the backend
|
||||
|
||||
|
||||
class Batch {
|
||||
public:
|
||||
typedef Stream::Slot Slot;
|
||||
|
||||
struct NamedBatchData {
|
||||
using BufferPointers = std::vector<BufferPointer>;
|
||||
using Function = std::function<void(gpu::Batch&, NamedBatchData&)>;
|
||||
|
||||
std::once_flag _once;
|
||||
BufferPointers _buffers;
|
||||
size_t _count{ 0 };
|
||||
Function _function;
|
||||
|
||||
void process(Batch& batch) {
|
||||
_function(batch, *this);
|
||||
}
|
||||
};
|
||||
|
||||
using NamedBatchDataMap = std::map<std::string, NamedBatchData>;
|
||||
|
||||
Batch();
|
||||
explicit Batch(const Batch& batch);
|
||||
~Batch();
|
||||
|
||||
void clear();
|
||||
|
||||
void preExecute();
|
||||
|
||||
// Batches may need to override the context level stereo settings
|
||||
// if they're performing framebuffer copy operations, like the
|
||||
// deferred lighting resolution mechanism
|
||||
|
@ -67,6 +95,12 @@ public:
|
|||
void drawInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbVertices, uint32 startVertex = 0, uint32 startInstance = 0);
|
||||
void drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbIndices, uint32 startIndex = 0, uint32 startInstance = 0);
|
||||
|
||||
|
||||
void setupNamedCalls(const std::string& instanceName, NamedBatchData::Function function);
|
||||
BufferPointer getNamedBuffer(const std::string& instanceName, uint8_t index = 0);
|
||||
|
||||
|
||||
|
||||
// Input Stage
|
||||
// InputFormat
|
||||
// InputBuffers
|
||||
|
@ -291,6 +325,8 @@ public:
|
|||
FramebufferCaches _framebuffers;
|
||||
QueryCaches _queries;
|
||||
|
||||
NamedBatchDataMap _namedData;
|
||||
|
||||
bool _enableStereo{ true };
|
||||
bool _enableSkybox{ false };
|
||||
|
||||
|
|
|
@ -120,6 +120,18 @@ enum Dimension {
|
|||
MAT4,
|
||||
NUM_DIMENSIONS,
|
||||
};
|
||||
|
||||
// Count (of scalars) in an Element for a given Dimension
|
||||
static const int LOCATION_COUNT[NUM_DIMENSIONS] = {
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
3,
|
||||
4,
|
||||
};
|
||||
|
||||
// Count (of scalars) in an Element for a given Dimension
|
||||
static const int DIMENSION_COUNT[NUM_DIMENSIONS] = {
|
||||
1,
|
||||
|
@ -127,8 +139,8 @@ static const int DIMENSION_COUNT[NUM_DIMENSIONS] = {
|
|||
3,
|
||||
4,
|
||||
4,
|
||||
9,
|
||||
16,
|
||||
3,
|
||||
4,
|
||||
};
|
||||
|
||||
// Semantic of an Element
|
||||
|
@ -184,6 +196,7 @@ public:
|
|||
|
||||
Dimension getDimension() const { return (Dimension)_dimension; }
|
||||
uint8 getDimensionCount() const { return DIMENSION_COUNT[(Dimension)_dimension]; }
|
||||
uint8 getLocationCount() const { return LOCATION_COUNT[(Dimension)_dimension]; }
|
||||
|
||||
Type getType() const { return (Type)_type; }
|
||||
bool isNormalized() const { return (getType() >= NFLOAT); }
|
||||
|
|
|
@ -191,6 +191,9 @@ void GLBackend::renderPassDraw(Batch& batch) {
|
|||
}
|
||||
|
||||
void GLBackend::render(Batch& batch) {
|
||||
// Finalize the batch by moving all the instanced rendering into the command buffer
|
||||
batch.preExecute();
|
||||
|
||||
_stereo._skybox = batch.isSkyboxEnabled();
|
||||
// Allow the batch to override the rendering stereo settings
|
||||
// for things like full framebuffer copy operations (deferred lighting passes)
|
||||
|
@ -316,7 +319,19 @@ void GLBackend::do_drawInstanced(Batch& batch, uint32 paramOffset) {
|
|||
}
|
||||
|
||||
void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) {
|
||||
(void) CHECK_GL_ERROR();
|
||||
updateInput();
|
||||
updateTransform();
|
||||
updatePipeline();
|
||||
|
||||
GLint numInstances = batch._params[paramOffset + 4]._uint;
|
||||
GLenum mode = _primitiveToGLmode[(Primitive)batch._params[paramOffset + 3]._uint];
|
||||
uint32 numIndices = batch._params[paramOffset + 2]._uint;
|
||||
uint32 startIndex = batch._params[paramOffset + 1]._uint;
|
||||
uint32 startInstance = batch._params[paramOffset + 0]._uint;
|
||||
GLenum glType = _elementTypeToGLType[_input._indexBufferType];
|
||||
|
||||
glDrawElementsInstanced(mode, numIndices, glType, nullptr, numInstances);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_resetStages(Batch& batch, uint32 paramOffset) {
|
||||
|
|
|
@ -160,7 +160,10 @@ void GLBackend::updateInput() {
|
|||
if (_input._format) {
|
||||
for (auto& it : _input._format->getAttributes()) {
|
||||
const Stream::Attribute& attrib = (it).second;
|
||||
newActivation.set(attrib._slot);
|
||||
uint8_t locationCount = attrib._element.getLocationCount();
|
||||
for (int i = 0; i < locationCount; ++i) {
|
||||
newActivation.set(attrib._slot + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,14 +214,19 @@ void GLBackend::updateInput() {
|
|||
const Stream::Attribute& attrib = attributes.at(channel._slots[i]);
|
||||
GLuint slot = attrib._slot;
|
||||
GLuint count = attrib._element.getDimensionCount();
|
||||
uint8_t locationCount = attrib._element.getLocationCount();
|
||||
GLenum type = _elementTypeToGLType[attrib._element.getType()];
|
||||
GLuint stride = strides[bufferNum];
|
||||
GLenum perLocationStride = strides[bufferNum];
|
||||
GLuint stride = perLocationStride * locationCount;
|
||||
GLuint pointer = attrib._offset + offsets[bufferNum];
|
||||
GLboolean isNormalized = attrib._element.isNormalized();
|
||||
|
||||
glVertexAttribPointer(slot, count, type, isNormalized, stride,
|
||||
reinterpret_cast<GLvoid*>(pointer));
|
||||
|
||||
for (int j = 0; j < locationCount; ++j) {
|
||||
glVertexAttribPointer(slot + j, count, type, isNormalized, stride,
|
||||
reinterpret_cast<GLvoid*>(pointer + perLocationStride * j));
|
||||
glVertexAttribDivisor(slot + j, attrib._frequency);
|
||||
}
|
||||
|
||||
// TODO: Support properly the IAttrib version
|
||||
|
||||
(void) CHECK_GL_ERROR();
|
||||
|
|
|
@ -75,6 +75,11 @@ void makeBindings(GLBackend::GLShader* shader) {
|
|||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "inInstanceTransform");
|
||||
if (loc >= 0 && loc != gpu::Stream::INSTANCE_XFM) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::INSTANCE_XFM, "inInstanceTransform");
|
||||
}
|
||||
|
||||
// Link again to take into account the assigned attrib location
|
||||
glLinkProgram(glprogram);
|
||||
|
||||
|
|
|
@ -18,4 +18,5 @@ in vec4 inTangent;
|
|||
in vec4 inSkinClusterIndex;
|
||||
in vec4 inSkinClusterWeight;
|
||||
in vec4 inTexCoord1;
|
||||
in mat4 inInstanceTransform;
|
||||
<@endif@>
|
||||
|
|
|
@ -139,6 +139,11 @@ public:
|
|||
// \return the number of bytes copied
|
||||
Size append(Size size, const Byte* data);
|
||||
|
||||
template <typename T>
|
||||
Size append(const T& t) {
|
||||
return append(sizeof(t), reinterpret_cast<const Byte*>(&t));
|
||||
}
|
||||
|
||||
// Access the sysmem object.
|
||||
const Sysmem& getSysmem() const { assert(_sysmem); return (*_sysmem); }
|
||||
Sysmem& editSysmem() { assert(_sysmem); return (*_sysmem); }
|
||||
|
|
|
@ -35,11 +35,12 @@ public:
|
|||
SKIN_CLUSTER_INDEX = 5,
|
||||
SKIN_CLUSTER_WEIGHT = 6,
|
||||
TEXCOORD1 = 7,
|
||||
INSTANCE_XFM = 8,
|
||||
INSTANCE_SCALE = 9,
|
||||
INSTANCE_TRANSLATE = 10,
|
||||
INSTANCE_SCALE = 8,
|
||||
INSTANCE_TRANSLATE = 9,
|
||||
INSTANCE_XFM = 10,
|
||||
|
||||
NUM_INPUT_SLOTS,
|
||||
// Instance XFM is a mat4, and as such takes up 4 slots
|
||||
NUM_INPUT_SLOTS = INSTANCE_XFM + 4,
|
||||
};
|
||||
|
||||
typedef uint8 Slot;
|
||||
|
|
|
@ -53,6 +53,15 @@ TransformCamera getTransformCamera() {
|
|||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func transformInstancedModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@>
|
||||
<!// Equivalent to the following but hoppefully a tad more accurate
|
||||
//return camera._projection * camera._view * object._model * pos; !>
|
||||
{ // transformModelToClipPos
|
||||
vec4 _eyepos = (inInstanceTransform * <$modelPos$>) + vec4(-<$modelPos$>.w * <$cameraTransform$>._viewInverse[3].xyz, 0.0);
|
||||
<$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos;
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func $transformModelToEyeAndClipPos(cameraTransform, objectTransform, modelPos, eyePos, clipPos)@>
|
||||
<!// Equivalent to the following but hoppefully a tad more accurate
|
||||
//return camera._projection * camera._view * object._model * pos; !>
|
||||
|
@ -65,12 +74,31 @@ TransformCamera getTransformCamera() {
|
|||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func $transformInstancedModelToEyeAndClipPos(cameraTransform, objectTransform, modelPos, eyePos, clipPos)@>
|
||||
<!// Equivalent to the following but hoppefully a tad more accurate
|
||||
//return camera._projection * camera._view * object._model * pos; !>
|
||||
{ // transformModelToClipPos
|
||||
vec4 _worldpos = (inInstanceTransform * <$modelPos$>);
|
||||
<$eyePos$> = (<$cameraTransform$>._view * _worldpos);
|
||||
vec4 _eyepos =(inInstanceTransform * <$modelPos$>) + vec4(-<$modelPos$>.w * <$cameraTransform$>._viewInverse[3].xyz, 0.0);
|
||||
<$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos;
|
||||
// <$eyePos$> = (<$cameraTransform$>._projectionInverse * <$clipPos$>);
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
|
||||
<@func transformModelToWorldPos(objectTransform, modelPos, worldPos)@>
|
||||
{ // transformModelToWorldPos
|
||||
<$worldPos$> = (<$objectTransform$>._model * <$modelPos$>);
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func transformInstancedModelToWorldPos(objectTransform, modelPos, worldPos)@>
|
||||
{ // transformModelToWorldPos
|
||||
<$worldPos$> = (inInstanceTransform * <$modelPos$>);
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func transformModelToEyeDir(cameraTransform, objectTransform, modelDir, eyeDir)@>
|
||||
{ // transformModelToEyeDir
|
||||
vec3 mr0 = vec3(<$objectTransform$>._modelInverse[0].x, <$objectTransform$>._modelInverse[1].x, <$objectTransform$>._modelInverse[2].x);
|
||||
|
@ -85,6 +113,21 @@ TransformCamera getTransformCamera() {
|
|||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func transformInstancedModelToEyeDir(cameraTransform, objectTransform, modelDir, eyeDir)@>
|
||||
{ // transformModelToEyeDir
|
||||
mat4 modelInverse = inverse(inInstanceTransform);
|
||||
vec3 mr0 = vec3(modelInverse[0].x, modelInverse[1].x, modelInverse[2].x);
|
||||
vec3 mr1 = vec3(modelInverse[0].y, modelInverse[1].y, modelInverse[2].y);
|
||||
vec3 mr2 = vec3(modelInverse[0].z, modelInverse[1].z, modelInverse[2].z);
|
||||
|
||||
vec3 mvc0 = vec3(dot(<$cameraTransform$>._viewInverse[0].xyz, mr0), dot(<$cameraTransform$>._viewInverse[0].xyz, mr1), dot(<$cameraTransform$>._viewInverse[0].xyz, mr2));
|
||||
vec3 mvc1 = vec3(dot(<$cameraTransform$>._viewInverse[1].xyz, mr0), dot(<$cameraTransform$>._viewInverse[1].xyz, mr1), dot(<$cameraTransform$>._viewInverse[1].xyz, mr2));
|
||||
vec3 mvc2 = vec3(dot(<$cameraTransform$>._viewInverse[2].xyz, mr0), dot(<$cameraTransform$>._viewInverse[2].xyz, mr1), dot(<$cameraTransform$>._viewInverse[2].xyz, mr2));
|
||||
|
||||
<$eyeDir$> = vec3(dot(mvc0, <$modelDir$>), dot(mvc1, <$modelDir$>), dot(mvc2, <$modelDir$>));
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func transformEyeToWorldDir(cameraTransform, eyeDir, worldDir)@>
|
||||
{ // transformEyeToWorldDir
|
||||
<$worldDir$> = vec3(<$cameraTransform$>._viewInverse * vec4(<$eyeDir$>.xyz, 0.0));
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,15 +37,22 @@ public:
|
|||
void init(AbstractViewStateInterface* viewState);
|
||||
|
||||
/// Sets up the state necessary to render static untextured geometry with the simple program.
|
||||
void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true,
|
||||
gpu::PipelinePointer bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true,
|
||||
bool emmisive = false, bool depthBias = false);
|
||||
|
||||
/// Sets up the state necessary to render static untextured geometry with the simple program.
|
||||
void bindInstanceProgram(gpu::Batch& batch, bool textured = false, bool culled = true,
|
||||
bool emmisive = false, bool depthBias = false);
|
||||
|
||||
//// Renders a solid sphere with the simple program.
|
||||
void renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color);
|
||||
|
||||
//// Renders a wireframe sphere with the simple program.
|
||||
void renderWireSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color);
|
||||
|
||||
//// Renders a solid cube using instancing. Transform should include scaling.
|
||||
void renderSolidCubeInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color);
|
||||
|
||||
//// Renders a solid cube with the simple program.
|
||||
void renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color);
|
||||
|
||||
|
|
|
@ -689,28 +689,31 @@ void GeometryCache::renderVertices(gpu::Batch& batch, gpu::Primitive primitiveTy
|
|||
}
|
||||
}
|
||||
|
||||
void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color) {
|
||||
Vec2Pair colorKey(glm::vec2(color.x, color.y), glm::vec2(color.z, color.y));
|
||||
const int FLOATS_PER_VERTEX = 3;
|
||||
const int VERTICES_PER_FACE = 4;
|
||||
const int NUMBER_OF_FACES = 6;
|
||||
const int TRIANGLES_PER_FACE = 2;
|
||||
const int VERTICES_PER_TRIANGLE = 3;
|
||||
const int vertices = NUMBER_OF_FACES * VERTICES_PER_FACE;
|
||||
const int indices = NUMBER_OF_FACES * TRIANGLES_PER_FACE * VERTICES_PER_TRIANGLE;
|
||||
const int vertexPoints = vertices * FLOATS_PER_VERTEX;
|
||||
const int VERTEX_STRIDE = sizeof(GLfloat) * FLOATS_PER_VERTEX * 2; // vertices and normals
|
||||
const int NORMALS_OFFSET = sizeof(GLfloat) * FLOATS_PER_VERTEX;
|
||||
static const int FLOATS_PER_VERTEX = 3;
|
||||
static const int VERTICES_PER_TRIANGLE = 3;
|
||||
|
||||
static const int CUBE_NUMBER_OF_FACES = 6;
|
||||
static const int CUBE_VERTICES_PER_FACE = 4;
|
||||
static const int CUBE_TRIANGLES_PER_FACE = 2;
|
||||
static const int CUBE_VERTICES = CUBE_NUMBER_OF_FACES * CUBE_VERTICES_PER_FACE;
|
||||
static const int CUBE_VERTEX_POINTS = CUBE_VERTICES * FLOATS_PER_VERTEX;
|
||||
static const int CUBE_INDICES = CUBE_NUMBER_OF_FACES * CUBE_TRIANGLES_PER_FACE * VERTICES_PER_TRIANGLE;
|
||||
|
||||
static const gpu::Element CUBE_POSITION_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ };
|
||||
static const gpu::Element CUBE_NORMAL_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ };
|
||||
static const gpu::Element CUBE_COLOR_ELEMENT{ gpu::VEC4, gpu::NUINT8, gpu::RGBA };
|
||||
static const gpu::Element INSTANCE_XFM_ELEMENT{ gpu::MAT4, gpu::FLOAT, gpu::XYZW };
|
||||
|
||||
gpu::BufferPointer GeometryCache::getCubeVertices(float size) {
|
||||
if (!_solidCubeVertices.contains(size)) {
|
||||
auto verticesBuffer = std::make_shared<gpu::Buffer>();
|
||||
_solidCubeVertices[size] = verticesBuffer;
|
||||
|
||||
GLfloat* vertexData = new GLfloat[vertexPoints * 2]; // vertices and normals
|
||||
GLfloat* vertexData = new GLfloat[CUBE_VERTEX_POINTS * 2]; // vertices and normals
|
||||
GLfloat* vertex = vertexData;
|
||||
float halfSize = size / 2.0f;
|
||||
|
||||
static GLfloat cannonicalVertices[vertexPoints] =
|
||||
static GLfloat cannonicalVertices[CUBE_VERTEX_POINTS] =
|
||||
{ 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0,v1,v2,v3 (front)
|
||||
1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0,v3,v4,v5 (right)
|
||||
1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0,v5,v6,v1 (top)
|
||||
|
@ -719,7 +722,7 @@ void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::ve
|
|||
1,-1,-1, -1,-1,-1, -1, 1,-1, 1, 1,-1 }; // v4,v7,v6,v5 (back)
|
||||
|
||||
// normal array
|
||||
static GLfloat cannonicalNormals[vertexPoints] =
|
||||
static GLfloat cannonicalNormals[CUBE_VERTEX_POINTS] =
|
||||
{ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0,v1,v2,v3 (front)
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0,v3,v4,v5 (right)
|
||||
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0,v5,v6,v1 (top)
|
||||
|
@ -731,7 +734,7 @@ void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::ve
|
|||
GLfloat* cannonicalVertex = &cannonicalVertices[0];
|
||||
GLfloat* cannonicalNormal = &cannonicalNormals[0];
|
||||
|
||||
for (int i = 0; i < vertices; i++) {
|
||||
for (int i = 0; i < CUBE_VERTICES; i++) {
|
||||
// vertices
|
||||
*(vertex++) = halfSize * *cannonicalVertex++;
|
||||
*(vertex++) = halfSize * *cannonicalVertex++;
|
||||
|
@ -742,90 +745,121 @@ void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::ve
|
|||
*(vertex++) = *cannonicalNormal++;
|
||||
*(vertex++) = *cannonicalNormal++;
|
||||
}
|
||||
|
||||
verticesBuffer->append(sizeof(GLfloat) * vertexPoints * 2, (gpu::Byte*) vertexData);
|
||||
verticesBuffer->append(sizeof(GLfloat) * CUBE_VERTEX_POINTS * 2, (gpu::Byte*) vertexData);
|
||||
}
|
||||
|
||||
return _solidCubeVertices[size];
|
||||
}
|
||||
|
||||
gpu::BufferPointer GeometryCache::getSolidCubeIndices() {
|
||||
if (!_solidCubeIndexBuffer) {
|
||||
static GLubyte cannonicalIndices[indices] =
|
||||
{ 0, 1, 2, 2, 3, 0, // front
|
||||
static GLubyte cannonicalIndices[CUBE_INDICES] = { 0, 1, 2, 2, 3, 0, // front
|
||||
4, 5, 6, 6, 7, 4, // right
|
||||
8, 9,10, 10,11, 8, // top
|
||||
12,13,14, 14,15,12, // left
|
||||
16,17,18, 18,19,16, // bottom
|
||||
20,21,22, 22,23,20 }; // back
|
||||
|
||||
|
||||
auto indexBuffer = std::make_shared<gpu::Buffer>();
|
||||
_solidCubeIndexBuffer = indexBuffer;
|
||||
|
||||
|
||||
_solidCubeIndexBuffer->append(sizeof(cannonicalIndices), (gpu::Byte*) cannonicalIndices);
|
||||
}
|
||||
return _solidCubeIndexBuffer;
|
||||
}
|
||||
|
||||
|
||||
void GeometryCache::setupCubeVertices(gpu::Batch& batch, gpu::BufferPointer& verticesBuffer) {
|
||||
static const int VERTEX_STRIDE = sizeof(GLfloat) * FLOATS_PER_VERTEX * 2; // vertices and normals
|
||||
static const int NORMALS_OFFSET = sizeof(GLfloat) * FLOATS_PER_VERTEX;
|
||||
|
||||
gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), VERTEX_STRIDE, CUBE_POSITION_ELEMENT);
|
||||
gpu::BufferView normalsView(verticesBuffer, NORMALS_OFFSET, verticesBuffer->getSize(), VERTEX_STRIDE, CUBE_NORMAL_ELEMENT);
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, verticesView);
|
||||
batch.setInputBuffer(gpu::Stream::NORMAL, normalsView);
|
||||
}
|
||||
|
||||
void GeometryCache::renderSolidCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer) {
|
||||
static gpu::Stream::FormatPointer streamFormat;
|
||||
if (!streamFormat) {
|
||||
streamFormat = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
||||
streamFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, CUBE_POSITION_ELEMENT, 0);
|
||||
streamFormat->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, CUBE_NORMAL_ELEMENT);
|
||||
streamFormat->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, CUBE_COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
|
||||
streamFormat->setAttribute(gpu::Stream::INSTANCE_XFM, gpu::Stream::INSTANCE_XFM, INSTANCE_XFM_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
|
||||
}
|
||||
batch.setInputFormat(streamFormat);
|
||||
|
||||
gpu::BufferView colorView(colorBuffer, CUBE_COLOR_ELEMENT);
|
||||
batch.setInputBuffer(gpu::Stream::COLOR, colorView);
|
||||
|
||||
gpu::BufferView instanceXfmView(transformBuffer, 0, transformBuffer->getSize(), INSTANCE_XFM_ELEMENT);
|
||||
batch.setInputBuffer(gpu::Stream::INSTANCE_XFM, instanceXfmView);
|
||||
|
||||
gpu::BufferPointer verticesBuffer = getCubeVertices(1.0);
|
||||
setupCubeVertices(batch, verticesBuffer);
|
||||
batch.setIndexBuffer(gpu::UINT8, getSolidCubeIndices(), 0);
|
||||
batch.drawIndexedInstanced(count, gpu::TRIANGLES, CUBE_INDICES);
|
||||
}
|
||||
|
||||
|
||||
void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color) {
|
||||
Vec2Pair colorKey(glm::vec2(color.x, color.y), glm::vec2(color.z, color.y));
|
||||
if (!_solidCubeColors.contains(colorKey)) {
|
||||
auto colorBuffer = std::make_shared<gpu::Buffer>();
|
||||
_solidCubeColors[colorKey] = colorBuffer;
|
||||
|
||||
const int NUM_COLOR_SCALARS_PER_CUBE = 24;
|
||||
int compactColor = ((int(color.x * 255.0f) & 0xFF)) |
|
||||
((int(color.y * 255.0f) & 0xFF) << 8) |
|
||||
((int(color.z * 255.0f) & 0xFF) << 16) |
|
||||
((int(color.w * 255.0f) & 0xFF) << 24);
|
||||
int colors[NUM_COLOR_SCALARS_PER_CUBE] = { compactColor, compactColor, compactColor, compactColor,
|
||||
compactColor, compactColor, compactColor, compactColor,
|
||||
compactColor, compactColor, compactColor, compactColor,
|
||||
compactColor, compactColor, compactColor, compactColor,
|
||||
compactColor, compactColor, compactColor, compactColor,
|
||||
compactColor, compactColor, compactColor, compactColor };
|
||||
|
||||
int colors[CUBE_VERTICES] = {
|
||||
compactColor, compactColor, compactColor, compactColor,
|
||||
compactColor, compactColor, compactColor, compactColor,
|
||||
compactColor, compactColor, compactColor, compactColor,
|
||||
compactColor, compactColor, compactColor, compactColor,
|
||||
compactColor, compactColor, compactColor, compactColor,
|
||||
compactColor, compactColor, compactColor, compactColor
|
||||
};
|
||||
colorBuffer->append(sizeof(colors), (gpu::Byte*) colors);
|
||||
}
|
||||
gpu::BufferPointer verticesBuffer = _solidCubeVertices[size];
|
||||
gpu::BufferPointer colorBuffer = _solidCubeColors[colorKey];
|
||||
|
||||
const int VERTICES_SLOT = 0;
|
||||
const int NORMALS_SLOT = 1;
|
||||
const int COLOR_SLOT = 2;
|
||||
static gpu::Stream::FormatPointer streamFormat;
|
||||
static gpu::Element positionElement, normalElement, colorElement;
|
||||
if (!streamFormat) {
|
||||
streamFormat = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
||||
streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||
streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
||||
positionElement = streamFormat->getAttributes().at(gpu::Stream::POSITION)._element;
|
||||
normalElement = streamFormat->getAttributes().at(gpu::Stream::NORMAL)._element;
|
||||
colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element;
|
||||
streamFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, CUBE_POSITION_ELEMENT, 0);
|
||||
streamFormat->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, CUBE_NORMAL_ELEMENT);
|
||||
streamFormat->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, CUBE_COLOR_ELEMENT);
|
||||
}
|
||||
|
||||
|
||||
gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), VERTEX_STRIDE, positionElement);
|
||||
gpu::BufferView normalsView(verticesBuffer, NORMALS_OFFSET, verticesBuffer->getSize(), VERTEX_STRIDE, normalElement);
|
||||
gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);
|
||||
|
||||
batch.setInputFormat(streamFormat);
|
||||
batch.setInputBuffer(VERTICES_SLOT, verticesView);
|
||||
batch.setInputBuffer(NORMALS_SLOT, normalsView);
|
||||
batch.setInputBuffer(COLOR_SLOT, colorView);
|
||||
batch.setIndexBuffer(gpu::UINT8, _solidCubeIndexBuffer, 0);
|
||||
batch.drawIndexed(gpu::TRIANGLES, indices);
|
||||
|
||||
gpu::BufferView colorView(colorBuffer, CUBE_COLOR_ELEMENT);
|
||||
batch.setInputBuffer(gpu::Stream::COLOR, colorView);
|
||||
|
||||
gpu::BufferPointer verticesBuffer = getCubeVertices(size);
|
||||
setupCubeVertices(batch, verticesBuffer);
|
||||
|
||||
batch.setIndexBuffer(gpu::UINT8, getSolidCubeIndices(), 0);
|
||||
batch.drawIndexed(gpu::TRIANGLES, CUBE_INDICES);
|
||||
}
|
||||
|
||||
|
||||
void GeometryCache::renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color) {
|
||||
Vec2Pair colorKey(glm::vec2(color.x, color.y),glm::vec2(color.z, color.y));
|
||||
const int FLOATS_PER_VERTEX = 3;
|
||||
const int VERTICES_PER_EDGE = 2;
|
||||
const int TOP_EDGES = 4;
|
||||
const int BOTTOM_EDGES = 4;
|
||||
const int SIDE_EDGES = 4;
|
||||
const int vertices = 8;
|
||||
const int indices = (TOP_EDGES + BOTTOM_EDGES + SIDE_EDGES) * VERTICES_PER_EDGE;
|
||||
static const int WIRE_CUBE_VERTICES_PER_EDGE = 2;
|
||||
static const int WIRE_CUBE_TOP_EDGES = 4;
|
||||
static const int WIRE_CUBE_BOTTOM_EDGES = 4;
|
||||
static const int WIRE_CUBE_SIDE_EDGES = 4;
|
||||
static const int WIRE_CUBE_VERTICES = 8;
|
||||
static const int WIRE_CUBE_INDICES = (WIRE_CUBE_TOP_EDGES + WIRE_CUBE_BOTTOM_EDGES + WIRE_CUBE_SIDE_EDGES) * WIRE_CUBE_VERTICES_PER_EDGE;
|
||||
|
||||
if (!_cubeVerticies.contains(size)) {
|
||||
auto verticesBuffer = std::make_shared<gpu::Buffer>();
|
||||
_cubeVerticies[size] = verticesBuffer;
|
||||
|
||||
int vertexPoints = vertices * FLOATS_PER_VERTEX;
|
||||
GLfloat* vertexData = new GLfloat[vertexPoints]; // only vertices, no normals because we're a wire cube
|
||||
static const int WIRE_CUBE_VERTEX_POINTS = WIRE_CUBE_VERTICES * FLOATS_PER_VERTEX;
|
||||
GLfloat* vertexData = new GLfloat[WIRE_CUBE_VERTEX_POINTS]; // only vertices, no normals because we're a wire cube
|
||||
GLfloat* vertex = vertexData;
|
||||
float halfSize = size / 2.0f;
|
||||
|
||||
|
@ -834,15 +868,15 @@ void GeometryCache::renderWireCube(gpu::Batch& batch, float size, const glm::vec
|
|||
1,-1, 1, 1,-1,-1, -1,-1,-1, -1,-1, 1 // v4, v5, v6, v7 (bottom)
|
||||
};
|
||||
|
||||
for (int i = 0; i < vertexPoints; i++) {
|
||||
for (int i = 0; i < WIRE_CUBE_VERTEX_POINTS; i++) {
|
||||
vertex[i] = cannonicalVertices[i] * halfSize;
|
||||
}
|
||||
|
||||
verticesBuffer->append(sizeof(GLfloat) * vertexPoints, (gpu::Byte*) vertexData); // I'm skeptical that this is right
|
||||
verticesBuffer->append(sizeof(GLfloat) * WIRE_CUBE_VERTEX_POINTS, (gpu::Byte*) vertexData); // I'm skeptical that this is right
|
||||
}
|
||||
|
||||
if (!_wireCubeIndexBuffer) {
|
||||
static GLubyte cannonicalIndices[indices] = {
|
||||
static GLubyte cannonicalIndices[WIRE_CUBE_INDICES] = {
|
||||
0, 1, 1, 2, 2, 3, 3, 0, // (top)
|
||||
4, 5, 5, 6, 6, 7, 7, 4, // (bottom)
|
||||
0, 4, 1, 5, 2, 6, 3, 7, // (side edges)
|
||||
|
@ -890,7 +924,7 @@ void GeometryCache::renderWireCube(gpu::Batch& batch, float size, const glm::vec
|
|||
batch.setInputBuffer(VERTICES_SLOT, verticesView);
|
||||
batch.setInputBuffer(COLOR_SLOT, colorView);
|
||||
batch.setIndexBuffer(gpu::UINT8, _wireCubeIndexBuffer, 0);
|
||||
batch.drawIndexed(gpu::LINES, indices);
|
||||
batch.drawIndexed(gpu::LINES, WIRE_CUBE_INDICES);
|
||||
}
|
||||
|
||||
void GeometryCache::renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id) {
|
||||
|
|
|
@ -131,6 +131,11 @@ public:
|
|||
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||
bool delayLoad, const void* extra);
|
||||
|
||||
gpu::BufferPointer getCubeVertices(float size);
|
||||
void setupCubeVertices(gpu::Batch& batch, gpu::BufferPointer& verticesBuffer);
|
||||
|
||||
gpu::BufferPointer getSolidCubeIndices();
|
||||
|
||||
void renderSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec3& color, bool solid = true, int id = UNKNOWN_ID)
|
||||
{ renderSphere(batch, radius, slices, stacks, glm::vec4(color, 1.0f), solid, id); }
|
||||
|
||||
|
@ -139,6 +144,7 @@ public:
|
|||
void renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color);
|
||||
void renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id = UNKNOWN_ID);
|
||||
|
||||
void renderSolidCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer);
|
||||
void renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color);
|
||||
void renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color);
|
||||
void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
uniform bool Instanced = false;
|
||||
// the interpolated normal
|
||||
|
||||
out vec3 _normal;
|
||||
|
@ -33,6 +34,11 @@ void main(void) {
|
|||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
|
||||
<$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$>
|
||||
if (Instanced) {
|
||||
<$transformInstancedModelToClipPos(cam, obj, inPosition, gl_Position)$>
|
||||
<$transformInstancedModelToEyeDir(cam, obj, inNormal.xyz, _normal)$>
|
||||
} else {
|
||||
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
|
||||
<$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$>
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue