Skip to content
Snippets Groups Projects

Feature/line shadows

Merged Aaron Grabowy requested to merge feature/line-shadows into develop
2 files
+ 220
145
Compare changes
  • Side-by-side
  • Inline
Files
2
@@ -20,7 +20,32 @@ aabb LineRenderable::computeAabb()
return aabb;
}
void LineRenderable::renderShadow(RenderInfo const&) {}
void LineRenderable::renderShadow(RenderInfo const& info)
{
auto shader = mShadowShader->use();
shader.setUniform("uModel", transform());
shader.setUniform("uInvModel", inverse(transform()));
shader.setUniform("uNoCaps", mNoCaps);
shader.setUniform("uWorldSpaceSize", mWorldSpaceSize);
shader.setUniform("uCameraFacing", mCameraFacing);
shader.setUniform("uScreenSize", tg::vec2(info.resolution));
shader.setUniform("uView", info.view);
shader.setUniform("uInvView", tg::inverse(info.view));
shader.setUniform("uInvProj", tg::inverse(info.proj));
shader.setUniform("uProj", info.proj);
shader.setUniform("uCamPos", info.camPos);
if (m3D)
{
auto const tanHalfFovY = 1.f / tg::abs(info.proj[1][1]);
shader.setUniform("uTanFov2", tanHalfFovY);
}
for (auto const& a : getAttributes())
a->prepareShader(shader);
mVertexArray->bind().draw();
}
void LineRenderable::renderForward(RenderInfo const& info)
{
@@ -143,110 +168,56 @@ void LineRenderable::init()
// build shader
{
detail::MeshShaderBuilder sb;
sb.addUniform("mat4", "uModel");
sb.addUniform("mat4", "uInvModel");
sb.addUniform("bool", "uWorldSpaceSize");
sb.addUniform("bool", "uCameraFacing");
sb.addUniform("bool", "uNoCaps");
sb.addUniform("bool", "uExtrapolate");
sb.addUniform("vec2", "uScreenSize");
if (m3D)
sb.addUniform("float", "uTanFov2");
sb.addUniform("mat4", "uView");
sb.addUniform("mat4", "uInvView");
sb.addUniform("mat4", "uProj");
sb.addUniform("mat4", "uInvProj");
sb.addUniform("vec3", "uCamPos");
sb.addPassthrough("vec3", "Position");
sb.addPassthrough("vec3", "Normal");
sb.addPassthrough("float", "LineWidth");
sb.addPassthrough("vec3", "fragPosWS");
sb.addFragmentLocation("vec3", "fColor");
sb.addFragmentLocation("vec3", "fNormal");
for (auto const& attr : getAttributes())
attr->buildShader(sb);
// colored mesh
if (aColor)
sb.addPassthrough(aColor->typeInShader(), "Color");
// data mapped mesh
if (getColorMapping())
getColorMapping()->buildShader(sb);
// texture mesh
if (getTexturing())
getTexturing()->buildShader(sb);
// Geometry shader in- and output
sb.addGeometryShaderDecl("layout(lines) in;");
if (m3D)
sb.addGeometryShaderDecl("layout(triangle_strip, max_vertices = 6) out;"); // 6 vertices for 4 triangles
else
sb.addGeometryShaderDecl("layout(triangle_strip, max_vertices = 8) out;"); // 8 vertices for 6 triangles
sb.addGeometryShaderDecl("out vec2 gAlpha;");
sb.addFragmentShaderDecl("in vec2 gAlpha;");
if (m3D)
{
sb.addGeometryShaderDecl("out vec3 gLineOrigin;");
sb.addGeometryShaderDecl("out vec3 gLineEnd;");
sb.addGeometryShaderDecl("out vec3 gLineDir;");
sb.addFragmentShaderDecl("in vec3 gLineOrigin;");
sb.addFragmentShaderDecl("in vec3 gLineEnd;");
sb.addFragmentShaderDecl("in vec3 gLineDir;");
}
// Helper functions to emit vertices from the given relative line coordinates
sb.addGeometryShaderDecl(R"(
void createVertex(vec3 basePos, float ea, vec3 n, vec3 r, vec3 u, float relX, float relY) {
gAlpha = vec2(relX, relY); // Relative line position for fragment shader
if(uExtrapolate) {
if(relX < 0) passthroughMix(0, 1, relX * ea);
if(relX > 1) passthroughMix(0, 1, (relX - 1) * ea + 1);
}
if(relX > 0) relX -= 1; // This sets the factor for the r vector to the right value in case of the second half
vec3 outPos = basePos + relX * r + relY * u;
gl_Position = uProj * uView * vec4(outPos, 1.0);
vOut.fragPosWS = outPos;
vOut.Normal = n; // Set normal again as it might have been overwritten by passthrough
EmitVertex();
}
void createVertexInverse(vec4 basePos, float ea, vec3 n, vec4 r, vec4 u, float relX, float relY) {
gAlpha = vec2(relX, relY);
if(uExtrapolate) {
if(relX < 0) passthroughMix(0, 1, relX * ea);
if(relX > 1) passthroughMix(0, 1, (relX - 1) * ea + 1);
}
if(relX > 0) relX -= 1;
vec4 outPos = basePos + relX * r + relY * u;
gl_Position = outPos;
outPos = uInvProj * outPos;
outPos /= outPos.w;
outPos = uInvView * outPos;
// Shared functionality
const auto createCommonShaderParts = [&](detail::MeshShaderBuilder& sb) {
sb.addUniform("mat4", "uModel");
sb.addUniform("mat4", "uInvModel");
sb.addUniform("bool", "uWorldSpaceSize");
sb.addUniform("bool", "uCameraFacing");
sb.addUniform("bool", "uNoCaps");
sb.addUniform("vec2", "uScreenSize");
if (m3D)
sb.addUniform("float", "uTanFov2");
sb.addUniform("mat4", "uView");
sb.addUniform("mat4", "uInvView");
sb.addUniform("mat4", "uProj");
sb.addUniform("mat4", "uInvProj");
sb.addUniform("vec3", "uCamPos");
sb.addPassthrough("vec3", "Position");
sb.addPassthrough("vec3", "Normal");
sb.addPassthrough("float", "LineWidth");
sb.addPassthrough("vec3", "fragPosWS");
for (auto const& attr : getAttributes())
attr->buildShader(sb);
// Geometry shader in- and output
sb.addGeometryShaderDecl("layout(lines) in;");
if (m3D)
sb.addGeometryShaderDecl("layout(triangle_strip, max_vertices = 6) out;"); // 6 vertices for 4 triangles
else
sb.addGeometryShaderDecl("layout(triangle_strip, max_vertices = 8) out;"); // 8 vertices for 6 triangles
vOut.fragPosWS = vec3(outPos);
vOut.Normal = n;
EmitVertex();
}
)");
sb.addGeometryShaderDecl("out vec2 gAlpha;");
sb.addFragmentShaderDecl("in vec2 gAlpha;");
if (m3D)
{
sb.addGeometryShaderDecl("out vec3 gLineOrigin;");
sb.addGeometryShaderDecl("out vec3 gLineEnd;");
sb.addGeometryShaderDecl("out vec3 gLineDir;");
sb.addFragmentShaderDecl("in vec3 gLineOrigin;");
sb.addFragmentShaderDecl("in vec3 gLineEnd;");
sb.addFragmentShaderDecl("in vec3 gLineDir;");
}
// Geometry shader code
// Geometry shader code
if (m3D)
{ // 3D lines
sb.addGeometryShaderCode(R"(
if (m3D)
{ // 3D lines
sb.addGeometryShaderCode(R"(
passthrough(0); // Load passthrough data for first vertex
vec3 pos0 = vec3(uModel * vec4(vIn[0].Position, 1.0));
@@ -316,12 +287,12 @@ void createVertexInverse(vec4 basePos, float ea, vec3 n, vec4 r, vec4 u, float r
createVertex(pos1 - b, ea, n, r, u, cr, -1);
}
)");
}
else
{
if (mWorldSpaceSize)
{ // Flat world space lines
sb.addGeometryShaderCode(R"(
}
else
{
if (mWorldSpaceSize)
{ // Flat world space lines
sb.addGeometryShaderCode(R"(
passthrough(0); // Load passthrough data for first vertex
vec3 pos0 = vec3(uModel * vec4(vIn[0].Position, 1.0));
@@ -360,10 +331,10 @@ void createVertexInverse(vec4 basePos, float ea, vec3 n, vec4 r, vec4 u, float r
createVertex(pos1, ea, n, r, u, 2, -1);
}
)");
}
else
{ // Flat screen space lines
sb.addGeometryShaderCode(R"(
}
else
{ // Flat screen space lines
sb.addGeometryShaderCode(R"(
passthrough(0); // Load passthrough data for first vertex
// it only makes sense if uCameraFacing is true for screenSpaceSize lines
@@ -403,28 +374,28 @@ void createVertexInverse(vec4 basePos, float ea, vec3 n, vec4 r, vec4 u, float r
createVertexInverse(spos1, ea, n, r, u, 2, -1);
}
)");
}
}
}
// Fragment shader code
// Fragment shader code
if (m3D)
{
sb.addFragmentShaderDecl(R"(
float distance2(vec3 a, vec3 b) {
vec3 d = a - b;
return dot(d, d);
}
)");
// Camera ray: rayOrigin + tRay * rayDir;
// Line: gLineOrigin + tLine * gLIneDir;
// A: the angle between the Line and the Camera ray
// r: the radius of the 2D slice of the capsule, i.e. its line width and radius of the two cap circles
// s: the amount to go back on the ray dir to get to the intersection point
// TODO in this shader code
sb.addFragmentShaderCode(R"(
if (m3D)
{
sb.addFragmentShaderDecl(R"(
float distance2(vec3 a, vec3 b) {
vec3 d = a - b;
return dot(d, d);
}
)");
// Camera ray: rayOrigin + tRay * rayDir;
// Line: gLineOrigin + tLine * gLIneDir;
// A: the angle between the Line and the Camera ray
// r: the radius of the 2D slice of the capsule, i.e. its line width and radius of the two cap circles
// s: the amount to go back on the ray dir to get to the intersection point
// TODO in this shader code
sb.addFragmentShaderCode(R"(
vec3 rayOrigin = uCamPos;
vec3 rayDir = normalize(vIn.fragPosWS - uCamPos);
@@ -470,36 +441,139 @@ void createVertexInverse(vec4 basePos, float ea, vec3 n, vec4 r, vec4 u, float r
tRaySphere -= sqrt(lineRadius2 - sphereDis2); // Go back on ray to intersection
vec3 newPos = rayOrigin + max(tRayCyl, tRaySphere) * rayDir;
vNormal = normalize(newPos - closestOnSegment);
vec4 newPosCS = uProj * uView * vec4(newPos, 1);
float depthNDC = newPosCS.z / newPosCS.w;
gl_FragDepth = (depthNDC - gl_DepthRange.near) / gl_DepthRange.diff;
fNormal = vNormal;
fColor = vColor.rgb * (fNormal.y * .5 + .5);
)");
}
else // Not 3D
{
if (mRoundCaps)
}
else // Not 3D
{
sb.addFragmentShaderCode(R"(
if (mRoundCaps)
{
sb.addFragmentShaderCode(R"(
if(gAlpha.x < 0 && distance(gAlpha, vec2(0, 0)) > 1) discard;
if(gAlpha.x > 1 && distance(gAlpha, vec2(1, 0)) > 1) discard;)");
}
}
sb.addFragmentShaderCode(R"(
};
// Forward
{
detail::MeshShaderBuilder sbForward;
createCommonShaderParts(sbForward);
sbForward.addUniform("bool", "uExtrapolate");
sbForward.addFragmentLocation("vec3", "fColor");
sbForward.addFragmentLocation("vec3", "fNormal");
// colored mesh
if (aColor)
sbForward.addPassthrough(aColor->typeInShader(), "Color");
// data mapped mesh
if (getColorMapping())
getColorMapping()->buildShader(sbForward);
// texture mesh
if (getTexturing())
getTexturing()->buildShader(sbForward);
// Helper functions to emit vertices from the given relative line coordinates
sbForward.addGeometryShaderDecl(R"(
void createVertex(vec3 basePos, float ea, vec3 n, vec3 r, vec3 u, float relX, float relY) {
gAlpha = vec2(relX, relY); // Relative line position for fragment shader
if(uExtrapolate) {
if(relX < 0) passthroughMix(0, 1, relX * ea);
if(relX > 1) passthroughMix(0, 1, (relX - 1) * ea + 1);
}
if(relX > 0) relX -= 1; // This sets the factor for the r vector to the right value in case of the second half
vec3 outPos = basePos + relX * r + relY * u;
gl_Position = uProj * uView * vec4(outPos, 1.0);
vOut.fragPosWS = outPos;
vOut.Normal = n; // Set normal again as it might have been overwritten by passthrough
EmitVertex();
}
void createVertexInverse(vec4 basePos, float ea, vec3 n, vec4 r, vec4 u, float relX, float relY) {
gAlpha = vec2(relX, relY);
if(uExtrapolate) {
if(relX < 0) passthroughMix(0, 1, relX * ea);
if(relX > 1) passthroughMix(0, 1, (relX - 1) * ea + 1);
}
if(relX > 0) relX -= 1;
vec4 outPos = basePos + relX * r + relY * u;
gl_Position = outPos;
outPos = uInvProj * outPos;
outPos /= outPos.w;
outPos = uInvView * outPos;
vOut.fragPosWS = vec3(outPos);
vOut.Normal = n;
EmitVertex();
}
)");
// Fragment shader code
if (m3D)
{
sbForward.addFragmentShaderCode(R"(
vNormal = normalize(newPos - closestOnSegment);
fNormal = vNormal;
fColor = vColor.rgb * (fNormal.y * .5 + .5);
)");
}
else // Not 3D
{
sbForward.addFragmentShaderCode(R"(
fNormal = vNormal;
fColor = vColor.rgb * (fNormal.y * .5 + .5);)");
}
mForwardShader = sbForward.createProgram();
}
mForwardShader = sb.createProgram();
}
// Shadow
{
detail::MeshShaderBuilder sbShadow;
createCommonShaderParts(sbShadow);
// prepare IBL
{
auto shader = mForwardShader->use();
// Helper functions to emit vertices from the given relative line coordinates
sbShadow.addGeometryShaderDecl(R"(
void createVertex(vec3 basePos, float ea, vec3 n, vec3 r, vec3 u, float relX, float relY) {
gAlpha = vec2(relX, relY); // Relative line position for fragment shader
if(relX > 0) relX -= 1; // This sets the factor for the r vector to the right value in case of the second half
vec3 outPos = basePos + relX * r + relY * u;
gl_Position = uProj * uView * vec4(outPos, 1.0);
vOut.fragPosWS = outPos;
EmitVertex();
}
void createVertexInverse(vec4 basePos, float ea, vec3 n, vec4 r, vec4 u, float relX, float relY) {
gAlpha = vec2(relX, relY);
if(relX > 0) relX -= 1;
vec4 outPos = basePos + relX * r + relY * u;
gl_Position = outPos;
outPos = uInvProj * outPos;
outPos /= outPos.w;
outPos = uInvView * outPos;
vOut.fragPosWS = vec3(outPos);
EmitVertex();
}
)");
mShadowShader = sbShadow.createProgram();
}
}
}
Loading