Skip to content
Snippets Groups Projects
Unverified Commit b7ec7ea6 authored by Alexander Rose's avatar Alexander Rose Committed by GitHub
Browse files

Merge pull request #665 from molstar/solid-impostor

Solid impostors
parents 7afcf0bb 74560adb
No related branches found
No related tags found
No related merge requests found
...@@ -7,7 +7,7 @@ Note that since we don't clearly distinguish between a public and private interf ...@@ -7,7 +7,7 @@ Note that since we don't clearly distinguish between a public and private interf
## [Unreleased] ## [Unreleased]
- Show histogram in direct volume control point settings - Show histogram in direct volume control point settings
- Add `solidInterior` parameter to sphere/cylinder impostors
## [v3.27.0] - 2022-12-15 ## [v3.27.0] - 2022-12-15
......
...@@ -158,6 +158,7 @@ export namespace Cylinders { ...@@ -158,6 +158,7 @@ export namespace Cylinders {
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory), ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory), xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory), transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
solidInterior: PD.Boolean(true, BaseGeometry.ShadingCategory),
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory), bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory), bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
}; };
...@@ -245,6 +246,7 @@ export namespace Cylinders { ...@@ -245,6 +246,7 @@ export namespace Cylinders {
dIgnoreLight: ValueCell.create(props.ignoreLight), dIgnoreLight: ValueCell.create(props.ignoreLight),
dXrayShaded: ValueCell.create(props.xrayShaded), dXrayShaded: ValueCell.create(props.xrayShaded),
dTransparentBackfaces: ValueCell.create(props.transparentBackfaces), dTransparentBackfaces: ValueCell.create(props.transparentBackfaces),
dSolidInterior: ValueCell.create(props.solidInterior),
uBumpFrequency: ValueCell.create(props.bumpFrequency), uBumpFrequency: ValueCell.create(props.bumpFrequency),
uBumpAmplitude: ValueCell.create(props.bumpAmplitude), uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
}; };
...@@ -263,6 +265,7 @@ export namespace Cylinders { ...@@ -263,6 +265,7 @@ export namespace Cylinders {
ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight); ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded); ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces); ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces);
ValueCell.updateIfChanged(values.dSolidInterior, props.solidInterior);
ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency); ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude); ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
} }
......
...@@ -130,6 +130,7 @@ export namespace Spheres { ...@@ -130,6 +130,7 @@ export namespace Spheres {
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory), ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory), xrayShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory), transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
solidInterior: PD.Boolean(true, BaseGeometry.ShadingCategory),
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory), bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory), bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
}; };
...@@ -212,6 +213,7 @@ export namespace Spheres { ...@@ -212,6 +213,7 @@ export namespace Spheres {
dIgnoreLight: ValueCell.create(props.ignoreLight), dIgnoreLight: ValueCell.create(props.ignoreLight),
dXrayShaded: ValueCell.create(props.xrayShaded), dXrayShaded: ValueCell.create(props.xrayShaded),
dTransparentBackfaces: ValueCell.create(props.transparentBackfaces), dTransparentBackfaces: ValueCell.create(props.transparentBackfaces),
dSolidInterior: ValueCell.create(props.solidInterior),
uBumpFrequency: ValueCell.create(props.bumpFrequency), uBumpFrequency: ValueCell.create(props.bumpFrequency),
uBumpAmplitude: ValueCell.create(props.bumpAmplitude), uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
}; };
...@@ -230,6 +232,7 @@ export namespace Spheres { ...@@ -230,6 +232,7 @@ export namespace Spheres {
ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight); ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight);
ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded); ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded);
ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces); ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces);
ValueCell.updateIfChanged(values.dSolidInterior, props.solidInterior);
ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency); ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude); ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
} }
......
...@@ -27,6 +27,7 @@ export const CylindersSchema = { ...@@ -27,6 +27,7 @@ export const CylindersSchema = {
dIgnoreLight: DefineSpec('boolean'), dIgnoreLight: DefineSpec('boolean'),
dXrayShaded: DefineSpec('boolean'), dXrayShaded: DefineSpec('boolean'),
dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']), dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']),
dSolidInterior: DefineSpec('boolean'),
uBumpFrequency: UniformSpec('f', 'material'), uBumpFrequency: UniformSpec('f', 'material'),
uBumpAmplitude: UniformSpec('f', 'material'), uBumpAmplitude: UniformSpec('f', 'material'),
}; };
......
...@@ -24,6 +24,7 @@ export const SpheresSchema = { ...@@ -24,6 +24,7 @@ export const SpheresSchema = {
dIgnoreLight: DefineSpec('boolean'), dIgnoreLight: DefineSpec('boolean'),
dXrayShaded: DefineSpec('boolean'), dXrayShaded: DefineSpec('boolean'),
dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']), dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']),
dSolidInterior: DefineSpec('boolean'),
uBumpFrequency: UniformSpec('f', 'material'), uBumpFrequency: UniformSpec('f', 'material'),
uBumpAmplitude: UniformSpec('f', 'material'), uBumpAmplitude: UniformSpec('f', 'material'),
}; };
......
...@@ -28,6 +28,12 @@ uniform mat4 uInvView; ...@@ -28,6 +28,12 @@ uniform mat4 uInvView;
#include light_frag_params #include light_frag_params
#include common_clip #include common_clip
#ifdef dSolidInterior
const bool solidInterior = true;
#else
const bool solidInterior = false;
#endif
// adapted from https://www.shadertoy.com/view/4lcSRn // adapted from https://www.shadertoy.com/view/4lcSRn
// The MIT License, Copyright 2016 Inigo Quilez // The MIT License, Copyright 2016 Inigo Quilez
bool CylinderImpostor( bool CylinderImpostor(
...@@ -53,6 +59,19 @@ bool CylinderImpostor( ...@@ -53,6 +59,19 @@ bool CylinderImpostor(
bool topCap = (vCap > 0.9 && vCap < 1.1) || vCap >= 2.9; bool topCap = (vCap > 0.9 && vCap < 1.1) || vCap >= 2.9;
bool bottomCap = (vCap > 1.9 && vCap < 2.1) || vCap >= 2.9; bool bottomCap = (vCap > 1.9 && vCap < 2.1) || vCap >= 2.9;
#ifdef dSolidInterior
bool topInterior = !topCap;
bool bottomInterior = !bottomCap;
topCap = true;
bottomCap = true;
#else
bool topInterior = false;
bool bottomInterior = false;
#endif
bool clipped = false;
bool objectClipped = false;
// body outside // body outside
h = sqrt(h); h = sqrt(h);
float t = (-k1 - h) / k2; float t = (-k1 - h) / k2;
...@@ -64,36 +83,76 @@ bool CylinderImpostor( ...@@ -64,36 +83,76 @@ bool CylinderImpostor(
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition); fragmentDepth = calcDepth(viewPosition);
#if defined(dClipVariant_pixel) && dClipObjectCount != 0 #if defined(dClipVariant_pixel) && dClipObjectCount != 0
if (clipTest(vec4(modelPosition, 0.0))) fragmentDepth = -1.0; if (clipTest(vec4(modelPosition, 0.0))) {
objectClipped = true;
fragmentDepth = -1.0;
#ifdef dSolidInterior
topCap = !topInterior;
bottomCap = !bottomInterior;
#endif
}
#endif #endif
if (fragmentDepth > 0.0) return true; if (fragmentDepth > 0.0) return true;
clipped = true;
} }
if (topCap && y < 0.0) { if (!clipped) {
// top cap if (topCap && y < 0.0) {
t = -baoc / bard; // top cap
if (abs(k1 + k2 * t) < h) { t = -baoc / bard;
interior = false; if (abs(k1 + k2 * t) < h) {
cameraNormal = -ba / baba; interior = topInterior;
modelPosition = rayOrigin + t * rayDir; cameraNormal = -ba / baba;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; modelPosition = rayOrigin + t * rayDir;
fragmentDepth = calcDepth(viewPosition); viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
if (fragmentDepth > 0.0) return true; fragmentDepth = calcDepth(viewPosition);
} #if defined(dClipVariant_pixel) && dClipObjectCount != 0
} else if(bottomCap && y >= 0.0) { if (clipTest(vec4(modelPosition, 0.0))) {
// bottom cap objectClipped = true;
t = (baba - baoc) / bard; fragmentDepth = -1.0;
if (abs(k1 + k2 * t) < h) { #ifdef dSolidInterior
interior = false; topCap = !topInterior;
cameraNormal = ba / baba; bottomCap = !bottomInterior;
modelPosition = rayOrigin + t * rayDir; #endif
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; }
fragmentDepth = calcDepth(viewPosition); #endif
if (fragmentDepth > 0.0) return true; if (fragmentDepth > 0.0) {
#ifdef dSolidInterior
if (interior) cameraNormal = -rayDir;
#endif
return true;
}
}
} else if (bottomCap && y >= 0.0) {
// bottom cap
t = (baba - baoc) / bard;
if (abs(k1 + k2 * t) < h) {
interior = bottomInterior;
cameraNormal = ba / baba;
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))) {
objectClipped = true;
fragmentDepth = -1.0;
#ifdef dSolidInterior
topCap = !topInterior;
bottomCap = !bottomInterior;
#endif
}
#endif
if (fragmentDepth > 0.0) {
#ifdef dSolidInterior
if (interior) cameraNormal = -rayDir;
#endif
return true;
}
}
} }
} }
if (uDoubleSided) { if (uDoubleSided || solidInterior) {
// body inside // body inside
h = -h; h = -h;
t = (-k1 - h) / k2; t = (-k1 - h) / k2;
...@@ -104,7 +163,15 @@ bool CylinderImpostor( ...@@ -104,7 +163,15 @@ bool CylinderImpostor(
modelPosition = rayOrigin + t * rayDir; modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition); fragmentDepth = calcDepth(viewPosition);
return true; if (fragmentDepth > 0.0) {
#ifdef dSolidInterior
if (!objectClipped) {
fragmentDepth = 0.0 + (0.0000002 / vSize);
cameraNormal = -rayDir;
}
#endif
return true;
}
} }
if (topCap && y < 0.0) { if (topCap && y < 0.0) {
...@@ -116,9 +183,17 @@ bool CylinderImpostor( ...@@ -116,9 +183,17 @@ bool CylinderImpostor(
modelPosition = rayOrigin + t * rayDir; modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition); fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true; if (fragmentDepth > 0.0) {
#ifdef dSolidInterior
if (!objectClipped) {
fragmentDepth = 0.0 + (0.0000002 / vSize);
cameraNormal = -rayDir;
}
#endif
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) {
...@@ -127,7 +202,15 @@ bool CylinderImpostor( ...@@ -127,7 +202,15 @@ bool CylinderImpostor(
modelPosition = rayOrigin + t * rayDir; modelPosition = rayOrigin + t * rayDir;
viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; viewPosition = (uView * vec4(modelPosition, 1.0)).xyz;
fragmentDepth = calcDepth(viewPosition); fragmentDepth = calcDepth(viewPosition);
if (fragmentDepth > 0.0) return true; if (fragmentDepth > 0.0) {
#ifdef dSolidInterior
if (!objectClipped) {
fragmentDepth = 0.0 + (0.0000002 / vSize);
cameraNormal = -rayDir;
}
#endif
return true;
}
} }
} }
} }
......
...@@ -57,9 +57,6 @@ void main() { ...@@ -57,9 +57,6 @@ void main() {
// ensure cylinder 'dir' is pointing towards the camera // ensure cylinder 'dir' is pointing towards the camera
if(dot(camDir, dir) < 0.0) { if(dot(camDir, dir) < 0.0) {
dir = -dir; dir = -dir;
vec3 tmp = vStart;
vStart = vEnd;
vEnd = tmp;
} }
vec3 left = cross(camDir, dir); vec3 left = cross(camDir, dir);
......
...@@ -23,7 +23,13 @@ varying float vRadiusSq; ...@@ -23,7 +23,13 @@ varying float vRadiusSq;
varying vec3 vPoint; varying vec3 vPoint;
varying vec3 vPointViewPosition; varying vec3 vPointViewPosition;
bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth, out bool clipped){ #ifdef dSolidInterior
const bool solidInterior = true;
#else
const bool solidInterior = false;
#endif
bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth){
vec3 cameraSpherePos = -vPointViewPosition; vec3 cameraSpherePos = -vPointViewPosition;
vec3 rayOrigin = mix(vec3(0.0, 0.0, 0.0), vPoint, uIsOrtho); vec3 rayOrigin = mix(vec3(0.0, 0.0, 0.0), vPoint, uIsOrtho);
...@@ -43,9 +49,11 @@ bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal ...@@ -43,9 +49,11 @@ bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal
modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz; modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz;
fragmentDepth = calcDepth(cameraPos); fragmentDepth = calcDepth(cameraPos);
bool objectClipped = false;
#if defined(dClipVariant_pixel) && dClipObjectCount != 0 #if defined(dClipVariant_pixel) && dClipObjectCount != 0
if (clipTest(vec4(modelPos, 0.0))) { if (clipTest(vec4(modelPos, 0.0))) {
clipped = true; objectClipped = true;
fragmentDepth = -1.0; fragmentDepth = -1.0;
} }
#endif #endif
...@@ -54,13 +62,21 @@ bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal ...@@ -54,13 +62,21 @@ bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal
cameraNormal = normalize(cameraPos - cameraSpherePos); cameraNormal = normalize(cameraPos - cameraSpherePos);
interior = false; interior = false;
return true; return true;
} else if (uDoubleSided) { } else if (uDoubleSided || solidInterior) {
cameraPos = rayDirection * posT + rayOrigin; cameraPos = rayDirection * posT + rayOrigin;
modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz; modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz;
fragmentDepth = calcDepth(cameraPos); fragmentDepth = calcDepth(cameraPos);
cameraNormal = -normalize(cameraPos - cameraSpherePos); cameraNormal = -normalize(cameraPos - cameraSpherePos);
interior = true; interior = true;
return true; if (fragmentDepth > 0.0) {
#ifdef dSolidInterior
if (!objectClipped) {
fragmentDepth = 0.0 + (0.0000001 / vRadius);
cameraNormal = -mix(normalize(vPoint), vec3(0.0, 0.0, 1.0), uIsOrtho);
}
#endif
return true;
}
} }
return false; return false;
...@@ -72,7 +88,7 @@ void main(void){ ...@@ -72,7 +88,7 @@ void main(void){
vec3 cameraNormal; vec3 cameraNormal;
float fragmentDepth; float fragmentDepth;
bool clipped = false; bool clipped = false;
bool hit = SphereImpostor(modelPos, cameraPos, cameraNormal, interior, fragmentDepth, clipped); bool hit = SphereImpostor(modelPos, cameraPos, cameraNormal, interior, fragmentDepth);
if (!hit) discard; if (!hit) discard;
if (fragmentDepth < 0.0) discard; if (fragmentDepth < 0.0) discard;
...@@ -81,10 +97,6 @@ void main(void){ ...@@ -81,10 +97,6 @@ void main(void){
vec3 vViewPosition = cameraPos; vec3 vViewPosition = cameraPos;
vec3 vModelPosition = modelPos; vec3 vModelPosition = modelPos;
if (interior && !clipped) {
fragmentDepth = 0.0 + (0.0000001 / vRadius);
}
gl_FragDepthEXT = fragmentDepth; gl_FragDepthEXT = fragmentDepth;
#include clip_pixel #include clip_pixel
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment