Skip to content
Snippets Groups Projects
Commit 601bd5ba authored by Alexander Rose's avatar Alexander Rose
Browse files

improve impostor shaders

- fix sphere near-clipping with orthographic projection
- fix cylinder near-clipping
- add interior cylinder caps
parent 5798f20c
No related branches found
No related tags found
No related merge requests found
...@@ -8,6 +8,10 @@ Note that since we don't clearly distinguish between a public and private interf ...@@ -8,6 +8,10 @@ Note that since we don't clearly distinguish between a public and private interf
- Fix 'once' for animations of systems with many frames - Fix 'once' for animations of systems with many frames
- Better guard against issue (black fringes) with bumpiness in impostors - Better guard against issue (black fringes) with bumpiness in impostors
- Improve impostor shaders
- Fix sphere near-clipping with orthographic projection
- Fix cylinder near-clipping
- Add interior cylinder caps
## [v3.26.0] - 2022-12-04 ## [v3.26.0] - 2022-12-04
......
...@@ -33,7 +33,8 @@ uniform mat4 uInvView; ...@@ -33,7 +33,8 @@ uniform mat4 uInvView;
bool CylinderImpostor( bool CylinderImpostor(
in vec3 rayOrigin, in vec3 rayDir, in vec3 rayOrigin, in vec3 rayDir,
in vec3 start, in vec3 end, in float radius, in vec3 start, in vec3 end, in float radius,
out vec4 intersection, out bool interior out vec3 cameraNormal, out bool interior,
out vec3 viewPosition, out float fragmentDepth
){ ){
vec3 ba = end - start; vec3 ba = end - start;
vec3 oc = rayOrigin - start; vec3 oc = rayOrigin - start;
...@@ -42,7 +43,7 @@ bool CylinderImpostor( ...@@ -42,7 +43,7 @@ bool CylinderImpostor(
float bard = dot(ba, rayDir); float bard = dot(ba, rayDir);
float baoc = dot(ba, oc); float baoc = dot(ba, oc);
float k2 = baba - bard*bard; float k2 = baba - bard * bard;
float k1 = baba * dot(oc, rayDir) - baoc * bard; float k1 = baba * dot(oc, rayDir) - baoc * bard;
float k0 = baba * dot(oc, oc) - baoc * baoc - radius * radius * baba; float k0 = baba * dot(oc, oc) - baoc * baoc - radius * radius * baba;
...@@ -58,8 +59,10 @@ bool CylinderImpostor( ...@@ -58,8 +59,10 @@ bool CylinderImpostor(
float y = baoc + t * bard; float y = baoc + t * bard;
if (y > 0.0 && y < baba) { if (y > 0.0 && y < baba) {
interior = false; interior = false;
intersection = vec4(t, (oc + t * rayDir - ba * y / baba) / radius); cameraNormal = (oc + t * rayDir - ba * y / baba) / radius;
return true; viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true;
} }
if (topCap && y < 0.0) { if (topCap && y < 0.0) {
...@@ -67,16 +70,20 @@ bool CylinderImpostor( ...@@ -67,16 +70,20 @@ bool CylinderImpostor(
t = -baoc / bard; t = -baoc / bard;
if (abs(k1 + k2 * t) < h) { if (abs(k1 + k2 * t) < h) {
interior = false; interior = false;
intersection = vec4(t, ba * sign(y) / baba); cameraNormal = -ba / baba;
return true; viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true;
} }
} else if(bottomCap && y >= 0.0) { } else if(bottomCap && y >= 0.0) {
// bottom cap // bottom cap
t = (baba - baoc) / bard; t = (baba - baoc) / bard;
if (abs(k1 + k2 * t) < h) { if (abs(k1 + k2 * t) < h) {
interior = false; interior = false;
intersection = vec4(t, ba * sign(y) / baba); cameraNormal = ba / baba;
return true; viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true;
} }
} }
...@@ -87,11 +94,33 @@ bool CylinderImpostor( ...@@ -87,11 +94,33 @@ bool CylinderImpostor(
y = baoc + t * bard; y = baoc + t * bard;
if (y > 0.0 && y < baba) { if (y > 0.0 && y < baba) {
interior = true; interior = true;
intersection = vec4(t, (oc + t * rayDir - ba * y / baba) / radius); cameraNormal = -(oc + t * rayDir - ba * y / baba) / radius;
viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
return true; return true;
} }
// TODO: handle inside caps??? if (topCap && y < 0.0) {
// top cap
t = -baoc / bard;
if (abs(k1 + k2 * t) < -h) {
interior = true;
cameraNormal = ba / baba;
viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true;
}
} else if(bottomCap && y >= 0.0) {
// bottom cap
t = (baba - baoc) / bard;
if (abs(k1 + k2 * t) < -h) {
interior = true;
cameraNormal = -ba / baba;
viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true;
}
}
} }
return false; return false;
...@@ -100,23 +129,21 @@ bool CylinderImpostor( ...@@ -100,23 +129,21 @@ bool CylinderImpostor(
void main() { void main() {
#include clip_pixel #include clip_pixel
vec3 rayOrigin = vModelPosition;
vec3 rayDir = mix(normalize(vModelPosition - uCameraPosition), uCameraDir, uIsOrtho); vec3 rayDir = mix(normalize(vModelPosition - uCameraPosition), uCameraDir, uIsOrtho);
vec4 intersection; vec3 cameraNormal;
bool interior; vec3 viewPosition;
bool hit = CylinderImpostor(vModelPosition, rayDir, vStart, vEnd, vSize, intersection, interior); float fragmentDepth;
bool hit = CylinderImpostor(rayOrigin, rayDir, vStart, vEnd, vSize, cameraNormal, interior, viewPosition, fragmentDepth);
if (!hit) discard; if (!hit) discard;
vec3 vViewPosition = vModelPosition + intersection.x * rayDir;
vViewPosition = (uView * vec4(vViewPosition, 1.0)).xyz;
float fragmentDepth = calcDepth(vViewPosition);
if (fragmentDepth < 0.0) discard; if (fragmentDepth < 0.0) discard;
if (fragmentDepth > 1.0) discard; if (fragmentDepth > 1.0) discard;
gl_FragDepthEXT = fragmentDepth; gl_FragDepthEXT = fragmentDepth;
vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz; vec3 vModelPosition = (uInvView * vec4(viewPosition, 1.0)).xyz;
#include assign_material_color #include assign_material_color
#if defined(dRenderVariant_pick) #if defined(dRenderVariant_pick)
...@@ -135,7 +162,7 @@ void main() { ...@@ -135,7 +162,7 @@ void main() {
gl_FragColor = material; gl_FragColor = material;
#elif defined(dRenderVariant_color) #elif defined(dRenderVariant_color)
mat3 normalMatrix = transpose3(inverse3(mat3(uView))); mat3 normalMatrix = transpose3(inverse3(mat3(uView)));
vec3 normal = normalize(normalMatrix * -normalize(intersection.yzw)); vec3 normal = normalize(normalMatrix * -normalize(cameraNormal));
#include apply_light_color #include apply_light_color
#include apply_interior_color #include apply_interior_color
......
/** /**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
* *
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
...@@ -69,6 +69,9 @@ void main() { ...@@ -69,6 +69,9 @@ void main() {
vViewPosition = mvPosition.xyz; vViewPosition = mvPosition.xyz;
gl_Position = uProjection * mvPosition; gl_Position = uProjection * mvPosition;
mvPosition.z -= 2.0 * (length(vEnd - vStart) + vSize); // avoid clipping
gl_Position.z = (uProjection * mvPosition).z;
#include clip_instance #include clip_instance
} }
`; `;
\ No newline at end of file
...@@ -23,12 +23,8 @@ varying float vRadiusSq; ...@@ -23,12 +23,8 @@ varying float vRadiusSq;
varying vec3 vPoint; varying vec3 vPoint;
varying vec3 vPointViewPosition; varying vec3 vPointViewPosition;
vec3 cameraPos; bool SphereImpostor(out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth){
vec3 cameraNormal;
bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
vec3 cameraSpherePos = -vPointViewPosition; vec3 cameraSpherePos = -vPointViewPosition;
cameraSpherePos.z += vRadius;
vec3 rayOrigin = mix(vec3(0.0, 0.0, 0.0), vPoint, uIsOrtho); vec3 rayOrigin = mix(vec3(0.0, 0.0, 0.0), vPoint, uIsOrtho);
vec3 rayDirection = mix(normalize(vPoint), vec3(0.0, 0.0, 1.0), uIsOrtho); vec3 rayDirection = mix(normalize(vPoint), vec3(0.0, 0.0, 1.0), uIsOrtho);
...@@ -37,49 +33,49 @@ bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){ ...@@ -37,49 +33,49 @@ bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
float B = dot(rayDirection, cameraSphereDir); float B = dot(rayDirection, cameraSphereDir);
float det = B * B + vRadiusSq - dot(cameraSphereDir, cameraSphereDir); float det = B * B + vRadiusSq - dot(cameraSphereDir, cameraSphereDir);
if (det < 0.0){ if (det < 0.0) return false;
discard;
return false;
}
float sqrtDet = sqrt(det); float sqrtDet = sqrt(det);
float posT = mix(B + sqrtDet, B + sqrtDet, uIsOrtho); float posT = mix(B + sqrtDet, B - sqrtDet, uIsOrtho);
float negT = mix(B - sqrtDet, sqrtDet - B, uIsOrtho); float negT = mix(B - sqrtDet, B + sqrtDet, uIsOrtho);
cameraPos = rayDirection * negT + rayOrigin; cameraPos = rayDirection * negT + rayOrigin;
fragmentDepth = calcDepth(cameraPos);
if (calcDepth(cameraPos) <= 0.0) { if (fragmentDepth > 0.0) {
cameraNormal = normalize(cameraPos - cameraSpherePos);
interior = false;
return true;
} else if (uDoubleSided) {
cameraPos = rayDirection * posT + rayOrigin; cameraPos = rayDirection * posT + rayOrigin;
fragmentDepth = calcDepth(cameraPos);
cameraNormal = -normalize(cameraPos - cameraSpherePos);
interior = true; interior = true;
} else { return true;
interior = false;
} }
cameraNormal = normalize(cameraPos - cameraSpherePos); return false;
cameraNormal *= float(!interior) * 2.0 - 1.0;
return !interior;
} }
void main(void){ void main(void){
#include clip_pixel #include clip_pixel
bool flag = Impostor(cameraPos, cameraNormal); vec3 cameraPos;
if (!uDoubleSided) { vec3 cameraNormal;
if (interior) discard; float fragmentDepth;
} bool hit = SphereImpostor(cameraPos, cameraNormal, interior, fragmentDepth);
if (!hit) discard;
vec3 vViewPosition = cameraPos;
float fragmentDepth = calcDepth(vViewPosition);
if (!flag && fragmentDepth >= 0.0) {
fragmentDepth = 0.0 + (0.0000001 / vRadius);
}
if (fragmentDepth < 0.0) discard; if (fragmentDepth < 0.0) discard;
if (fragmentDepth > 1.0) discard; if (fragmentDepth > 1.0) discard;
if (interior && fragmentDepth >= 0.0) {
fragmentDepth = 0.0 + (0.0000001 / vRadius);
}
gl_FragDepthEXT = fragmentDepth; gl_FragDepthEXT = fragmentDepth;
vec3 vViewPosition = cameraPos;
vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz; vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
#include assign_material_color #include assign_material_color
......
/** /**
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
* *
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
...@@ -85,7 +85,6 @@ void main(void){ ...@@ -85,7 +85,6 @@ void main(void){
vec4 position4 = vec4(aPosition, 1.0); vec4 position4 = vec4(aPosition, 1.0);
vec4 mvPosition = uModelView * aTransform * position4; vec4 mvPosition = uModelView * aTransform * position4;
mvPosition.z -= vRadius; // avoid clipping, added again in fragment shader
gl_Position = uProjection * vec4(mvPosition.xyz, 1.0); gl_Position = uProjection * vec4(mvPosition.xyz, 1.0);
quadraticProjection(size, aPosition); quadraticProjection(size, aPosition);
...@@ -97,6 +96,9 @@ void main(void){ ...@@ -97,6 +96,9 @@ void main(void){
vModelPosition = (uModel * aTransform * position4).xyz; // for clipping in frag shader vModelPosition = (uModel * aTransform * position4).xyz; // for clipping in frag shader
mvPosition.z -= 2.0 * vRadius; // avoid clipping
gl_Position.z = (uProjection * vec4(mvPosition.xyz, 1.0)).z;
#include clip_instance #include clip_instance
} }
`; `;
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment