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
- Fix 'once' for animations of systems with many frames
- 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
......
......@@ -33,7 +33,8 @@ uniform mat4 uInvView;
bool CylinderImpostor(
in vec3 rayOrigin, in vec3 rayDir,
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 oc = rayOrigin - start;
......@@ -42,7 +43,7 @@ bool CylinderImpostor(
float bard = dot(ba, rayDir);
float baoc = dot(ba, oc);
float k2 = baba - bard*bard;
float k2 = baba - bard * bard;
float k1 = baba * dot(oc, rayDir) - baoc * bard;
float k0 = baba * dot(oc, oc) - baoc * baoc - radius * radius * baba;
......@@ -58,8 +59,10 @@ bool CylinderImpostor(
float y = baoc + t * bard;
if (y > 0.0 && y < baba) {
interior = false;
intersection = vec4(t, (oc + t * rayDir - ba * y / baba) / radius);
return true;
cameraNormal = (oc + t * rayDir - ba * y / baba) / radius;
viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true;
}
if (topCap && y < 0.0) {
......@@ -67,16 +70,20 @@ bool CylinderImpostor(
t = -baoc / bard;
if (abs(k1 + k2 * t) < h) {
interior = false;
intersection = vec4(t, ba * sign(y) / baba);
return 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 = false;
intersection = vec4(t, ba * sign(y) / baba);
return true;
cameraNormal = ba / baba;
viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true;
}
}
......@@ -87,11 +94,33 @@ bool CylinderImpostor(
y = baoc + t * bard;
if (y > 0.0 && y < baba) {
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;
}
// 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;
......@@ -100,23 +129,21 @@ bool CylinderImpostor(
void main() {
#include clip_pixel
vec3 rayOrigin = vModelPosition;
vec3 rayDir = mix(normalize(vModelPosition - uCameraPosition), uCameraDir, uIsOrtho);
vec4 intersection;
bool interior;
bool hit = CylinderImpostor(vModelPosition, rayDir, vStart, vEnd, vSize, intersection, interior);
vec3 cameraNormal;
vec3 viewPosition;
float fragmentDepth;
bool hit = CylinderImpostor(rayOrigin, rayDir, vStart, vEnd, vSize, cameraNormal, interior, viewPosition, fragmentDepth);
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 > 1.0) discard;
gl_FragDepthEXT = fragmentDepth;
vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
vec3 vModelPosition = (uInvView * vec4(viewPosition, 1.0)).xyz;
#include assign_material_color
#if defined(dRenderVariant_pick)
......@@ -135,7 +162,7 @@ void main() {
gl_FragColor = material;
#elif defined(dRenderVariant_color)
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_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>
*/
......@@ -69,6 +69,9 @@ void main() {
vViewPosition = mvPosition.xyz;
gl_Position = uProjection * mvPosition;
mvPosition.z -= 2.0 * (length(vEnd - vStart) + vSize); // avoid clipping
gl_Position.z = (uProjection * mvPosition).z;
#include clip_instance
}
`;
\ No newline at end of file
......@@ -23,12 +23,8 @@ varying float vRadiusSq;
varying vec3 vPoint;
varying vec3 vPointViewPosition;
vec3 cameraPos;
vec3 cameraNormal;
bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
bool SphereImpostor(out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth){
vec3 cameraSpherePos = -vPointViewPosition;
cameraSpherePos.z += vRadius;
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);
......@@ -37,49 +33,49 @@ bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
float B = dot(rayDirection, cameraSphereDir);
float det = B * B + vRadiusSq - dot(cameraSphereDir, cameraSphereDir);
if (det < 0.0){
discard;
return false;
}
if (det < 0.0) return false;
float sqrtDet = sqrt(det);
float posT = mix(B + sqrtDet, B + sqrtDet, uIsOrtho);
float negT = mix(B - sqrtDet, sqrtDet - B, uIsOrtho);
float posT = mix(B + sqrtDet, B - sqrtDet, uIsOrtho);
float negT = mix(B - sqrtDet, B + sqrtDet, uIsOrtho);
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;
fragmentDepth = calcDepth(cameraPos);
cameraNormal = -normalize(cameraPos - cameraSpherePos);
interior = true;
} else {
interior = false;
return true;
}
cameraNormal = normalize(cameraPos - cameraSpherePos);
cameraNormal *= float(!interior) * 2.0 - 1.0;
return !interior;
return false;
}
void main(void){
#include clip_pixel
bool flag = Impostor(cameraPos, cameraNormal);
if (!uDoubleSided) {
if (interior) discard;
}
vec3 vViewPosition = cameraPos;
float fragmentDepth = calcDepth(vViewPosition);
if (!flag && fragmentDepth >= 0.0) {
fragmentDepth = 0.0 + (0.0000001 / vRadius);
}
vec3 cameraPos;
vec3 cameraNormal;
float fragmentDepth;
bool hit = SphereImpostor(cameraPos, cameraNormal, interior, fragmentDepth);
if (!hit) discard;
if (fragmentDepth < 0.0) discard;
if (fragmentDepth > 1.0) discard;
if (interior && fragmentDepth >= 0.0) {
fragmentDepth = 0.0 + (0.0000001 / vRadius);
}
gl_FragDepthEXT = fragmentDepth;
vec3 vViewPosition = cameraPos;
vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
#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>
*/
......@@ -85,7 +85,6 @@ void main(void){
vec4 position4 = vec4(aPosition, 1.0);
vec4 mvPosition = uModelView * aTransform * position4;
mvPosition.z -= vRadius; // avoid clipping, added again in fragment shader
gl_Position = uProjection * vec4(mvPosition.xyz, 1.0);
quadraticProjection(size, aPosition);
......@@ -97,6 +96,9 @@ void main(void){
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
}
`;
\ 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