Files
deighton-ar/mobile/ios/ViroKit.framework/Headers/VROShaderModifier.h
2018-03-27 17:46:15 -07:00

300 lines
8.3 KiB
C++

//
// VROShaderModifier.h
// ViroRenderer
//
// Created by Raj Advani on 10/13/16.
// Copyright © 2016 Viro Media. All rights reserved.
//
#ifndef VROShaderModifier_h
#define VROShaderModifier_h
#include <stdlib.h>
#include <vector>
#include <string>
#include <functional>
#include <memory>
#include <map>
#include "VROOpenGL.h"
class VROUniform;
class VROGeometry;
class VROMaterial;
typedef std::function<void(VROUniform *uniform, GLuint location,
const VROGeometry *geometry, const VROMaterial *material)> VROUniformBindingBlock;
/*
The entry point, which signals where in the shader program this modifier will
act.
----------------
Geometry entry point. The code may declare uniforms and read/write
to the following structures:
struct VROShaderGeometry {
vec3 position;
vec3 normal;
vec2 texcoord;
vec4 tangent;
vec4 bone_weights;
ivec4 bone_indices;
} _geometry;
struct VROTransforms {
mat4 model_matrix;
mat4 view_matrix;
mat4 projection_matrix;
} _transforms;
The Geometry entry point enables modifiers to change vertex parameters
in the vertex shader. This includes geometry parameters like position,
normals, and texcoords, and transform parameters like the model, view,
and projection matrices.
----------------
Vertex entry point. The code may declare uniforms and read/write
to the following structure:
struct VROShaderVertex {
vec3 position;
} _vertex;
The Vertex entry point enables modifiers to change the position of
vertices *after* their transformation into normalized device coordinates.
The input and output (_vertex.position) is in normalized device coordinates.
----------------
Surface entry point. The code may declare uniforms and read/write
to the following structure:
struct VROSurface {
lowp vec4 diffuse_color;
highp vec2 diffuse_texcoord;
lowp float diffuse_intensity;
lowp float shininess;
lowp vec3 specular_color;
highp vec2 specular_texcoord;
highp float roughness;
highp float metalness;
highp float ao;
lowp float alpha;
lowp vec3 normal;
highp vec3 position;
} _surface;
The Surface entry point enables modifiers to change surface parameters, in
the fragment shader, prior to the lighting computation.
----------------
Lighting Model entry point. The code runs once per light. It reads from the
_surface structure and the _light structure below, and sets the results in
the _lightingContribution structure:
struct VROLightingContribution {
highp vec3 ambient;
highp vec3 diffuse;
highp vec3 specular;
highp float visibility;
} _lightingContribution;
struct VROLightUniforms {
int type;
highp float attenuation_start_distance;
highp float attenuation_end_distance;
highp float attenuation_falloff_exp;
highp vec4 position;
highp vec4 direction;
highp vec3 color;
highp float intensity;
highp float spot_inner_angle;
highp float spot_outer_angle;
} _light;
The Lighting Model entry point enables modifiers to define the impact of each
light on a given material. After being invoked on each light, the lighting
contributions from each light are accumulated and combined with material surface
properties to generate the final color. The visibility value (which defaults to
1.0) is multiplied by the diffuse and specular components; it can be used to
simulate the impact of shadow.
Note, as an optimization, total ambient light is initialized to the sum
of all ambient lights. Therefore, in general lighting models will not need to
add anything to _lightingContribution.ambient.
----------------
Fragment entry point. The code may declare uniforms and read/write
to the variable:
highp vec4 _output_color;
The Fragment entry point enables modifiers to alter the final color of each
fragment, after the lighting computation.
----------------
Image entry point. The image entry point is *only* available for 2D post-processing
shaders. The code may declare uniforms for the fragment shader (the vertex
shader is a fixed quad in normalized device coordinates), and must simply
set the frag_color.
frag_color = ... (vec4) ...
The Image entry point enables modifiers to quickly create new post-processing
functions for VROImageShaderPrograms.
----------------
*/
enum class VROShaderEntryPoint {
Geometry,
Vertex,
Surface,
LightingModel,
Fragment,
Image,
};
enum class VROShaderSection {
Uniforms,
Body
};
/*
Modifies the source of a VROShaderProgram, and enables the binding of new uniforms
to said program. A shader modifier can be attached to multiple shaders. Note in such
cases, the uniform binders will be consistent across shaders (they cannot be different
for each shader).
*/
class VROShaderModifier {
public:
static std::string getShaderModifierKey(const std::vector<std::shared_ptr<VROShaderModifier>> &modifiers);
/*
Create a new shader modifier that operates at the given entry point. The input
should be valid GLSL code, with each line as a separate string. Uniform declarations
are automatically separated out from the body of the input code.
*/
VROShaderModifier(VROShaderEntryPoint entryPoint, std::vector<std::string> input);
virtual ~VROShaderModifier();
VROShaderEntryPoint getEntryPoint() const {
return _entryPoint;
}
int getShaderModifierId() const {
return _shaderModifierId;
}
/*
Names can be added to shader modifiers, for debugging only. Will be appended
to the parent shader name.
*/
void setName(std::string name) {
_name = name;
}
std::string getName() const {
return _name;
}
/*
Add a string of text and what it should be replaced with. This will perform
a find and replace on the modified shader.
*/
void addReplacement(std::string stringMatching, std::string replacementString) {
_replacements[stringMatching] = replacementString;
}
/*
Set a block that will bind the uniform of the given name. This will be
invoked each time a shader containining this modifier is bound. The block
should set the uniform in the shader via glUniform* methods.
*/
void setUniformBinder(std::string uniform, VROUniformBindingBlock bindingBlock);
/*
Invoke the uniform binder for the given uniform.
*/
void bindUniform(VROUniform *uniform, GLuint location,
const VROGeometry *geometry, const VROMaterial *material);
/*
Get the pragma directive that corresponds to this modifier's entry point and
the given section within a shader. This is the point in the shader where the
modifier source will be inserted.
*/
std::string getDirective(VROShaderSection section) const;
/*
Get the uniforms for which we have an attached binder.
*/
std::vector<std::string> getUniforms() const;
/*
Get the replacement map, used to replace matching lines of code in the
modified shader with new lines of code.
*/
const std::map<std::string, std::string> &getReplacements() const {
return _replacements;
}
/*
Get the uniform declaration code. This gets placed at the top of the file.
*/
std::string getUniformsSource() const {
return _uniforms;
}
/*
Get the body of the source. This gets placed in the main vertex or fragment
function.
*/
std::string getBodySource() const {
return _body;
}
private:
int _shaderModifierId;
std::string _name;
/*
The new uniforms this shader modifier will add. Single string containing
the uniform declarations, with newlines between them.
*/
std::string _uniforms;
/*
The code this modifier is adding to the body of the shader.
*/
std::string _body;
/*
Map of lines this modifier will replace in the shader it modifies.
*/
std::map<std::string, std::string> _replacements;
VROShaderEntryPoint _entryPoint;
std::map<std::string, VROUniformBindingBlock> _uniformBinders;
/*
Return true if the given line is a variable declaration, and false
if not. Variable declarations are lines that declare a uniform, in,
our out variable.
*/
bool isVariableDeclaration(std::string &line);
};
#endif