Skip to content

Commit

Permalink
Implemented a #include parser for the shader lib, to reduce code dupl…
Browse files Browse the repository at this point in the history
…ication between the tesselation and geometry shaders. Moved the precise eye calculations back to the geometry shader as this gives a better look, but kept an imprecise mask calculation in the tessellation shader to limit high subdivision to the area around the eyes only.
  • Loading branch information
nitronoid committed Mar 29, 2018
1 parent 173e93a commit 15eadba
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 96 deletions.
4 changes: 4 additions & 0 deletions include/ShaderLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class ShaderLib
//-----------------------------------------------------------------------------------------------------
QOpenGLShaderProgram* getCurrentShader();

private:
std::string loadFileToString(const std::string &_path);
void parseIncludes(std::string &io_shaderString);

private:
enum SHADER_TYPES {VERTEX, FRAGMENT, GEOMETRY, TESSCONTROL, TESSEVAL};
//-----------------------------------------------------------------------------------------------------
Expand Down
39 changes: 39 additions & 0 deletions shaders/include/owl_eye_funcs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

mat3 rotationMatrix3d(vec3 axis, float angle)
{
axis = normalize(axis);
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - c;

return mat3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c);
}

vec3 eyePos(vec3 _pos, float scale, vec3 translate, float _twist)
{
vec3 newPos = _pos;
float stretch = 1.15;
newPos.y *= stretch;

newPos = newPos/scale - vec3(translate);

vec3 upVec = vec3(0.0, 0.0, 1.0);
newPos = rotationMatrix3d(upVec, _twist) * newPos;

return newPos;
}

float eyeMask(vec3 _pos, float _fuzz, float _cap)
{
vec2 centre = vec2(0.5);
float dist = distance(centre, _pos.xy);
float mask = 1.0 - smoothstep(_cap - _fuzz, _cap + _fuzz, dist);
return clamp(mask, 0.0, 1.0);
}

float mask(float _maskA, float _maskB, float _fuzz, float _zDir)
{
return (_maskA + _maskB) * smoothstep(0.0, _fuzz, _zDir);
}
15 changes: 12 additions & 3 deletions shaders/owl_pbr_geo.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ uniform float eyeThickness = 0.08;
uniform float eyeGap = 0.19;
uniform float eyeFuzz = 0.02;

#include "shaders/include/owl_eye_funcs.h"

// Linear interpolation at between x and y, at t
float lerp(float x, float y, float t)
{
Expand Down Expand Up @@ -90,14 +92,21 @@ float eyes(vec3 _posA, vec3 _posB, float fuzz, float gap, float thickness, float

void main( void )
{
for(int i=0; i < 3; i++)
for(int i = 0; i < 3; i++)
{
Normal = normalize(te_normal[i]);
TexCoords = te_uv[i];

vec3 pos = te_position[i];
float rotation = radians(eyeRotation);
vec3 posA = eyePos(pos, eyeScale, eyeTranslate, rotation);
pos.x *= -1.0;
vec3 posB = eyePos(pos, eyeScale, eyeTranslate, -rotation);
float maskA = eyeMask(posA, eyeFuzz, 0.7);
float maskB = eyeMask(posB, eyeFuzz, 0.7);
float bigMask = mask(maskA, maskB, eyeFuzz, te_normal[i].z);


float height = eyes(te_posA[i], te_posB[i], eyeFuzz, eyeGap, eyeThickness, eyeWarp, eyeExponent, te_maskA[i], te_maskB[i]) * te_bigMask[i];
float height = eyes(posA, posB, eyeFuzz, eyeGap, eyeThickness, eyeWarp, eyeExponent, maskA, maskB) * bigMask;

EyeVal = height;

Expand Down
86 changes: 11 additions & 75 deletions shaders/owl_pbr_tess_control.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -9,74 +9,15 @@ in vec2 v_uv[];
out vec3 tc_position[];
out vec3 tc_normal[];
out vec2 tc_uv[];
out vec3 tc_posA[];
out vec3 tc_posB[];
out float tc_maskA[];
out float tc_maskB[];
out float tc_bigMask[];

uniform int innerTess = 64;
uniform int outerTess = 64;
uniform float eyeRotation = 7.0;
uniform float eyeScale = 1.55;
uniform vec3 eyeTranslate = vec3(0.21, 0.3, 0.0);
uniform float eyeFuzz = 0.02;

#include "shaders/include/owl_eye_funcs.h"
#define ID gl_InvocationID

mat4 rotationMatrix4d(vec3 axis, float angle)
{
axis = normalize(axis);
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - c;

return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0,
0.0, 0.0, 0.0, 1.0);
}

mat3 rotationMatrix3d(vec3 axis, float angle)
{
axis = normalize(axis);
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - c;

return mat3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c);
}


vec3 eyePos(vec3 _pos, float scale, vec3 translate, float _twist)
{
vec3 newPos = _pos;
float stretch = 1.15;
newPos.y *= stretch;

newPos = newPos/scale - vec3(translate);

vec3 upVec = vec3(0.0, 0.0, 1.0);
newPos = rotationMatrix3d(upVec, _twist) * newPos;

return newPos;
}

float eyeMask(vec3 _pos, float _fuzz)
{
vec2 centre = vec2(0.5);
float dist = distance(centre, _pos.xy);
float cap = 0.7;
float mask = 1.0 - smoothstep(cap - _fuzz, cap + _fuzz, dist);
return clamp(mask, 0.0, 1.0);
}

float mask(float _maskA, float _maskB, float _fuzz, float _zDir)
{
return (_maskA + _maskB) * smoothstep(0.0, 0.0 + _fuzz, _zDir);
}

void main(void)
{
Expand All @@ -86,26 +27,21 @@ void main(void)
pos.x *= -1.0;
vec3 posB = eyePos(pos, eyeScale, eyeTranslate, -rotation);

tc_posA[ID] = posA;
tc_posB[ID] = posB;

float maskA = eyeMask(posA, eyeFuzz);
float maskB = eyeMask(posB, eyeFuzz);
tc_maskA[ID] = maskA;
tc_maskB[ID] = maskB;
float maskA = eyeMask(posA, eyeFuzz, 0.7);
float maskB = eyeMask(posB, eyeFuzz, 0.7);
float bigMask = mask(maskA, maskB, eyeFuzz, v_normal[ID].z);
tc_bigMask[ID] = bigMask;

tc_position[ID] = v_position[ID];
tc_normal[ID] = v_normal[ID];
tc_uv[ID] = v_uv[ID];

int tessLevel = 1 + int(ceil(64 * smoothstep(0.0, 1.0, bigMask)));
// if(ID == 0)
// {
gl_TessLevelInner[ID] = tessLevel;
gl_TessLevelOuter[ID * 3] = tessLevel;
gl_TessLevelOuter[ID * 3 + 1] = tessLevel;
gl_TessLevelOuter[ID * 3 + 2] = tessLevel;
// }
float tessMask = mask(eyeMask(posA, eyeFuzz, 1.0), eyeMask(posB, eyeFuzz, 1.0), eyeFuzz, v_normal[ID].z);
int tessLevel = 1 + int(ceil(64 * smoothstep(0.0, 1.0, tessMask)));

gl_TessLevelInner[0] = tessLevel;
gl_TessLevelOuter[0] = tessLevel;
gl_TessLevelOuter[1] = tessLevel;
gl_TessLevelOuter[2] = tessLevel;

}
15 changes: 0 additions & 15 deletions shaders/owl_pbr_tess_eval.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,10 @@ layout(triangles, equal_spacing, cw) in;
in vec3 tc_position[];
in vec3 tc_normal[];
in vec2 tc_uv[];
in vec3 tc_posA[];
in vec3 tc_posB[];
in float tc_maskA[];
in float tc_maskB[];
in float tc_bigMask[];

out vec3 te_position;
out vec3 te_normal;
out vec2 te_uv;
out vec3 te_posA;
out vec3 te_posB;
out float te_maskA;
out float te_maskB;
out float te_bigMask;

uniform mat4 MVP;

Expand All @@ -27,10 +17,5 @@ void main(void)
te_normal = (gl_TessCoord.x * tc_normal[0] + gl_TessCoord.y * tc_normal[1] + gl_TessCoord.z * tc_normal[2]);
te_uv = (gl_TessCoord.x * tc_uv[0] + gl_TessCoord.y * tc_uv[1] + gl_TessCoord.z * tc_uv[2]);
te_position = (gl_TessCoord.x * tc_position[0] + gl_TessCoord.y * tc_position[1] + gl_TessCoord.z * tc_position[2]);
te_posA = (gl_TessCoord.x * tc_posA[0] + gl_TessCoord.y * tc_posA[1] + gl_TessCoord.z * tc_posA[2]);
te_posB = (gl_TessCoord.x * tc_posB[0] + gl_TessCoord.y * tc_posB[1] + gl_TessCoord.z * tc_posB[2]);
te_maskA = (gl_TessCoord.x * tc_maskA[0] + gl_TessCoord.y * tc_maskA[1] + gl_TessCoord.z * tc_maskA[2]);
te_maskB = (gl_TessCoord.x * tc_maskB[0] + gl_TessCoord.y * tc_maskB[1] + gl_TessCoord.z * tc_maskB[2]);
te_bigMask = (gl_TessCoord.x * tc_bigMask[0] + gl_TessCoord.y * tc_bigMask[1] + gl_TessCoord.z * tc_bigMask[2]);
gl_Position = MVP * vec4(te_position, 1.0);
}
2 changes: 0 additions & 2 deletions src/DemoScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ void DemoScene::initGeo()
// Create and bind our Vertex Buffer Object
m_meshVBO.init();
generateNewGeometry();

context()->versionFunctions<QOpenGLFunctions_4_1_Core>()->glPatchParameteri(GL_PATCH_VERTICES, 3);
}
//-----------------------------------------------------------------------------------------------------
void DemoScene::keyPress(QKeyEvent* io_event)
Expand Down
2 changes: 2 additions & 0 deletions src/MaterialPBR.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#include "MaterialPBR.h"
#include "Scene.h"
#include "ShaderLib.h"
#include <QOpenGLFunctions_4_0_Core>

void MaterialPBR::init()
{
auto shaderPtr = m_shaderLib->getCurrentShader();

shaderPtr->setPatchVertexCount(3);
shaderPtr->setUniformValue("albedo", QVector3D{m_albedo.x, m_albedo.y, m_albedo.z});
shaderPtr->setUniformValue("ao", m_ao);
shaderPtr->setUniformValue("exposure", m_exposure);
Expand Down
80 changes: 79 additions & 1 deletion src/ShaderLib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
#include <QFile>
#include <QJsonObject>
#include <QJsonDocument>
#include <string>
#include <fstream>
#include <streambuf>
#include <regex>

std::string ShaderLib::loadShaderProg(const QString &_jsonFileName)
{
Expand Down Expand Up @@ -52,7 +56,10 @@ void ShaderLib::createShader(const std::string &_name, const std::array<QString,
if (!m_shaderParts.count(stdPath))
{
QOpenGLShader* shad = new QOpenGLShader(qShaders[shader]);
shad->compileSourceFile(path);
std::string shaderString = loadFileToString(stdPath);
parseIncludes(shaderString);

shad->compileSourceCode(shaderString.c_str());
m_shaderParts[stdPath].reset(shad);
}
program->addShader(m_shaderParts[stdPath].get());
Expand All @@ -61,6 +68,77 @@ void ShaderLib::createShader(const std::string &_name, const std::array<QString,
m_shaderPrograms[_name].reset(program);
}

namespace std
{

template<class BidirIt, class Traits, class CharT, class UnaryFunction>
std::basic_string<CharT> regex_replace(BidirIt _first, BidirIt _last, const std::basic_regex<CharT,Traits>& _re, UnaryFunction _f)
{
std::basic_string<CharT> s;

typename std::match_results<BidirIt>::difference_type positionOfLastMatch = 0;
auto endOfLastMatch = _first;

auto callback = [&](const std::match_results<BidirIt>& match)
{
auto positionOfThisMatch = match.position(0);
auto diff = positionOfThisMatch - positionOfLastMatch;

auto startOfThisMatch = endOfLastMatch;
std::advance(startOfThisMatch, diff);

s.append(endOfLastMatch, startOfThisMatch);
s.append(_f(match));

auto lengthOfMatch = match.length(0);

positionOfLastMatch = positionOfThisMatch + lengthOfMatch;

endOfLastMatch = startOfThisMatch;
std::advance(endOfLastMatch, lengthOfMatch);
};

std::regex_iterator<BidirIt> begin(_first, _last, _re), end;
std::for_each(begin, end, callback);

s.append(endOfLastMatch, _last);

return s;
}

template<class Traits, class CharT, class UnaryFunction>
std::string regex_replace(const std::string& s, const std::basic_regex<CharT,Traits>& re, UnaryFunction f)
{
return regex_replace(s.cbegin(), s.cend(), re, f);
}

} // namespace std

std::string ShaderLib::loadFileToString(const std::string &_path)
{
std::string ret;
std::ifstream shaderFileStream(_path);
shaderFileStream.seekg(0, std::ios::end);
ret.reserve(shaderFileStream.tellg());
shaderFileStream.seekg(0, std::ios::beg);

ret.assign((std::istreambuf_iterator<char>(shaderFileStream)), std::istreambuf_iterator<char>());
return ret;
}

void ShaderLib::parseIncludes(std::string &io_shaderString)
{
std::regex matcher(R"(#{1}include\ +(\"|\<)[a-zA-Z][a-zA-Z0-9_\/]+\.(h|glsl)(\"|\>))");
io_shaderString = std::regex_replace(io_shaderString, matcher, [this](const std::smatch& _m)
{
auto str = _m.str();
auto begin = str.find('"') + 1;
auto end = str.find_last_of('"');
return loadFileToString(std::string(str.begin() + begin, str.begin() + end));
}
);
}

void ShaderLib::useShader(const std::string& _name)
{
m_currentShader = m_shaderPrograms[_name].get();
Expand Down

0 comments on commit 15eadba

Please sign in to comment.