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) {
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) {
@ -105,7 +105,7 @@ Procedural::Procedural() {
_transparentState->setCullMode(gpu::State::CULL_NONE);
_transparentState->setDepthTest(true, true, gpu::LESS_EQUAL);
_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);
}
@ -211,10 +211,10 @@ bool Procedural::isReady() const {
}
void Procedural::prepare(gpu::Batch& batch,
const glm::vec3& position,
const glm::vec3& size,
const glm::quat& orientation,
const glm::vec4& color) {
const glm::vec3& position,
const glm::vec3& size,
const glm::quat& orientation,
const glm::vec4& color) {
_entityDimensions = size;
_entityPosition = position;
_entityOrientation = glm::mat3_cast(orientation);
@ -308,6 +308,7 @@ void Procedural::prepare(gpu::Batch& batch,
}
}
void Procedural::setupUniforms(bool transparent) {
_uniforms.clear();
auto customUniformCount = _data.uniforms.keys().size();
@ -323,53 +324,50 @@ void Procedural::setupUniforms(bool transparent) {
} else if (value.isArray()) {
auto valueArray = value.toArray();
switch (valueArray.size()) {
case 0:
break;
case 0:
break;
case 1: {
float v = valueArray[0].toDouble();
_uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform1f(slot, v); });
break;
}
case 1: {
float v = valueArray[0].toDouble();
_uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform1f(slot, v); });
break;
}
case 2: {
glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() };
_uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform2f(slot, v.x, v.y); });
break;
}
case 2: {
glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() };
_uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform2f(slot, v.x, v.y); });
break;
}
case 3: {
glm::vec3 v{
valueArray[0].toDouble(),
valueArray[1].toDouble(),
valueArray[2].toDouble(),
};
_uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform3f(slot, v.x, v.y, v.z); });
break;
}
case 3: {
glm::vec3 v{
valueArray[0].toDouble(),
valueArray[1].toDouble(),
valueArray[2].toDouble(),
};
_uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform3f(slot, v.x, v.y, v.z); });
break;
}
default:
case 4: {
glm::vec4 v{
valueArray[0].toDouble(),
valueArray[1].toDouble(),
valueArray[2].toDouble(),
valueArray[3].toDouble(),
};
_uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform4f(slot, v.x, v.y, v.z, v.w); });
break;
}
default:
case 4: {
glm::vec4 v{
valueArray[0].toDouble(),
valueArray[1].toDouble(),
valueArray[2].toDouble(),
valueArray[3].toDouble(),
};
_uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform4f(slot, v.x, v.y, v.z, v.w); });
break;
}
}
}
}
_uniforms.push_back([=](gpu::Batch& batch) {
// Time and position
{
// Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds
float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND;
_standardInputs.posAndTime = vec4(_entityPosition, time);
}
_standardInputs.position = vec4(_entityPosition, 1.0f);
// 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;
// Date
{
@ -385,7 +383,8 @@ void Procedural::setupUniforms(bool transparent) {
_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);
for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) {

View file

@ -73,14 +73,29 @@ public:
protected:
// DO NOT TOUCH
// We have to pack these in a particular way to match the ProceduralCommon.slh
// layout.
struct StandardInputs {
vec4 date;
vec4 posAndTime;
vec4 scaleAndCount;
mat4 orientation;
vec4 position;
vec4 scale;
float time;
int frameCount;
vec2 _spare1;
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
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_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 posAndTime;
vec4 scaleAndCount;
mat4 orientation;
vec4 resolution[4];
};
LAYOUT(binding=0) uniform standardInputsBuffer {
StandardInputs params;
};
// shader playback time (in seconds)
float iGlobalTime = params.posAndTime.w;
vec4 iDate = params.date;
int iFrameCount = int(params.scaleAndCount.w);
// 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
);
// Offset 16, acts as vec4 for alignment purposes
vec3 worldPosition;
// Offset 32, acts as vec4 for alignment purposes
vec3 worldScale;
// Offset 48
float globalTime;
// Offset 52
int frameCount;
// Offset 56
vec2 _spare1;
// Offset 64, acts as vec4[4] for alignment purposes
vec3 channelResolution[4];
// Offset 128, acts as vec4[3] for alignment purposes
// Also, each individual component is aligned as a vec4
mat3 worldOrientation;
// Offset 176
vec4 _spare2;
} standardInputs;
#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
// Resolution doesn't make sense in the VR context