Reimplement procedural uniforms without extension requirements

This commit is contained in:
Brad Davis 2018-10-19 14:39:32 -07:00
parent c8e664a0a1
commit 3f2f5b18ec
3 changed files with 97 additions and 82 deletions

View file

@ -40,7 +40,7 @@ static const std::string PROCEDURAL_VERSION = "//PROCEDURAL_VERSION";
bool operator==(const ProceduralData& a, const ProceduralData& b) { bool operator==(const ProceduralData& a, const ProceduralData& b) {
return ((a.version == b.version) && (a.shaderUrl == b.shaderUrl) && (a.uniforms == b.uniforms) && return ((a.version == b.version) && (a.shaderUrl == b.shaderUrl) && (a.uniforms == b.uniforms) &&
(a.channels == b.channels)); (a.channels == b.channels));
} }
QJsonValue ProceduralData::getProceduralData(const QString& proceduralJson) { QJsonValue ProceduralData::getProceduralData(const QString& proceduralJson) {
@ -105,7 +105,7 @@ Procedural::Procedural() {
_transparentState->setCullMode(gpu::State::CULL_NONE); _transparentState->setCullMode(gpu::State::CULL_NONE);
_transparentState->setDepthTest(true, true, gpu::LESS_EQUAL); _transparentState->setDepthTest(true, true, gpu::LESS_EQUAL);
_transparentState->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, _transparentState->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
_standardInputsBuffer = std::make_shared<gpu::Buffer>(sizeof(StandardInputs), nullptr); _standardInputsBuffer = std::make_shared<gpu::Buffer>(sizeof(StandardInputs), nullptr);
} }
@ -211,10 +211,10 @@ bool Procedural::isReady() const {
} }
void Procedural::prepare(gpu::Batch& batch, void Procedural::prepare(gpu::Batch& batch,
const glm::vec3& position, const glm::vec3& position,
const glm::vec3& size, const glm::vec3& size,
const glm::quat& orientation, const glm::quat& orientation,
const glm::vec4& color) { const glm::vec4& color) {
_entityDimensions = size; _entityDimensions = size;
_entityPosition = position; _entityPosition = position;
_entityOrientation = glm::mat3_cast(orientation); _entityOrientation = glm::mat3_cast(orientation);
@ -308,6 +308,7 @@ void Procedural::prepare(gpu::Batch& batch,
} }
} }
void Procedural::setupUniforms(bool transparent) { void Procedural::setupUniforms(bool transparent) {
_uniforms.clear(); _uniforms.clear();
auto customUniformCount = _data.uniforms.keys().size(); auto customUniformCount = _data.uniforms.keys().size();
@ -323,53 +324,50 @@ void Procedural::setupUniforms(bool transparent) {
} else if (value.isArray()) { } else if (value.isArray()) {
auto valueArray = value.toArray(); auto valueArray = value.toArray();
switch (valueArray.size()) { switch (valueArray.size()) {
case 0: case 0:
break; break;
case 1: { case 1: {
float v = valueArray[0].toDouble(); float v = valueArray[0].toDouble();
_uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform1f(slot, v); }); _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform1f(slot, v); });
break; break;
} }
case 2: { case 2: {
glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() }; glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() };
_uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform2f(slot, v.x, v.y); }); _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform2f(slot, v.x, v.y); });
break; break;
} }
case 3: { case 3: {
glm::vec3 v{ glm::vec3 v{
valueArray[0].toDouble(), valueArray[0].toDouble(),
valueArray[1].toDouble(), valueArray[1].toDouble(),
valueArray[2].toDouble(), valueArray[2].toDouble(),
}; };
_uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform3f(slot, v.x, v.y, v.z); }); _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform3f(slot, v.x, v.y, v.z); });
break; break;
} }
default: default:
case 4: { case 4: {
glm::vec4 v{ glm::vec4 v{
valueArray[0].toDouble(), valueArray[0].toDouble(),
valueArray[1].toDouble(), valueArray[1].toDouble(),
valueArray[2].toDouble(), valueArray[2].toDouble(),
valueArray[3].toDouble(), valueArray[3].toDouble(),
}; };
_uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform4f(slot, v.x, v.y, v.z, v.w); }); _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform4f(slot, v.x, v.y, v.z, v.w); });
break; break;
} }
} }
} }
} }
_uniforms.push_back([=](gpu::Batch& batch) { _uniforms.push_back([=](gpu::Batch& batch) {
// Time and position _standardInputs.position = vec4(_entityPosition, 1.0f);
{ // Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds
// Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds _standardInputs.time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND;
float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND;
_standardInputs.posAndTime = vec4(_entityPosition, time);
}
// Date // Date
{ {
@ -385,7 +383,8 @@ void Procedural::setupUniforms(bool transparent) {
_standardInputs.date.w = (time.hour() * 3600) + (time.minute() * 60) + time.second() + fractSeconds; _standardInputs.date.w = (time.hour() * 3600) + (time.minute() * 60) + time.second() + fractSeconds;
} }
_standardInputs.scaleAndCount = vec4(_entityDimensions, ++_frameCount); _standardInputs.scale = vec4(_entityDimensions, 1.0f);
_standardInputs.frameCount = ++_frameCount;
_standardInputs.orientation = mat4(_entityOrientation); _standardInputs.orientation = mat4(_entityOrientation);
for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) { for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) {

View file

@ -73,14 +73,29 @@ public:
protected: protected:
// DO NOT TOUCH
// We have to pack these in a particular way to match the ProceduralCommon.slh
// layout.
struct StandardInputs { struct StandardInputs {
vec4 date; vec4 date;
vec4 posAndTime; vec4 position;
vec4 scaleAndCount; vec4 scale;
mat4 orientation; float time;
int frameCount;
vec2 _spare1;
vec4 resolution[4]; vec4 resolution[4];
mat4 orientation;
}; };
static_assert(0 == offsetof(StandardInputs, date), "ProceduralOffsets");
static_assert(16 == offsetof(StandardInputs, position), "ProceduralOffsets");
static_assert(32 == offsetof(StandardInputs, scale), "ProceduralOffsets");
static_assert(48 == offsetof(StandardInputs, time), "ProceduralOffsets");
static_assert(52 == offsetof(StandardInputs, frameCount), "ProceduralOffsets");
static_assert(56 == offsetof(StandardInputs, _spare1), "ProceduralOffsets");
static_assert(64 == offsetof(StandardInputs, resolution), "ProceduralOffsets");
static_assert(128 == offsetof(StandardInputs, orientation), "ProceduralOffsets");
// Procedural metadata // Procedural metadata
ProceduralData _data; ProceduralData _data;

View file

@ -23,42 +23,43 @@ LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL1) uniform sampler2D iChannel1;
LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL2) uniform sampler2D iChannel2; LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL2) uniform sampler2D iChannel2;
LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL3) uniform sampler2D iChannel3; LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL3) uniform sampler2D iChannel3;
struct StandardInputs { // DO NOT TOUCH
// This block does not follow our normal rules of always using a struct and
// always using 16 byte aligned types like vec4 and mat4
//
// This is because this block must be EXACTLY how it is in order to maintain
// comptability with existing procedural shaders that previously relied on these
// inputs as uniforms, not members of a UBO
LAYOUT_STD140(binding=0) uniform standardInputsBuffer {
// Offset 0
vec4 date; vec4 date;
vec4 posAndTime; // Offset 16, acts as vec4 for alignment purposes
vec4 scaleAndCount; vec3 worldPosition;
mat4 orientation; // Offset 32, acts as vec4 for alignment purposes
vec4 resolution[4]; vec3 worldScale;
}; // Offset 48
float globalTime;
// Offset 52
LAYOUT(binding=0) uniform standardInputsBuffer { int frameCount;
StandardInputs params; // Offset 56
}; vec2 _spare1;
// Offset 64, acts as vec4[4] for alignment purposes
// shader playback time (in seconds) vec3 channelResolution[4];
float iGlobalTime = params.posAndTime.w; // Offset 128, acts as vec4[3] for alignment purposes
// Also, each individual component is aligned as a vec4
vec4 iDate = params.date; mat3 worldOrientation;
// Offset 176
int iFrameCount = int(params.scaleAndCount.w); vec4 _spare2;
} standardInputs;
// the position of the object being rendered
vec3 iWorldPosition = params.posAndTime.xyz;
// the dimensions of the object being rendered
vec3 iWorldScale = params.scaleAndCount.xyz;
// the orientation of the object being rendered
mat3 iWorldOrientation = mat3(params.orientation);
vec3 iChannelResolution[4] = vec3[4](
params.resolution[0].xyz,
params.resolution[1].xyz,
params.resolution[2].xyz,
params.resolution[3].xyz
);
#define iDate standardInputs.date
#define iWorldPosition standardInputs.worldPosition
#define iWorldScale standardInputs.worldScale
#define iGlobalTime standardInputs.globalTime
#define iFrameCount standardInputs.frameCount
#define iChannelResolution standardInputs.channelResolution
#define iWorldOrientation standardInputs.worldOrientation
// Unimplemented uniforms // Unimplemented uniforms
// Resolution doesn't make sense in the VR context // Resolution doesn't make sense in the VR context