New User defined uniforms in Custom shaders

This commit is contained in:
Bruno Herbelin
2024-03-10 11:51:13 +01:00
parent f280d3b64c
commit d5f2b375a6
7 changed files with 164 additions and 27 deletions

View File

@@ -967,6 +967,27 @@ bool Control::receiveSourceAttribute(Source *target, const std::string &attribut
textsrc->contents()->setText(label);
}
}
/// e.g. '/vimix/current/uniform sf var 0.5'
else if (attribute.compare(OSC_SOURCE_UNIFORM) == 0) {
std::string uniform_name;
float uniform_value = NAN;
const char *str = nullptr;
arguments >> str;
uniform_name = std::string(str);
arguments >> uniform_value >> osc::EndMessage;
CloneSource *clonesrc = dynamic_cast<CloneSource *>(target);
if (clonesrc) {
ImageFilter *f = dynamic_cast<ImageFilter *>(clonesrc->filter());
if (f) {
f->setProgramParameter(uniform_name, uniform_value);
}
}
}
/// e.g. '/vimix/current/filter sf blur 0.5'
else if (attribute.compare(OSC_SOURCE_FILTER) == 0) {
std::string filter_name;

View File

@@ -71,6 +71,7 @@
#define OSC_SOURCE_TEXSIZE "/texture_size"
#define OSC_SOURCE_TEXANGLE "/texture_angle"
#define OSC_SOURCE_FILTER "/filter"
#define OSC_SOURCE_UNIFORM "/uniform"
#define OSC_SESSION "/session"
#define OSC_SESSION_VERSION "/version"

View File

@@ -1377,6 +1377,12 @@ void ImGuiVisitor::visit (ImageFilter& f)
FilteringProgram target;
f.setProgram( target );
}
// List of parameters
std::ostringstream oss;
oss << "Custom ";
list_parameters_(f, oss);
}
void ImGuiVisitor::visit (CloneSource& s)

View File

@@ -18,6 +18,7 @@
**/
#include <ctime>
#include <algorithm>
#include <regex>
#include <glm/gtc/matrix_access.hpp>
#include <glm/gtc/matrix_transform.hpp>
@@ -26,6 +27,7 @@
#include "Visitor.h"
#include "FrameBuffer.h"
#include "Primitives.h"
#include "BaseToolkit.h"
#include "ImageFilter.h"
@@ -150,6 +152,17 @@ bool FilteringProgram::operator!= (const FilteringProgram& other) const
return false;
}
bool FilteringProgram::hasParameter(const std::string &p)
{
return parameters_.find(p) != parameters_.end();
}
void FilteringProgram::removeParameter(const std::string &p)
{
if (hasParameter(p))
parameters_.erase(p);
}
////////////////////////////////////////
///// //
@@ -168,6 +181,7 @@ ImageFilteringShader::ImageFilteringShader(): ImageShader()
timer_ = g_timer_new ();
iTime_ = 0.0;
iFrame_ = 0;
uniforms_changed_ = true;
ImageShader::reset();
}
@@ -216,9 +230,17 @@ void ImageFilteringShader::use()
//
// loop over uniforms
//
for (auto u = uniforms_.begin(); u != uniforms_.end(); ++u)
for (auto u = uniforms_.begin(); u != uniforms_.end(); ) {
// set uniform to current value
program_->setUniform( u->first, u->second );
if ( program_->setUniform(u->first, u->second) )
// uniform variable could be set, keep it
++u;
else {
// uniform variable does not exist in code, remove it
u = uniforms_.erase(u);
uniforms_changed_ = true;
}
}
}
void ImageFilteringShader::reset()
@@ -242,7 +264,7 @@ void ImageFilteringShader::setCode(const std::string &code, std::promise<std::st
// shader is composed of a header, the given code and a footer
shader_code_ = fragmentHeader + code_ + fragmentFooter;
// shift line numbers by number of lines in header
std::string::difference_type n = std::count(fragmentHeader.begin(), fragmentHeader.end(), '\n');
static std::string::difference_type n = std::count(fragmentHeader.begin(), fragmentHeader.end(), '\n');
// launch build
custom_shading_.setShaders("shaders/image.vs", shader_code_, (int)n, ret);
}
@@ -309,6 +331,19 @@ void ImageFilter::update (float dt)
if ( program_.isTwoPass() )
shaders_.second->update(dt);
// uniforms changed in main shader
if ( shaders_.first->uniforms_changed_ ) {
// loop over the parameters of the program...
std::map<std::string, float> __P = program_.parameters();
for (auto param = __P.begin(); param != __P.end(); ++param) {
// .. and remove the parameters that are not valid uniforms
if (shaders_.first->uniforms_.count(param->first) < 1)
program_.removeParameter(param->first);
}
// done
shaders_.first->uniforms_changed_ = false;
}
}
uint ImageFilter::texture () const
@@ -392,6 +427,9 @@ FilteringProgram ImageFilter::program () const
return program_;
}
#define REGEX_UNIFORM_DECLARATION "uniform\\s+float\\s+"
#define REGEX_UNIFORM_VALUE "(\\s*=\\s*[[:digit:]](\\.[[:digit:]])?)?\\s*\\;"
void ImageFilter::setProgram(const FilteringProgram &f, std::promise<std::string> *ret)
{
// always keep local copy
@@ -404,11 +442,42 @@ void ImageFilter::setProgram(const FilteringProgram &f, std::promise<std::string
// set code to the shader for first-pass
shaders_.first->setCode( codes.first, ret );
// Parse code to detect additional declaration of uniform variables
// Search for "uniform float", a variable name, with possibly a '=' and float value
std::string glslcode(codes.first);
std::smatch found_uniform;
std::regex is_a_uniform(REGEX_UNIFORM_DECLARATION "[[:alpha:]]+" REGEX_UNIFORM_VALUE);
// loop over every uniform declarations in the GLSL code
while (std::regex_search(glslcode, found_uniform, is_a_uniform)) {
// found a complete declaration of uniform variable
std::string declaration = found_uniform.str();
// extract variable name by erasing everything else
std::string varname =
std::regex_replace(declaration,std::regex(REGEX_UNIFORM_DECLARATION),"");
varname = std::regex_replace(varname, std::regex(REGEX_UNIFORM_VALUE), "");
// add to list of parameters if was not already there, with default value
if ( !program_.hasParameter(varname) )
program_.setParameter(varname, 0.f);
// try to find a value in uniform declaration, and set parameter value if valid
float val = 0.f;
std::smatch found_value;
std::regex is_a_float_value("[[:digit:]](\\.[[:digit:]])?");
if (std::regex_search(declaration, found_value, is_a_float_value)) {
// set value only if a value is given
if ( BaseToolkit::is_a_value(found_value.str(), &val) )
program_.setParameter(varname, val);
}
// keep parsing
glslcode = found_uniform.suffix().str();
}
// SECOND PASS
if ( program_.isTwoPass() )
// set the code to the shader for second-pass
shaders_.second->setCode( codes.second );
shaders_.second->setCode(codes.second);
// UPDATE UNIFORMS
updateParameters();
}

View File

@@ -47,7 +47,7 @@ public:
std::pair< std::string, std::string > code();
// if has second pass
bool isTwoPass() const { return two_pass_filter_; }
inline bool isTwoPass() const { return two_pass_filter_; }
// set the list of parameters
inline void setParameters(const std::map< std::string, float > &parameters) { parameters_ = parameters; }
@@ -57,6 +57,8 @@ public:
// set the value of a parameter
inline void setParameter(const std::string &p, float value) { parameters_[p] = value; }
bool hasParameter(const std::string &p);
void removeParameter(const std::string &p);
// globals
static std::string getFilterCodeInputs();
@@ -85,6 +87,7 @@ public:
// list of uniforms to control shader
std::map< std::string, float > uniforms_;
bool uniforms_changed_;
ImageFilteringShader();
~ImageFilteringShader();

View File

@@ -232,52 +232,89 @@ void ShadingProgram::reset()
}
template<>
void ShadingProgram::setUniform<int>(const std::string& name, int val) {
glUniform1i(glGetUniformLocation(id_, name.c_str()), val);
bool ShadingProgram::setUniform<int>(const std::string &name, int val)
{
GLint uid = glGetUniformLocation(id_, name.c_str());
if (uid < 0)
return false;
glUniform1i(uid, val);
return true;
}
template<>
void ShadingProgram::setUniform<bool>(const std::string& name, bool val) {
glUniform1i(glGetUniformLocation(id_, name.c_str()), val);
bool ShadingProgram::setUniform<bool>(const std::string& name, bool val) {
GLint uid = glGetUniformLocation(id_, name.c_str());
if (uid < 0)
return false;
glUniform1i(uid, val);
return true;
}
template<>
void ShadingProgram::setUniform<float>(const std::string& name, float val) {
glUniform1f(glGetUniformLocation(id_, name.c_str()), val);
bool ShadingProgram::setUniform<float>(const std::string& name, float val) {
GLint uid = glGetUniformLocation(id_, name.c_str());
if (uid < 0)
return false;
glUniform1f(uid, val);
return true;
}
template<>
void ShadingProgram::setUniform<float>(const std::string& name, float val1, float val2) {
glUniform2f(glGetUniformLocation(id_, name.c_str()), val1, val2);
bool ShadingProgram::setUniform<float>(const std::string& name, float val1, float val2) {
GLint uid = glGetUniformLocation(id_, name.c_str());
if (uid < 0)
return false;
glUniform2f(uid, val1, val2);
return true;
}
template<>
void ShadingProgram::setUniform<float>(const std::string& name, float val1, float val2, float val3) {
glUniform3f(glGetUniformLocation(id_, name.c_str()), val1, val2, val3);
bool ShadingProgram::setUniform<float>(const std::string& name, float val1, float val2, float val3) {
GLint uid = glGetUniformLocation(id_, name.c_str());
if (uid < 0)
return false;
glUniform3f(uid, val1, val2, val3);
return true;
}
template<>
void ShadingProgram::setUniform<glm::vec2>(const std::string& name, glm::vec2 val) {
bool ShadingProgram::setUniform<glm::vec2>(const std::string& name, glm::vec2 val) {
glm::vec2 v(val);
glUniform2fv(glGetUniformLocation(id_, name.c_str()), 1, glm::value_ptr(v));
GLint uid = glGetUniformLocation(id_, name.c_str());
if (uid < 0)
return false;
glUniform2fv(uid, 1, glm::value_ptr(v));
return true;
}
template<>
void ShadingProgram::setUniform<glm::vec3>(const std::string& name, glm::vec3 val) {
bool ShadingProgram::setUniform<glm::vec3>(const std::string& name, glm::vec3 val) {
glm::vec3 v(val);
glUniform3fv(glGetUniformLocation(id_, name.c_str()), 1, glm::value_ptr(v));
GLint uid = glGetUniformLocation(id_, name.c_str());
if (uid < 0)
return false;
glUniform3fv(uid, 1, glm::value_ptr(v));
return true;
}
template<>
void ShadingProgram::setUniform<glm::vec4>(const std::string& name, glm::vec4 val) {
bool ShadingProgram::setUniform<glm::vec4>(const std::string& name, glm::vec4 val) {
glm::vec4 v(val);
glUniform4fv(glGetUniformLocation(id_, name.c_str()), 1, glm::value_ptr(v));
GLint uid = glGetUniformLocation(id_, name.c_str());
if (uid < 0)
return false;
glUniform4fv(uid, 1, glm::value_ptr(v));
return true;
}
template<>
void ShadingProgram::setUniform<glm::mat4>(const std::string& name, glm::mat4 val) {
bool ShadingProgram::setUniform<glm::mat4>(const std::string& name, glm::mat4 val) {
glm::mat4 m(val);
glUniformMatrix4fv(glGetUniformLocation(id_, name.c_str()), 1, GL_FALSE, glm::value_ptr(m));
GLint uid = glGetUniformLocation(id_, name.c_str());
if (uid < 0)
return false;
glUniformMatrix4fv(uid, 1, GL_FALSE, glm::value_ptr(m));
return true;
}

View File

@@ -25,9 +25,9 @@ public:
static void enduse();
void reset();
template<typename T> void setUniform(const std::string& name, T val);
template<typename T> void setUniform(const std::string& name, T val1, T val2);
template<typename T> void setUniform(const std::string& name, T val1, T val2, T val3);
template<typename T> bool setUniform(const std::string& name, T val);
template<typename T> bool setUniform(const std::string& name, T val1, T val2);
template<typename T> bool setUniform(const std::string& name, T val1, T val2, T val3);
private:
unsigned int id_;
@@ -54,7 +54,7 @@ public:
virtual void use();
virtual void reset();
virtual void accept(Visitor& v);
void copy(Shader const& S);
void copy(Shader const &S);
glm::mat4 projection;
glm::mat4 modelview;