diff --git a/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp b/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp index a5c0f20b3a..b7d6cb6a88 100644 --- a/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp +++ b/src/Mod/CAM/PathSimulator/AppGL/GuiDisplay.cpp @@ -139,7 +139,7 @@ bool GuiDisplay::InitGui() mThumbMaxMotion = (float)guiItems[eGuiItemSlider].texItem.w; // init shader - mShader.CompileShader((char*)VertShader2DTex, (char*)FragShader2dTex); + mShader.CompileShader("GuiDisplay", (char*)VertShader2DTex, (char*)FragShader2dTex); mShader.UpdateTextureSlot(0); UpdateSimSpeed(1); diff --git a/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.cpp b/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.cpp index 77344bc7b6..8e1269868b 100644 --- a/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.cpp +++ b/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.cpp @@ -372,9 +372,11 @@ void MillSimulation::Render() RenderBaseShape(); RenderPath(); simDisplay.updateDisplay = false; + simDisplay.RenderResult(true); + } + else { + simDisplay.RenderResult(false); } - - simDisplay.RenderResult(); /* if (mDebug > 0) { mat4x4 test; diff --git a/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.h b/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.h index e7ade679ae..a4ba8830a0 100644 --- a/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.h +++ b/src/Mod/CAM/PathSimulator/AppGL/MillSimulation.h @@ -115,8 +115,8 @@ protected: SolidObject mBaseShape; vec3 bgndColor = {0.1f, 0.2f, 0.3f}; - vec3 stockColor = {0.7f, 0.75f, 0.9f}; - vec3 cutColor = {0.85f, 0.95f, 0.85f}; + vec3 stockColor = {0.5f, 0.55f, 0.9f}; + vec3 cutColor = {0.5f, 0.84f, 0.73f}; vec3 toolColor = {0.5f, 0.4f, 0.3f}; vec3 baseShapeColor = {0.7f, 0.6f, 0.5f}; diff --git a/src/Mod/CAM/PathSimulator/AppGL/OpenGlWrapper.h b/src/Mod/CAM/PathSimulator/AppGL/OpenGlWrapper.h index 415036ec24..8eee113a74 100644 --- a/src/Mod/CAM/PathSimulator/AppGL/OpenGlWrapper.h +++ b/src/Mod/CAM/PathSimulator/AppGL/OpenGlWrapper.h @@ -86,4 +86,7 @@ extern QOpenGLContext* gOpenGlContext; #define glVertexAttribIPointer gSimWindow->glVertexAttribIPointer #define glUniform4fv gSimWindow->glUniform4fv #define glLineWidth gSimWindow->glLineWidth +#define glGetShaderiv gSimWindow->glGetShaderiv +#define glGetShaderInfoLog gSimWindow->glGetShaderInfoLog + #endif // !__openglwrapper_h__ diff --git a/src/Mod/CAM/PathSimulator/AppGL/Shader.cpp b/src/Mod/CAM/PathSimulator/AppGL/Shader.cpp index d587f1e35c..52d746d903 100644 --- a/src/Mod/CAM/PathSimulator/AppGL/Shader.cpp +++ b/src/Mod/CAM/PathSimulator/AppGL/Shader.cpp @@ -18,11 +18,20 @@ * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * + * * + * Portions of this code are taken from: * + * "OpenGL 4 Shading Language cookbook" Third edition * + * Written by: David Wolff * + * Published by: www.packt.com * + * License: MIT License * + * * + * * ***************************************************************************/ #include "GlUtils.h" #include "Shader.h" #include +#include namespace MillSim { @@ -74,6 +83,16 @@ void Shader::UpdateEnvColor(vec3 lightPos, vec3 lightColor, vec3 ambient, float } } +void Shader::UpdateScreenDimension(int width, int height) +{ + if (mScreenWidthPos >= 0) { + glUniform1f(mScreenWidthPos, (float)width); + } + if (mScreenHeightPos >= 0) { + glUniform1f(mScreenHeightPos, (float)height); + } +} + void Shader::UpdateObjColor(vec3 objColor) { if (mObjectColorPos >= 0) { @@ -95,6 +114,13 @@ void Shader::UpdateNormalState(bool isInverted) } } +void Shader::UpdateSsaoActive(bool isActive) +{ + if (mSsaoActivePos >= 0) { + glUniform1i(mSsaoActivePos, isActive); + } +} + void Shader::UpdateTextureSlot(int slot) { if (mTexSlotPos >= 0) { @@ -102,7 +128,7 @@ void Shader::UpdateTextureSlot(int slot) } } -void Shader::UpdateAlbedoTexSlot(int albedoSlot) +void Shader::UpdateColorTexSlot(int albedoSlot) { if (mAlbedoPos >= 0) { glUniform1i(mAlbedoPos, albedoSlot); @@ -123,10 +149,10 @@ void Shader::UpdateNormalTexSlot(int normalSlot) } } -void Shader::UpdateNoiseTexSlot(int noiseSlot) +void Shader::UpdateRandomTexSlot(int randSlot) { - if (mNoisePos >= 0) { - glUniform1i(mNoisePos, noiseSlot); + if (mRandTexPos >= 0) { + glUniform1i(mRandTexPos, randSlot); } } @@ -150,31 +176,32 @@ void Shader::UpdateCurSegment(int curSeg) } -#ifdef QT_OPENGL_LIB -bool CheckCompileResult(int /* shader */) -{ - return false; -#else -bool CheckCompileResult(int shader) +bool CheckCompileResult(int shaderId, const char* shaderName, bool isVertex) { char log[1024]; int res = 0; GLsizei len; - glGetShaderiv(shader, GL_COMPILE_STATUS, &res); + glGetShaderiv(shaderId, GL_COMPILE_STATUS, &res); if (res != 0) { return false; } - glGetShaderInfoLog(shader, 1020, &len, log); + int headerLen = snprintf(log, + 48, + "Error compiling %s %s shader: ", + shaderName, + isVertex ? "vertex" : "fragment"); + glGetShaderInfoLog(shaderId, 1020 - headerLen, &len, log + headerLen); + len += headerLen; if (len > 1020) { len = 1020; } log[len] = 0; - std::cout << log << std::endl; + Base::Console().Error(log); return true; -#endif } -unsigned int Shader::CompileShader(const char* _vertShader, const char* _fragShader) +unsigned int +Shader::CompileShader(const char* name, const char* _vertShader, const char* _fragShader) { vertShader = _vertShader; fragShader = _fragShader; @@ -182,7 +209,7 @@ unsigned int Shader::CompileShader(const char* _vertShader, const char* _fragSha GLint res = 0; glShaderSource(vertex_shader, 1, &vertShader, NULL); glCompileShader(vertex_shader); - if (CheckCompileResult(vertex_shader)) { + if (CheckCompileResult(vertex_shader, name, true)) { glDeleteShader(vertex_shader); return 0xdeadbeef; } @@ -190,7 +217,7 @@ unsigned int Shader::CompileShader(const char* _vertShader, const char* _fragSha const GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment_shader, 1, &fragShader, NULL); glCompileShader(fragment_shader); - if (CheckCompileResult(fragment_shader)) { + if (CheckCompileResult(fragment_shader, name, false)) { glDeleteShader(fragment_shader); glDeleteShader(vertex_shader); return 0xdeadbeef; @@ -220,14 +247,16 @@ unsigned int Shader::CompileShader(const char* _vertShader, const char* _fragSha mObjectColorAlphaPos = glGetUniformLocation(shaderId, "objectColorAlpha"); mTexSlotPos = glGetUniformLocation(shaderId, "texSlot"); mInvertedNormalsPos = glGetUniformLocation(shaderId, "invertedNormals"); - mSsaoSamplesPos = glGetUniformLocation(shaderId, "ssaoSamples"); - mAlbedoPos = glGetUniformLocation(shaderId, "texAlbedo"); - mPositionPos = glGetUniformLocation(shaderId, "texPosition"); - mNormalPos = glGetUniformLocation(shaderId, "texNormal"); - mSsaoPos = glGetUniformLocation(shaderId, "texSsao"); - mNoisePos = glGetUniformLocation(shaderId, "texNoise"); - mSamplesPos = glGetUniformLocation(shaderId, "ssaoSamples"); + mSsaoActivePos = glGetUniformLocation(shaderId, "ssaoActive"); + mAlbedoPos = glGetUniformLocation(shaderId, "ColorTex"); + mPositionPos = glGetUniformLocation(shaderId, "PositionTex"); + mNormalPos = glGetUniformLocation(shaderId, "NormalTex"); + mSsaoPos = glGetUniformLocation(shaderId, "AoTex"); + mRandTexPos = glGetUniformLocation(shaderId, "RandTex"); + mSamplesPos = glGetUniformLocation(shaderId, "SampleKernel"); mCurSegmentPos = glGetUniformLocation(shaderId, "curSegment"); + mScreenWidthPos = glGetUniformLocation(shaderId, "screenWidth"); + mScreenHeightPos = glGetUniformLocation(shaderId, "screenHeight"); Activate(); return shaderId; @@ -258,7 +287,7 @@ const char* VertShader3DNorm = R"( layout(location = 1) in vec3 aNormal; out vec3 Normal; - out vec3 FragPos; + out vec3 Position; uniform mat4 model; uniform mat4 view; @@ -268,7 +297,7 @@ const char* VertShader3DNorm = R"( void main(void) { vec4 viewPos = view * model * vec4(aPosition, 1.0); - FragPos = vec3(model * vec4(aPosition, 1.0)); + Position = vec3(model * vec4(aPosition, 1.0)); Normal = vec3(normalRot * vec4(aNormal, 1.0)); gl_Position = projection * viewPos; } @@ -281,7 +310,7 @@ const char* VertShader3DInvNorm = R"( layout(location = 1) in vec3 aNormal; out vec3 Normal; - out vec3 FragPos; + out vec3 Position; uniform mat4 model; uniform mat4 view; @@ -291,7 +320,7 @@ const char* VertShader3DInvNorm = R"( void main(void) { gl_Position = projection * view * model * vec4(aPosition, 1.0); - FragPos = vec3(model * vec4(aPosition, 1.0)); + Position = vec3(model * vec4(aPosition, 1.0)); Normal = -vec3(normalRot * vec4(aNormal, 1.0)); } )"; @@ -338,7 +367,7 @@ const char* FragShaderNorm = R"( out vec4 FragColor; in vec3 Normal; - in vec3 FragPos; + in vec3 Position; uniform vec3 lightPos; uniform vec3 lightColor; @@ -348,7 +377,7 @@ const char* FragShaderNorm = R"( void main() { vec3 norm = normalize(Normal); - vec3 lightDir = normalize(lightPos - FragPos); + vec3 lightDir = normalize(lightPos - Position); float diff = max(dot(norm, lightDir), 0.0); vec3 diffuse = diff * lightColor; vec3 result = (lightAmbient + diffuse) * objectColor; @@ -362,7 +391,7 @@ const char* FragShaderFlat = R"( out vec4 FragColor; in vec3 Normal; - in vec3 FragPos; + in vec3 Position; uniform vec3 objectColor; void main() @@ -407,7 +436,7 @@ const char* VertShaderGeom = R"( layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; - out vec3 FragPos; + out vec3 Position; out vec3 Normal; uniform bool invertedNormals; @@ -419,7 +448,7 @@ const char* VertShaderGeom = R"( void main() { vec4 viewPos = view * model * vec4(aPos, 1.0); - FragPos = viewPos.xyz; + Position = viewPos.xyz; mat3 normalMatrix = transpose(inverse(mat3(view * model))); Normal = normalMatrix * (invertedNormals ? -aNormal : aNormal); @@ -430,82 +459,99 @@ const char* VertShaderGeom = R"( const char* FragShaderGeom = R"( #version 330 core - layout (location = 0) out vec4 texAlbedo; - layout (location = 1) out vec3 texPosition; - layout (location = 2) out vec3 texNormal; + layout (location = 0) out vec4 ColorTex; + layout (location = 1) out vec3 PositionTex; + layout (location = 2) out vec3 NormalTex; - in vec3 FragPos; + in vec3 Position; in vec3 Normal; uniform vec3 objectColor; void main() { - // store the fragment position vector in the first gbuffer texture - texPosition = FragPos; - // also store the per-fragment normals into the gbuffer - texNormal = normalize(Normal); - // and the diffuse per-fragment color - texAlbedo = vec4(objectColor, 1.0f); + // Store position, normal, and diffuse color in textures + PositionTex = Position; + NormalTex = normalize(Normal); + ColorTex = vec4(objectColor, 1.0f); } )"; const char* FragShaderSSAO = R"( #version 330 core - out vec4 FragColor; + layout (location = 0) out float AoData; in vec2 texCoord; - uniform sampler2D texNoise; - uniform sampler2D texPosition; - uniform sampler2D texNormal; + uniform sampler2D RandTex; + uniform sampler2D PositionTex; + uniform sampler2D NormalTex; - uniform vec3 ssaoSamples[64]; - - // parameters (you'd probably want to use them as uniforms to more easily tweak the effect) - int kernelSize = 64; - float radius = 30f; - float bias = 0.01; - - // tile noise texture over screen based on screen dimensions divided by noise size - const vec2 noiseScale = vec2(800.0/4.0, 600.0/4.0); + const int kernelSize = 64; + uniform vec3 SampleKernel[kernelSize]; + uniform float Radius = 20.0f; + uniform float screenWidth = 800.0; + uniform float screenHeight = 600.0; uniform mat4 projection; void main() { - // get input for SSAO algorithm - vec3 fragPos = texture(texPosition, texCoord).xyz; - vec3 normal = normalize(texture(texNormal, texCoord).rgb); - vec3 randomVec = normalize(texture(texNoise, texCoord * noiseScale).xyz); - // create TBN change-of-basis matrix: from tangent-space to view-space - vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal)); - vec3 bitangent = cross(normal, tangent); - mat3 TBN = mat3(tangent, bitangent, normal); - // iterate over the sample kernel and calculate occlusion factor - float occlusion = 0.0; - for(int i = 0; i < kernelSize; ++i) - { - // get sample position - vec3 samplePos = TBN * ssaoSamples[i]; // from tangent to view-space - samplePos = fragPos + samplePos * radius; + // Create the random tangent space matrix + vec2 randScale = vec2( screenWidth / 4.0, screenHeight / 4.0 ); + vec3 randDir = normalize( texture(RandTex, texCoord.xy * randScale).xyz ); + vec3 n = normalize( texture(NormalTex, texCoord).xyz ); + vec3 biTang = cross( n, randDir ); + if( length(biTang) < 0.0001 ) // If n and randDir are parallel, n is in x-y plane + biTang = cross( n, vec3(0,0,1)); + biTang = normalize(biTang); + vec3 tang = cross(biTang, n); + mat3 toCamSpace = mat3(tang, biTang, n); - // project sample position (to sample texture) (to get position on screen/texture) - vec4 offset = vec4(samplePos, 1.0); - offset = projection * offset; // from view to clip-space - offset.xyz /= offset.w; // perspective divide - offset.xyz = offset.xyz * 0.5 + 0.5; // transform to range 0.0 - 1.0 + float occlusionSum = 0.0; + vec3 camPos = texture(PositionTex, texCoord).xyz; + for( int i = 0; i < kernelSize; i++ ) { + vec3 samplePos = camPos + Radius * (toCamSpace * SampleKernel[i]); - // get sample depth - float sampleDepth = texture(texPosition, offset.xy).z; // get depth value of kernel - // sample + // Project point + vec4 p = projection * vec4(samplePos,1); + p *= 1.0 / p.w; + p.xyz = p.xyz * 0.5 + 0.5; - // range check & accumulate - float rangeCheck = smoothstep(0.0, 1.0, radius * 0.1f / abs(sampleDepth - fragPos.z)); - occlusion += (sampleDepth >= samplePos.z + bias ? 1.0 : 0.0) * rangeCheck; + // Access camera space z-coordinate at that point + float surfaceZ = texture(PositionTex, p.xy).z; + float zDist = surfaceZ - camPos.z; + + // Count points that ARE occluded + if( zDist >= 0.0 && zDist <= Radius && surfaceZ > samplePos.z ) occlusionSum += 1.0; } - occlusion = 1.0 - (occlusion / kernelSize); - FragColor = vec4(occlusion, 0, 0, 1); + + float occ = occlusionSum / kernelSize; + AoData = 1.0 - occ; + } +)"; + + +const char* FragShaderSSAOBlur = R"( + #version 330 core + layout (location = 0) out float AoData; + + in vec2 texCoord; + + uniform sampler2D AoTex; + + void main() + { + ivec2 pix = ivec2( gl_FragCoord.xy ); + float sum = 0.0; + for( int x = -1; x <= 2; ++x ) { + for( int y = -1; y <= 2; y++ ) { + sum += texelFetchOffset( AoTex, pix, 0, ivec2(x,y) ).r; + } + } + + float ao = sum * (1.0 / 16.0); + AoData = ao; } )"; @@ -515,112 +561,40 @@ const char* FragShaderSSAOLighting = R"( in vec2 texCoord; - uniform sampler2D texSsao; - uniform sampler2D texAlbedo; - uniform sampler2D texPosition; - uniform sampler2D texNormal; - uniform vec3 lightPos; uniform vec3 lightColor; uniform vec3 lightAmbient; - uniform float lightLinear; + uniform bool ssaoActive; + + uniform sampler2D ColorTex; + uniform sampler2D PositionTex; + uniform sampler2D NormalTex; + uniform sampler2D AoTex; + + vec3 ambAndDiffuse( vec3 pos, vec3 norm, vec3 diff, float ao ) { + ao = pow(ao, 4); + vec3 ambient = lightAmbient * diff * ao; + vec3 s = normalize( lightPos - pos); + float sDotN = max( dot(s,norm), 0.0 ); + return ambient + lightColor * diff * sDotN; + } void main() { - // retrieve data from gbuffer - vec4 DiffuseA = texture(texAlbedo, texCoord); - vec3 Diffuse = DiffuseA.rgb; - vec3 FragPos = texture(texPosition, texCoord).rgb; - vec3 Normal = texture(texNormal, texCoord).rgb; - float AmbientOcclusion = texture(texSsao, texCoord).r; + vec3 pos = texture( PositionTex, texCoord ).xyz; + vec3 norm = texture( NormalTex, texCoord ).xyz; + vec4 DiffColorA = texture(ColorTex, texCoord); + vec3 diffColor = DiffColorA.rgb; + float aoVal = ssaoActive ? texture( AoTex, texCoord).r : 1.0; - // then calculate lighting as usual - vec3 lighting = lightAmbient * Diffuse * AmbientOcclusion; - vec3 viewDir = normalize(-FragPos); // viewpos is (0.0.0) - // diffuse - vec3 lightDir = normalize(lightPos - FragPos); - vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * lightColor; - // specular - vec3 halfwayDir = normalize(lightDir + viewDir); - float spec = pow(max(dot(Normal, halfwayDir), 0.0), 16.0); - vec3 specular = lightColor * spec; - // attenuation - float distance = length(lightPos - FragPos); - float attenuation = 1.0 / (1.0 + lightLinear * distance); - lighting += (diffuse + specular * 0.3) * attenuation; + vec3 col = ambAndDiffuse(pos, norm, diffColor, aoVal); + col = pow(col, vec3(1.0/2.2)); - FragColor = vec4(lighting, DiffuseA.a); + FragColor = vec4( col, DiffColorA.a ); } )"; -const char* FragShaderStdLighting = R"( - #version 330 core - out vec4 FragColor; - - in vec2 texCoord; - - uniform sampler2D texAlbedo; - uniform sampler2D texPosition; - uniform sampler2D texNormal; - - uniform vec3 lightPos; - uniform vec3 lightColor; - uniform float lightLinear; - uniform vec3 lightAmbient; - - void main() - { - // retrieve data from gbuffer - vec4 DiffuseA = texture(texAlbedo, texCoord); - vec3 Diffuse = DiffuseA.rgb; - vec3 FragPos = texture(texPosition, texCoord).rgb; - vec3 Normal = texture(texNormal, texCoord).rgb; - - // then calculate lighting as usual - vec3 lighting = lightAmbient * Diffuse; - vec3 viewDir = normalize(-FragPos); // viewpos is (0.0.0) - // diffuse - vec3 lightDir = normalize(lightPos - FragPos); - vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * lightColor; - // specular - vec3 halfwayDir = normalize(lightDir + viewDir); - float spec = pow(max(dot(Normal, halfwayDir), 0.0), 16.0); - vec3 specular = lightColor * spec; - // attenuation - float distance = length(lightPos - FragPos); - float attenuation = 1.0 / (1.0 + lightLinear * distance); - lighting += (diffuse + specular * 0.3) * attenuation; - - FragColor = vec4(lighting, DiffuseA.a); - } -)"; - -const char* FragShaderSSAOBlur = R"( - #version 330 core - out vec4 FragColor; - - in vec2 texCoord; - - uniform sampler2D texSsao; - - void main() - { - vec2 texelSize = 1.0 / vec2(textureSize(texSsao, 0)); - float result = 0.0; - for (int x = -2; x <= 1; ++x) - { - for (int y = -2; y <= 1; ++y) - { - vec2 offset = vec2(float(x), float(y)) * texelSize; - result += texture(texSsao, texCoord + offset).r; - } - } - FragColor = vec4(result / (4.0 * 4.0), 0, 0, 1); - } -)"; - - const char* VertShader3DLine = R"( #version 330 core diff --git a/src/Mod/CAM/PathSimulator/AppGL/Shader.h b/src/Mod/CAM/PathSimulator/AppGL/Shader.h index 47c867fb72..febe57547f 100644 --- a/src/Mod/CAM/PathSimulator/AppGL/Shader.h +++ b/src/Mod/CAM/PathSimulator/AppGL/Shader.h @@ -41,18 +41,20 @@ public: void UpdateProjectionMat(mat4x4 mat); void UpdateViewMat(mat4x4 mat); void UpdateEnvColor(vec3 lightPos, vec3 lightColor, vec3 ambient, float linearity); + void UpdateScreenDimension(int width, int height); void UpdateObjColor(vec3 objColor); void UpdateObjColorAlpha(vec4 objColor); void UpdateNormalState(bool isInverted); + void UpdateSsaoActive(bool isInverted); void UpdateTextureSlot(int slot); - void UpdateAlbedoTexSlot(int albedoSlot); + void UpdateColorTexSlot(int albedoSlot); void UpdatePositionTexSlot(int positionSlot); void UpdateNormalTexSlot(int normalSlot); - void UpdateNoiseTexSlot(int noiseSlot); + void UpdateRandomTexSlot(int noiseSlot); void UpdateSsaoTexSlot(int ssaoSlot); void UpdateKernelVals(int nVals, float* vals); void UpdateCurSegment(int curSeg); - unsigned int CompileShader(const char* vertShader, const char* fragShader); + unsigned int CompileShader(const char* name, const char* vertShader, const char* fragShader); void Activate(); void Destroy(); bool IsValid() @@ -74,14 +76,16 @@ protected: int mObjectColorAlphaPos = -1; int mTexSlotPos = -1; int mInvertedNormalsPos = -1; - int mSsaoSamplesPos = -1; + int mSsaoActivePos = -1; int mAlbedoPos = -1; int mPositionPos = -1; int mNormalPos = -1; int mSsaoPos = -1; - int mNoisePos = -1; + int mRandTexPos = -1; int mSamplesPos = -1; int mCurSegmentPos = -1; + int mScreenWidthPos = -1; + int mScreenHeightPos = -1; const char* vertShader = nullptr; const char* fragShader = nullptr; diff --git a/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.cpp b/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.cpp index 5ddcb028ec..e68dd14c1a 100644 --- a/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.cpp +++ b/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.cpp @@ -18,14 +18,19 @@ * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * + * * + * Portions of this code are taken from: * + * "OpenGL 4 Shading Language cookbook" Third edition * + * Written by: David Wolff * + * Published by: www.packt.com * + * License: MIT License * + * * + * * ***************************************************************************/ #include "SimDisplay.h" #include "linmath.h" #include "OpenGlWrapper.h" -#include - -#define GL_UBYTE GL_UNSIGNED_BYTE namespace MillSim @@ -35,51 +40,44 @@ void SimDisplay::InitShaders() { // use shaders // standard diffuse shader - shader3D.CompileShader(VertShader3DNorm, FragShaderNorm); + shader3D.CompileShader("StdDiffuse", VertShader3DNorm, FragShaderNorm); shader3D.UpdateEnvColor(lightPos, lightColor, ambientCol, 0.0f); // invarted normal diffuse shader for inner mesh - shaderInv3D.CompileShader(VertShader3DInvNorm, FragShaderNorm); + shaderInv3D.CompileShader("InvertNormal", VertShader3DInvNorm, FragShaderNorm); shaderInv3D.UpdateEnvColor(lightPos, lightColor, ambientCol, 0.0f); // null shader to calculate meshes only (simulation stage) - shaderFlat.CompileShader(VertShader3DNorm, FragShaderFlat); + shaderFlat.CompileShader("Null", VertShader3DNorm, FragShaderFlat); // texture shader to render Simulator FBO - shaderSimFbo.CompileShader(VertShader2DFbo, FragShader2dFbo); + shaderSimFbo.CompileShader("Texture", VertShader2DFbo, FragShader2dFbo); shaderSimFbo.UpdateTextureSlot(0); // geometric shader - generate texture with all geometric info for further processing - shaderGeom.CompileShader(VertShaderGeom, FragShaderGeom); - shaderGeomCloser.CompileShader(VertShaderGeom, FragShaderGeom); - - // lighting shader - apply standard lighting based on geometric buffers - shaderLighting.CompileShader(VertShader2DFbo, FragShaderStdLighting); - shaderLighting.UpdateAlbedoTexSlot(0); - shaderLighting.UpdatePositionTexSlot(1); - shaderLighting.UpdateNormalTexSlot(2); - shaderLighting.UpdateEnvColor(lightPos, lightColor, ambientCol, 0.01f); + shaderGeom.CompileShader("Geometric", VertShaderGeom, FragShaderGeom); + shaderGeomCloser.CompileShader("GeomCloser", VertShaderGeom, FragShaderGeom); // SSAO shader - generate SSAO info and embed in texture buffer - shaderSSAO.CompileShader(VertShader2DFbo, FragShaderSSAO); - shaderSSAO.UpdateNoiseTexSlot(0); + shaderSSAO.CompileShader("SSAO", VertShader2DFbo, FragShaderSSAO); + shaderSSAO.UpdateRandomTexSlot(0); shaderSSAO.UpdatePositionTexSlot(1); shaderSSAO.UpdateNormalTexSlot(2); // SSAO blur shader - smooth generated SSAO texture - shaderSSAOBlur.CompileShader(VertShader2DFbo, FragShaderSSAOBlur); + shaderSSAOBlur.CompileShader("Blur", VertShader2DFbo, FragShaderSSAOBlur); shaderSSAOBlur.UpdateSsaoTexSlot(0); // SSAO lighting shader - apply lightig modified by SSAO calculations - shaderSSAOLighting.CompileShader(VertShader2DFbo, FragShaderSSAOLighting); - shaderSSAOLighting.UpdateAlbedoTexSlot(0); + shaderSSAOLighting.CompileShader("SsaoLighting", VertShader2DFbo, FragShaderSSAOLighting); + shaderSSAOLighting.UpdateColorTexSlot(0); shaderSSAOLighting.UpdatePositionTexSlot(1); shaderSSAOLighting.UpdateNormalTexSlot(2); shaderSSAOLighting.UpdateSsaoTexSlot(3); shaderSSAOLighting.UpdateEnvColor(lightPos, lightColor, ambientCol, 0.01f); // Mill Path Line Shader - shaderLinePath.CompileShader(VertShader3DLine, FragShader3DLine); + shaderLinePath.CompileShader("PathLine", VertShader3DLine, FragShader3DLine); } void SimDisplay::CreateFboQuad() @@ -101,6 +99,40 @@ void SimDisplay::CreateFboQuad() glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); } +void SimDisplay::CreateGBufTex(GLenum texUnit, + GLint intFormat, + GLenum format, + GLenum type, + GLuint& texid) +{ + glActiveTexture(texUnit); + glGenTextures(1, &texid); + glBindTexture(GL_TEXTURE_2D, texid); + glTexImage2D(GL_TEXTURE_2D, 0, intFormat, mWidth, mHeight, 0, format, type, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); +} + +void SimDisplay::UniformHemisphere(vec3& randVec) +{ + float x1 = distr01(generator); + float x2 = distr01(generator); + float s = sqrt(1.0f - x1 * x1); + randVec[0] = cosf(PI2 * x2) * s; + randVec[1] = sinf(PI2 * x2) * s; + randVec[2] = x1; +} + +void SimDisplay::UniformCircle(vec3& randVec) +{ + float x = distr01(generator); + randVec[0] = cosf(PI2 * x); + randVec[1] = sinf(PI2 * x); + randVec[2] = 0; +} + + void SimDisplay::CreateDisplayFbos() { // setup frame buffer for simulation @@ -108,51 +140,15 @@ void SimDisplay::CreateDisplayFbos() glBindFramebuffer(GL_FRAMEBUFFER, mFbo); // a color texture for the frame buffer - glGenTextures(1, &mFboColTexture); - glBindTexture(GL_TEXTURE_2D, mFboColTexture); - glTexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA8, - gWindowSizeW, - gWindowSizeH, - 0, - GL_RGBA, - GL_UBYTE, - NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + CreateGBufTex(GL_TEXTURE0, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, mFboColTexture); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFboColTexture, 0); // a position texture for the frame buffer - glGenTextures(1, &mFboPosTexture); - glBindTexture(GL_TEXTURE_2D, mFboPosTexture); - glTexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA16F, - gWindowSizeW, - gWindowSizeH, - 0, - GL_RGBA, - GL_FLOAT, - NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + CreateGBufTex(GL_TEXTURE1, GL_RGB32F, GL_RGBA, GL_FLOAT, mFboPosTexture); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mFboPosTexture, 0); // a normal texture for the frame buffer - glGenTextures(1, &mFboNormTexture); - glBindTexture(GL_TEXTURE_2D, mFboNormTexture); - glTexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA16F, - gWindowSizeW, - gWindowSizeH, - 0, - GL_RGBA, - GL_FLOAT, - NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + CreateGBufTex(GL_TEXTURE2, GL_RGB32F, GL_RGBA, GL_FLOAT, mFboNormTexture); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, mFboNormTexture, 0); @@ -166,8 +162,8 @@ void SimDisplay::CreateDisplayFbos() glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, - gWindowSizeW, - gWindowSizeH); // use a single renderbuffer object for both a depth AND stencil buffer. + mWidth, + mHeight); // use a single renderbuffer object for both a depth AND stencil buffer. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, @@ -180,7 +176,6 @@ void SimDisplay::CreateDisplayFbos() glBindFramebuffer(GL_FRAMEBUFFER, 0); } - void SimDisplay::CreateSsaoFbos() { @@ -190,11 +185,7 @@ void SimDisplay::CreateSsaoFbos() glGenFramebuffers(1, &mSsaoFbo); glBindFramebuffer(GL_FRAMEBUFFER, mSsaoFbo); // SSAO color buffer - glGenTextures(1, &mFboSsaoTexture); - glBindTexture(GL_TEXTURE_2D, mFboSsaoTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, gWindowSizeW, gWindowSizeH, 0, GL_RED, GL_FLOAT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + CreateGBufTex(GL_TEXTURE0, GL_R16F, GL_RED, GL_FLOAT, mFboSsaoTexture); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFboSsaoTexture, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { mSsaoValid = false; @@ -204,11 +195,7 @@ void SimDisplay::CreateSsaoFbos() // setup framebuffer for SSAO blur processing glGenFramebuffers(1, &mSsaoBlurFbo); glBindFramebuffer(GL_FRAMEBUFFER, mSsaoBlurFbo); - glGenTextures(1, &mFboSsaoBlurTexture); - glBindTexture(GL_TEXTURE_2D, mFboSsaoBlurTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, gWindowSizeW, gWindowSizeH, 0, GL_RED, GL_FLOAT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + CreateGBufTex(GL_TEXTURE0, GL_R16F, GL_RED, GL_FLOAT, mFboSsaoBlurTexture); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, @@ -222,46 +209,36 @@ void SimDisplay::CreateSsaoFbos() glBindFramebuffer(GL_FRAMEBUFFER, 0); // generate sample kernel - std::uniform_real_distribution randomFloats(0.0, 1.0); - std::default_random_engine generator; - for (unsigned int i = 0; i < 64; ++i) { + int kernSize = 64; + for (int i = 0; i < kernSize; i++) { vec3 sample; - vec3_set(sample, - randomFloats(generator) * 2.0f - 1.0f, - randomFloats(generator) * 2.0f - 1.0f, - randomFloats(generator)); // * 2.0f - 1.0f); - vec3_norm(sample, sample); - vec3_scale(sample, sample, randomFloats(generator)); - float scale = float(i) / 64.0f; - - // scale samples s.t. they're more aligned to center of kernel - scale = Lerp(0.1f, 1.0f, scale * scale); - vec3_scale(sample, sample, scale); + UniformHemisphere(sample); + float scale = ((float)(i * i)) / (kernSize * kernSize); + float interpScale = 0.1f * (1.0f - scale) + scale; + vec3_scale(sample, sample, interpScale); mSsaoKernel.push_back(*(Point3D*)sample); } shaderSSAO.Activate(); shaderSSAO.UpdateKernelVals(mSsaoKernel.size(), &mSsaoKernel[0].x); - // generate noise texture - std::vector ssaoNoise; - for (unsigned int i = 0; i < 16; i++) { - vec3 noise; - vec3_set(noise, - randomFloats(generator) * 2.0f - 1.0f, - randomFloats(generator) * 2.0f - 1.0f, - 0.0f); // rotate around z-axis (in tangent space) - ssaoNoise.push_back(*(Point3D*)noise); + // generate random direction texture + int randSize = 4 * 4; + std::vector randDirections; + for (int i = 0; i < randSize; i++) { + vec3 randvec; + UniformCircle(randvec); + randDirections.push_back(*(Point3D*)randvec); } - glGenTextures(1, &mFboSsaoNoiseTexture); - glBindTexture(GL_TEXTURE_2D, mFboSsaoNoiseTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 4, 4, 0, GL_RGB, GL_FLOAT, &ssaoNoise[0]); + + glGenTextures(1, &mFboRandTexture); + glBindTexture(GL_TEXTURE_2D, mFboRandTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 4, 4, 0, GL_RGB, GL_FLOAT, &randDirections[0].x); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } - SimDisplay::~SimDisplay() { CleanGL(); @@ -276,6 +253,8 @@ void SimDisplay::InitGL() // setup light object mlightObject.GenerateBoxStock(-0.5f, -0.5f, -0.5f, 1, 1, 1); + mWidth = gWindowSizeW; + mHeight = gWindowSizeH; InitShaders(); CreateDisplayFbos(); CreateSsaoFbos(); @@ -298,7 +277,7 @@ void SimDisplay::CleanFbos() GLDELETE_TEXTURE(mFboNormTexture); GLDELETE_TEXTURE(mFboSsaoTexture); GLDELETE_TEXTURE(mFboSsaoBlurTexture); - GLDELETE_TEXTURE(mFboSsaoNoiseTexture); + GLDELETE_TEXTURE(mFboRandTexture); GLDELETE_RENDERBUFFER(mRboDepthStencil); } @@ -317,7 +296,6 @@ void SimDisplay::CleanGL() shaderSimFbo.Destroy(); shaderGeom.Destroy(); shaderSSAO.Destroy(); - shaderLighting.Destroy(); shaderSSAOLighting.Destroy(); shaderSSAOBlur.Destroy(); @@ -394,10 +372,10 @@ void SimDisplay::ScaleViewToStock(StockObject* obj) mlightObject.SetPosition(lightPos); } -void SimDisplay::RenderResult() +void SimDisplay::RenderResult(bool recalculate) { if (mSsaoValid && applySSAO) { - RenderResultSSAO(); + RenderResultSSAO(recalculate); } else { RenderResultStandard(); @@ -410,7 +388,11 @@ void SimDisplay::RenderResultStandard() glBindFramebuffer(GL_FRAMEBUFFER, 0); // display the sim result within the FBO - shaderLighting.Activate(); + shaderSSAOLighting.Activate(); + shaderSSAOLighting.UpdateColorTexSlot(0); + shaderSSAOLighting.UpdatePositionTexSlot(1); + shaderSSAOLighting.UpdateNormalTexSlot(2); + shaderSSAOLighting.UpdateSsaoActive(false); // shaderSimFbo.Activate(); glBindVertexArray(mFboQuadVAO); glDisable(GL_DEPTH_TEST); @@ -426,47 +408,57 @@ void SimDisplay::RenderResultStandard() glDrawArrays(GL_TRIANGLES, 0, 6); } -void SimDisplay::RenderResultSSAO() +void SimDisplay::RenderResultSSAO(bool recalculate) { + glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); - // generate SSAO texture - glBindFramebuffer(GL_FRAMEBUFFER, mSsaoFbo); - shaderSSAO.Activate(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mFboSsaoNoiseTexture); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, mFboPosTexture); - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, mFboNormTexture); - glBindVertexArray(mFboQuadVAO); - glDrawArrays(GL_TRIANGLES, 0, 6); + if (recalculate) { + // generate SSAO texture + glBindFramebuffer(GL_FRAMEBUFFER, mSsaoFbo); + shaderSSAO.Activate(); + shaderSSAO.UpdateRandomTexSlot(0); + shaderSSAO.UpdatePositionTexSlot(1); + shaderSSAO.UpdateNormalTexSlot(2); + shaderSSAO.UpdateScreenDimension(mWidth, mHeight); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, mFboRandTexture); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, mFboPosTexture); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, mFboNormTexture); + glBindVertexArray(mFboQuadVAO); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // blur SSAO texture to remove noise + glBindFramebuffer(GL_FRAMEBUFFER, mSsaoBlurFbo); + glClear(GL_COLOR_BUFFER_BIT); + shaderSSAOBlur.Activate(); + shaderSSAOBlur.UpdateSsaoTexSlot(0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, mFboSsaoTexture); + glBindVertexArray(mFboQuadVAO); + glDrawArrays(GL_TRIANGLES, 0, 6); + } + + // lighting pass: glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // blur SSAO texture to remove noise - glBindFramebuffer(GL_FRAMEBUFFER, mSsaoBlurFbo); - glClear(GL_COLOR_BUFFER_BIT); - shaderSSAOBlur.Activate(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mFboSsaoTexture); - glBindVertexArray(mFboQuadVAO); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // lighting pass: deferred Blinn-Phong lighting with added screen-space ambient occlusion shaderSSAOLighting.Activate(); - shaderSSAOLighting.UpdateAlbedoTexSlot(0); + shaderSSAOLighting.UpdateColorTexSlot(0); shaderSSAOLighting.UpdatePositionTexSlot(1); shaderSSAOLighting.UpdateNormalTexSlot(2); shaderSSAOLighting.UpdateSsaoTexSlot(3); + shaderSSAOLighting.UpdateSsaoActive(true); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mFboColTexture); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, mFboPosTexture); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, mFboNormTexture); - glActiveTexture(GL_TEXTURE3); // add extra SSAO texture to lighting pass + glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, mFboSsaoBlurTexture); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -544,6 +536,8 @@ void SimDisplay::UpdateEyeFactor(float factor) void SimDisplay::UpdateWindowScale() { + mWidth = gWindowSizeW; + mHeight = gWindowSizeH; glBindFramebuffer(GL_FRAMEBUFFER, mFbo); CleanFbos(); CreateDisplayFbos(); diff --git a/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.h b/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.h index 29a2ff78f1..079918225e 100644 --- a/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.h +++ b/src/Mod/CAM/PathSimulator/AppGL/SimDisplay.h @@ -28,7 +28,8 @@ #include "StockObject.h" #include "MillPathLine.h" #include - +#include +#include namespace MillSim { @@ -52,9 +53,9 @@ public: void StartCloserGeometryPass(vec3 objColor); void RenderLightObject(); void ScaleViewToStock(StockObject* obj); - void RenderResult(); + void RenderResult(bool recalculate); void RenderResultStandard(); - void RenderResultSSAO(); + void RenderResultSSAO(bool recalculate); void SetupLinePathPass(int curSegment, bool isHidden); void TiltEye(float tiltStep); void RotateEye(float rotStep); @@ -79,20 +80,19 @@ protected: void CreateDisplayFbos(); void CreateSsaoFbos(); void CreateFboQuad(); - float Lerp(float a, float b, float f) - { - return a + f * (b - a); - } + void CreateGBufTex(GLenum texUnit, GLint intFormat, GLenum format, GLenum type, GLuint& texid); + void UniformHemisphere(vec3& randVec); + void UniformCircle(vec3& randVec); protected: // shaders Shader shader3D, shaderInv3D, shaderFlat, shaderSimFbo; - Shader shaderGeom, shaderSSAO, shaderLighting, shaderSSAOLighting, shaderSSAOBlur; + Shader shaderGeom, shaderSSAO, shaderSSAOLighting, shaderSSAOBlur; Shader shaderGeomCloser; Shader shaderLinePath; - vec3 lightColor = {0.8f, 0.9f, 1.0f}; + vec3 lightColor = {0.5f, 0.6f, 0.7f}; vec3 lightPos = {20.0f, 20.0f, 10.0f}; - vec3 ambientCol = {0.6f, 0.6f, 0.7f}; + vec3 ambientCol = {0.2f, 0.2f, 0.25f}; vec4 pathLineColor = {0.0f, 0.9f, 0.0f, 1.0}; vec3 pathLineColorPassed = {0.9f, 0.3f, 0.3f}; @@ -103,6 +103,12 @@ protected: mat4x4 mMatLookAt; StockObject mlightObject; + int mWidth; + int mHeight; + + std::mt19937 generator; + std::uniform_real_distribution distr01; + float mEyeDistance = 30; float mEyeRoration = 0; @@ -131,7 +137,7 @@ protected: unsigned int mSsaoBlurFbo; unsigned int mFboSsaoTexture; unsigned int mFboSsaoBlurTexture; - unsigned int mFboSsaoNoiseTexture; + unsigned int mFboRandTexture; }; } // namespace MillSim