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

impostor per-pixel object clipping

parent 4ff5ed3b
No related branches found
No related tags found
No related merge requests found
......@@ -12,6 +12,7 @@ Note that since we don't clearly distinguish between a public and private interf
- Fix sphere near-clipping with orthographic projection
- Fix cylinder near-clipping
- Add interior cylinder caps
- Add per-pixel object clipping
## [v3.26.0] - 2022-12-04
......
export const clip_instance = `
#if defined(dClipVariant_instance) && dClipObjectCount != 0
int flag = 0;
#if defined(dClipping)
flag = int(floor(vClipping * 255.0 + 0.5));
#endif
vec4 mCenter = uModel * aTransform * vec4(uInvariantBoundingSphere.xyz, 1.0);
if (clipTest(vec4(mCenter.xyz, uInvariantBoundingSphere.w), flag))
if (clipTest(vec4(mCenter.xyz, uInvariantBoundingSphere.w)))
// move out of [ -w, +w ] to 'discard' in vert shader
gl_Position.z = 2.0 * gl_Position.w;
#endif
......
export const clip_pixel = `
#if defined(dClipVariant_pixel) && dClipObjectCount != 0
#if defined(dClipping)
int clippingFlag = int(floor(vClipping * 255.0 + 0.5));
#else
int clippingFlag = 0;
#endif
if (clipTest(vec4(vModelPosition, 0.0), clippingFlag))
if (clipTest(vec4(vModelPosition, 0.0)))
discard;
#endif
`;
\ No newline at end of file
/**
* 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 Ludovic Autin <autin@scripps.edu>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
......@@ -7,45 +7,45 @@
export const common_clip = `
#if dClipObjectCount != 0
vec3 quaternionTransform(vec4 q, vec3 v) {
vec3 quaternionTransform(const in vec4 q, const in vec3 v) {
vec3 t = 2.0 * cross(q.xyz, v);
return v + q.w * t + cross(q.xyz, t);
}
vec4 computePlane(vec3 normal, vec3 inPoint) {
vec4 computePlane(const in vec3 normal, const in vec3 inPoint) {
return vec4(normalize(normal), -dot(normal, inPoint));
}
float planeSD(vec4 plane, vec3 center) {
float planeSD(const in vec4 plane, const in vec3 center) {
return -dot(plane.xyz, center - plane.xyz * -plane.w);
}
float sphereSD(vec3 position, vec4 rotation, vec3 size, vec3 center) {
float sphereSD(const in vec3 position, const in vec4 rotation, const in vec3 size, const in vec3 center) {
return (
length(quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position) / size) - 1.0
) * min(min(size.x, size.y), size.z);
}
float cubeSD(vec3 position, vec4 rotation, vec3 size, vec3 center) {
float cubeSD(const in vec3 position, const in vec4 rotation, const in vec3 size, const in vec3 center) {
vec3 d = abs(quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position)) - size;
return min(max(d.x, max(d.y, d.z)), 0.0) + length(max(d, 0.0));
}
float cylinderSD(vec3 position, vec4 rotation, vec3 size, vec3 center) {
float cylinderSD(const in vec3 position, const in vec4 rotation, const in vec3 size, const in vec3 center) {
vec3 t = quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position);
vec2 d = abs(vec2(length(t.xz), t.y)) - size.xy;
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
}
float infiniteConeSD(vec3 position, vec4 rotation, vec3 size, vec3 center) {
float infiniteConeSD(const in vec3 position, const in vec4 rotation, const in vec3 size, const in vec3 center) {
vec3 t = quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position);
float q = length(t.xy);
return dot(size.xy, vec2(q, t.z));
}
float getSignedDistance(vec3 center, int type, vec3 position, vec4 rotation, vec3 scale) {
float getSignedDistance(const in vec3 center, const in int type, const in vec3 position, const in vec4 rotation, const in vec3 scale) {
if (type == 1) {
vec3 normal = quaternionTransform(rotation, vec3(0.0, 1.0, 0.0));
vec4 plane = computePlane(normal, position);
......@@ -65,7 +65,7 @@ export const common_clip = `
#if __VERSION__ == 100
// 8-bit
int bitwiseAnd(int a, int b) {
int bitwiseAnd(const in int a, const in int b) {
int d = 128;
int result = 0;
for (int i = 0; i < 8; ++i) {
......@@ -78,17 +78,23 @@ export const common_clip = `
return result;
}
bool hasBit(int mask, int bit) {
bool hasBit(const in int mask, const in int bit) {
return bitwiseAnd(mask, bit) == 0;
}
#else
bool hasBit(int mask, int bit) {
bool hasBit(const in int mask, const in int bit) {
return (mask & bit) == 0;
}
#endif
// flag is a bit-flag for clip-objects to ignore (note, object ids start at 1 not 0)
bool clipTest(vec4 sphere, int flag) {
bool clipTest(const in vec4 sphere) {
// flag is a bit-flag for clip-objects to ignore (note, object ids start at 1 not 0)
#if defined(dClipping)
int flag = int(floor(vClipping * 255.0 + 0.5));
#else
int flag = 0;
#endif
#pragma unroll_loop_start
for (int i = 0; i < dClipObjectCount; ++i) {
if (flag == 0 || hasBit(flag, UNROLLED_LOOP_INDEX + 1)) {
......
......@@ -34,7 +34,7 @@ bool CylinderImpostor(
in vec3 rayOrigin, in vec3 rayDir,
in vec3 start, in vec3 end, in float radius,
out vec3 cameraNormal, out bool interior,
out vec3 viewPosition, out float fragmentDepth
out vec3 modelPosition, out vec3 viewPosition, out float fragmentDepth
){
vec3 ba = end - start;
vec3 oc = rayOrigin - start;
......@@ -60,8 +60,12 @@ bool CylinderImpostor(
if (y > 0.0 && y < baba) {
interior = false;
cameraNormal = (oc + t * rayDir - ba * y / baba) / radius;
viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
#if defined(dClipVariant_pixel) && dClipObjectCount != 0
if (clipTest(vec4(modelPosition, 0.0))) fragmentDepth = -1.0;
#endif
if (fragmentDepth > 0.0) return true;
}
......@@ -71,7 +75,8 @@ bool CylinderImpostor(
if (abs(k1 + k2 * t) < h) {
interior = false;
cameraNormal = -ba / baba;
viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true;
}
......@@ -81,7 +86,8 @@ bool CylinderImpostor(
if (abs(k1 + k2 * t) < h) {
interior = false;
cameraNormal = ba / baba;
viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true;
}
......@@ -95,7 +101,8 @@ bool CylinderImpostor(
if (y > 0.0 && y < baba) {
interior = true;
cameraNormal = -(oc + t * rayDir - ba * y / baba) / radius;
viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
return true;
}
......@@ -106,7 +113,8 @@ bool CylinderImpostor(
if (abs(k1 + k2 * t) < -h) {
interior = true;
cameraNormal = ba / baba;
viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true;
}
......@@ -116,7 +124,8 @@ bool CylinderImpostor(
if (abs(k1 + k2 * t) < -h) {
interior = true;
cameraNormal = -ba / baba;
viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true;
}
......@@ -127,15 +136,14 @@ bool CylinderImpostor(
}
void main() {
#include clip_pixel
vec3 rayOrigin = vModelPosition;
vec3 rayDir = mix(normalize(vModelPosition - uCameraPosition), uCameraDir, uIsOrtho);
vec3 cameraNormal;
vec3 modelPosition;
vec3 viewPosition;
float fragmentDepth;
bool hit = CylinderImpostor(rayOrigin, rayDir, vStart, vEnd, vSize, cameraNormal, interior, viewPosition, fragmentDepth);
bool hit = CylinderImpostor(rayOrigin, rayDir, vStart, vEnd, vSize, cameraNormal, interior, modelPosition, viewPosition, fragmentDepth);
if (!hit) discard;
if (fragmentDepth < 0.0) discard;
......@@ -143,7 +151,10 @@ void main() {
gl_FragDepthEXT = fragmentDepth;
vec3 vModelPosition = (uInvView * vec4(viewPosition, 1.0)).xyz;
vec3 vViewPosition = viewPosition;
vec3 vModelPosition = modelPosition;
#include clip_pixel
#include assign_material_color
#if defined(dRenderVariant_pick)
......
......@@ -229,7 +229,7 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 rayDir) {
#if defined(dClipVariant_pixel) && dClipObjectCount != 0
vec3 vModelPosition = v3m4(unitPos * uGridDim, modelTransform);
if (clipTest(vec4(vModelPosition, 0.0), 0)) {
if (clipTest(vec4(vModelPosition, 0.0))) {
prevValue = value;
pos += step;
continue;
......
......@@ -23,7 +23,7 @@ varying float vRadiusSq;
varying vec3 vPoint;
varying vec3 vPointViewPosition;
bool SphereImpostor(out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth){
bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth, out bool clipped){
vec3 cameraSpherePos = -vPointViewPosition;
vec3 rayOrigin = mix(vec3(0.0, 0.0, 0.0), vPoint, uIsOrtho);
......@@ -40,14 +40,23 @@ bool SphereImpostor(out vec3 cameraPos, out vec3 cameraNormal, out bool interior
float negT = mix(B - sqrtDet, B + sqrtDet, uIsOrtho);
cameraPos = rayDirection * negT + rayOrigin;
modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz;
fragmentDepth = calcDepth(cameraPos);
#if defined(dClipVariant_pixel) && dClipObjectCount != 0
if (clipTest(vec4(modelPos, 0.0))) {
clipped = true;
fragmentDepth = -1.0;
}
#endif
if (fragmentDepth > 0.0) {
cameraNormal = normalize(cameraPos - cameraSpherePos);
interior = false;
return true;
} else if (uDoubleSided) {
cameraPos = rayDirection * posT + rayOrigin;
modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz;
fragmentDepth = calcDepth(cameraPos);
cameraNormal = -normalize(cameraPos - cameraSpherePos);
interior = true;
......@@ -58,25 +67,27 @@ bool SphereImpostor(out vec3 cameraPos, out vec3 cameraNormal, out bool interior
}
void main(void){
#include clip_pixel
vec3 modelPos;
vec3 cameraPos;
vec3 cameraNormal;
float fragmentDepth;
bool hit = SphereImpostor(cameraPos, cameraNormal, interior, fragmentDepth);
bool clipped = false;
bool hit = SphereImpostor(modelPos, cameraPos, cameraNormal, interior, fragmentDepth, clipped);
if (!hit) discard;
if (fragmentDepth < 0.0) discard;
if (fragmentDepth > 1.0) discard;
if (interior) {
vec3 vViewPosition = cameraPos;
vec3 vModelPosition = modelPos;
if (interior && !clipped) {
fragmentDepth = 0.0 + (0.0000001 / vRadius);
}
gl_FragDepthEXT = fragmentDepth;
vec3 vViewPosition = cameraPos;
vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
#include clip_pixel
#include assign_material_color
#if defined(dRenderVariant_pick)
......
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