Skip to content

Commit

Permalink
add alternative to alpha-based transparency
Browse files Browse the repository at this point in the history
The alternative transparency implements the so-called screen-door
transparency approach by using a polygon stipple pattern for
transparent objects. The stipple pattern is implemented in the
shader. Screen-door transparency is disabled by default and must
be enabled by passing transparency : 'screendoor' to the viewer
constructor.
  • Loading branch information
biasmv committed Jul 18, 2015
1 parent 01c53d8 commit 70fd0c2
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 101 deletions.
38 changes: 4 additions & 34 deletions demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@ function lines() {
var go = viewer.lines('structure', structure, {
color: color.byResidueProp('num'),
showRelated : '1' });
go.setSelection(go.select({rnumRange : [15,20]}));
go.setOpacity(0.5, go.select({rnumRange : [25,30]}));
}

function cartoon() {
viewer.clear();
var go = viewer.cartoon('structure', structure, {
color : color.ssSuccession(), showRelated : '1',
});
go.setSelection(go.select({rnumRange : [15,20]}));
var rotation = viewpoint.principalAxes(go);
viewer.setRotation(rotation)
}
Expand Down Expand Up @@ -247,50 +248,19 @@ $('#load-from-pdb').change(function() {
viewer = pv.Viewer(document.getElementById('viewer'), {
width : 'auto', height: 'auto', antialias : true, fog : true,
outline : true, quality : 'medium', style : 'phong',
selectionColor : 'white',
selectionColor : 'white', transparency : 'screendoor',
background : '#ccc', animateTime: 500, doubleClick : null
});
viewer.addListener('viewerReady', crambin);

viewer.on('doubleClick', function(picked) {
if (picked === null) {
viewer.fitTo(structure);
return;
return;
}
viewer.setCenter(picked.pos(), 500);
});

var lastAtom = null;

viewer.addListener('click', function(picked) {
if (picked === null) return;
var target = picked.target();
if (target.qualifiedName !== undefined) {
var view = picked.node()
.structure().createEmptyView();
viewer.requestRedraw();
if (lastAtom !== null) {
viewer.rm('dist.*');
var g = viewer.customMesh('dist.line');
var p1 = lastAtom.pos();
var p2 = target.pos();
var m = pv.vec3.clone(p1);
pv.vec3.add(m, m, p2);
pv.vec3.scale(m, m, 0.5);
g.addTube(p1, p2, 0.1,
{ cap : true, color : 'white' });
var d = pv.vec3.distance(p1, p2);
var l = viewer.label('dist.label',
d.toFixed(2), m);
console.log('distance: ', d);
lastAtom = null;
} else {
lastAtom = target;
view.addAtom(target);
}
picked.node().setSelection(view);
}
});
window.addEventListener('resize', function() {
viewer.fitParent();
});
Expand Down
6 changes: 6 additions & 0 deletions src/gfx/cam.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ function Cam(gl) {
this._selectionColor = vec3.fromValues(0.1, 1.0, 0.1);
this._center = vec3.create();
this._zoom = 50;
this._screenDoorTransparency = false;
this._updateProjectionMat = true;
this._updateModelViewMat = true;
this._upsamplingFactor = 1;
Expand All @@ -68,6 +69,10 @@ Cam.prototype = {
this._stateId = 0;
}
},
setScreenDoorTransparency : function(value) {
this._screenDoorTransparency = value;
this._incrementStateId();
},
setOutlineWidth : function(value) {
if (this._outlineWidth !== value) {
this._outlineWidth = value;
Expand Down Expand Up @@ -336,6 +341,7 @@ Cam.prototype = {
gl.uniform3fv(shader.selectionColor, this._selectionColor);
gl.uniform2fv(shader.relativePixelSize, this._relativePixelSize);
gl.uniform1f(shader.outlineWidth, this._outlineWidth);
gl.uniform1i(shader.screenDoorTransparency, this._screenDoorTransparency);
}
};

Expand Down
2 changes: 2 additions & 0 deletions src/gfx/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ Canvas.prototype = {
shaderProgram.outlineWidth = getUniformLoc(shaderProgram, 'outlineWidth');
shaderProgram.relativePixelSize = getUniformLoc(shaderProgram,
'relativePixelSize');
shaderProgram.screenDoorTransparency = getUniformLoc(shaderProgram,
'screenDoorTransparency');
shaderProgram.selectionColor = getUniformLoc(shaderProgram,
'selectionColor');
shaderProgram.pointSize = getUniformLoc(shaderProgram, 'pointSize');
Expand Down
116 changes: 54 additions & 62 deletions src/gfx/shaders.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,56 @@ define({
// This is required, because the outline shaders do not work well on iOS
// with mediump, but some android devices do not support highp.

// line fragment shader, essentially uses the vertColor and adds some fog.
LINES_FS : '\n\

// this fragment shader prelude gets added to all fragment shader code
// before compiling. It essentially contains a selection of functions
// required by multiple fragment shaders, e.g. the code for screen-door-
// transparency, selection highlighting etc.
PRELUDE_FS : '\n\
precision ${PRECISION} float;\n\
uniform bool screenDoorTransparency;\n\
vec4 handleAlpha(vec4 inColor) {\n\
if (screenDoorTransparency) {\n\
ivec2 pxCoord = ivec2(gl_FragCoord.xy);\n\
ivec2 mod = pxCoord - (pxCoord/2) * 2;\n\
if (inColor.a < 0.99 &&\n\
(inColor.a < 0.01 || mod.x != 0 || mod.y != 0)) { discard; }\n\
return vec4(inColor.rgb, 1.0);\n\
} else {\n\
if (inColor.a == 0.0) { discard; }\n\
return inColor;\n\
} \n\
} \n\
uniform vec3 selectionColor;\n\
\n\
varying vec4 vertColor;\n\
varying vec3 vertNormal;\n\
vec3 handleSelect(vec3 inColor, float vertSelect) { \n\
return mix(inColor, selectionColor, step(0.5, vertSelect) * 0.7); \n\
} \n\
\n\
uniform bool fog;\n\
uniform float fogNear;\n\
uniform float fogFar;\n\
uniform vec3 fogColor;\n\
uniform bool fog;\n\
\n\
void main(void) {\n\
gl_FragColor = vec4(vertColor);\n\
if (gl_FragColor.a == 0.0) { discard; }\n\
float depth = gl_FragCoord.z / gl_FragCoord.w;\n\
vec3 handleFog(vec3 inColor) {\n\
if (fog) {\n\
float fog_factor = smoothstep(fogNear, fogFar, depth);\n\
gl_FragColor = mix(gl_FragColor, vec4(fogColor, gl_FragColor.w),\n\
fog_factor);\n\
float depth = gl_FragCoord.z / gl_FragCoord.w;\n\
float fogFactor = smoothstep(fogNear, fogFar, depth);\n\
return mix(inColor, fogColor, fogFactor);\n\
} else {\n\
return inColor;\n\
}\n\
}',

// line fragment shader, essentially uses the vertColor and adds some fog.
LINES_FS : '\n\
varying vec4 vertColor;\n\
varying vec3 vertNormal;\n\
\n\
void main(void) {\n\
gl_FragColor = handleAlpha(vertColor);\n\
gl_FragColor.rgb = handleFog(gl_FragColor.rgb);\n\
}',

SELECT_LINES_FS : '\n\
precision ${PRECISION} float;\n\
\n\
Expand Down Expand Up @@ -144,63 +172,36 @@ void main(void) {\n\

// hemilight fragment shader
HEMILIGHT_FS : '\n\
precision ${PRECISION} float;\n\
\n\
varying vec4 vertColor;\n\
varying vec3 vertNormal;\n\
uniform float fogNear;\n\
uniform float fogFar;\n\
uniform vec3 fogColor;\n\
uniform vec3 selectionColor;\n\
varying float vertSelect;\n\
uniform bool fog;\n\
\n\
void main(void) {\n\
float dp = dot(vertNormal, vec3(0.0, 0.0, 1.0));\n\
float hemi = min(1.0, max(0.0, dp)*0.6+0.5);\n\
hemi *= vertColor.a;\n\
gl_FragColor = vec4(vertColor.rgb*hemi, vertColor.a);\n\
if (gl_FragColor.a == 0.0) { discard; }\n\
gl_FragColor.rgb = mix(gl_FragColor.rgb, selectionColor, \n\
step(0.5, vertSelect) * 0.7);\n\
float depth = gl_FragCoord.z / gl_FragCoord.w;\n\
if (fog) {\n\
float fog_factor = smoothstep(fogNear, fogFar, depth);\n\
gl_FragColor = mix(gl_FragColor, vec4(fogColor, gl_FragColor.w),\n\
fog_factor);\n\
}\n\
gl_FragColor.rgb = handleFog(handleSelect(gl_FragColor.rgb, vertSelect));\n\
gl_FragColor = handleAlpha(gl_FragColor);\n\
}',
// phong fragment shader
PHONG_FS : '\n\
precision ${PRECISION} float;\n\
\n\
varying vec4 vertColor;\n\
varying vec3 vertNormal;\n\
varying vec3 vertPos;\n\
uniform float fogNear;\n\
uniform float fogFar;\n\
uniform vec3 fogColor;\n\
uniform bool fog;\n\
uniform float zoom;\n\
uniform vec3 selectionColor;\n\
varying float vertSelect;\n\
\n\
void main(void) {\n\
vec3 eyePos = vec3(0.0, 0.0, zoom);\n\
float dp = dot(vertNormal, normalize(eyePos - vertPos));\n\
float hemi = min(1.0, max(0.3, dp)+0.2);\n\
hemi *= vertColor.a;\n\
//hemi *= vertColor.a;\n\
vec3 rgbColor = vertColor.rgb * hemi; \n\
rgbColor += min(vertColor.rgb, 0.8) * pow(max(0.0, dp), 18.0);\n\
rgbColor = mix(rgbColor, selectionColor, step(0.5, vertSelect) * 0.7);\n\
rgbColor = handleSelect(rgbColor, vertSelect);\n\
gl_FragColor = vec4(clamp(rgbColor, 0.0, 1.0), vertColor.a);\n\
if (gl_FragColor.a == 0.0) { discard; }\n\
float depth = gl_FragCoord.z / gl_FragCoord.w;\n\
if (fog) {\n\
float fog_factor = smoothstep(fogNear, fogFar, depth);\n\
gl_FragColor = mix(gl_FragColor, vec4(fogColor, gl_FragColor.w),\n\
fog_factor);\n\
}\n\
gl_FragColor.rgb = handleFog(gl_FragColor.rgb);\n\
gl_FragColor = handleAlpha(gl_FragColor);\n\
}',

// hemilight vertex shader
Expand All @@ -227,27 +228,17 @@ void main(void) {\n\

// outline shader. mixes outlineColor with fogColor
OUTLINE_FS : '\n\
precision ${PRECISION} float;\n\
varying float vertAlpha;\n\
varying float vertSelect;\n\
\n\
uniform vec3 outlineColor;\n\
uniform vec3 selectionColor;\n\
uniform float fogNear;\n\
uniform float fogFar;\n\
uniform vec3 fogColor;\n\
uniform bool fog;\n\
\n\
void main() {\n\
gl_FragColor = vec4(mix(outlineColor, selectionColor, vertSelect), \n\
gl_FragColor = vec4(mix(outlineColor, selectionColor, \n\
step(0.5, vertSelect)), \n\
vertAlpha);\n\
if (gl_FragColor.a == 0.0) { discard; }\n\
float depth = gl_FragCoord.z / gl_FragCoord.w;\n\
if (fog) { \n\
float fog_factor = smoothstep(fogNear, fogFar, depth);\n\
gl_FragColor = mix(gl_FragColor, vec4(fogColor, vertAlpha),\n\
fog_factor);\n\
}\n\
gl_FragColor.rgb = handleFog(gl_FragColor.rgb);\n\
gl_FragColor = handleAlpha(gl_FragColor);\n\
}',

// outline vertex shader. Expands vertices along the (in-screen) xy
Expand All @@ -259,7 +250,7 @@ attribute vec3 attrPos;\n\
attribute vec3 attrNormal;\n\
attribute vec4 attrColor;\n\
attribute float attrSelect;\n\
\n\
\n\
uniform vec3 outlineColor;\n\
uniform mat4 projectionMat;\n\
uniform mat4 modelviewMat;\n\
Expand All @@ -273,7 +264,8 @@ void main(void) {\n\
vec4 normal = modelviewMat * vec4(attrNormal, 0.0);\n\
vertAlpha = attrColor.a;\n\
vertSelect = attrSelect;\n\
vec2 expansion = relativePixelSize * (outlineWidth + 2.0 * attrSelect);\n\
vec2 expansion = relativePixelSize * \n\
(outlineWidth + 2.0 * step(0.5, attrSelect));\n\
vec2 offset = normal.xy * expansion;\n\
gl_Position.xy += gl_Position.w * offset;\n\
gl_Position.z += gl_Position.w*0.0001;\n\
Expand Down
20 changes: 15 additions & 5 deletions src/viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ Viewer.prototype = {
fov : optValue(opts, 'fov', 45.0),
doubleClick : getDoubleClickHandler(opts),
click : getClickHandler(opts),
fog : optValue(opts, 'fog', true)
fog : optValue(opts, 'fog', true),
transparency : optValue(opts, 'transparency', 'alpha'),
};
var parentRect = domElement.getBoundingClientRect();
if (options.width === 'auto') {
Expand Down Expand Up @@ -310,6 +311,9 @@ Viewer.prototype = {
this._cam.setOutlineColorColor(color.forceRGB(value));
} else if (optName === 'outlineWidth') {
this._cam.setOutlineWidth(value + 0.0 /* force to float*/);
} else if (optName === 'transparency') {
var sd = value === 'screendoor';
this._cam.setScreenDoorTransparency(sd);
}
}
return this._options[optName];
Expand Down Expand Up @@ -366,6 +370,8 @@ Viewer.prototype = {
this._cam = new Cam(this._canvas.gl());
this._cam.setUpsamplingFactor(this._canvas.superSamplingFactor());
this._cam.setOutlineWidth(this._options.outlineWidth);
var sd = this._options.transparency === 'screendoor';
this._cam.setScreenDoorTransparency(sd);
this._cam.fog(this._options.fog);
this._cam.setFogColor(this._options.background);
this._cam.setOutlineColor(this._options.outlineColor);
Expand All @@ -376,10 +382,14 @@ Viewer.prototype = {
var c = this._canvas;
var p = shouldUseHighPrecision() ? 'highp' : 'mediump';
this._shaderCatalog = {
hemilight : c.initShader(shaders.HEMILIGHT_VS, shaders.HEMILIGHT_FS, p),
phong : c.initShader(shaders.HEMILIGHT_VS, shaders.PHONG_FS, p),
outline : c.initShader(shaders.OUTLINE_VS, shaders.OUTLINE_FS, p),
lines : c.initShader(shaders.LINES_VS, shaders.LINES_FS, p),
hemilight : c.initShader(shaders.HEMILIGHT_VS,
shaders.PRELUDE_FS + shaders.HEMILIGHT_FS, p),
phong : c.initShader(shaders.HEMILIGHT_VS,
shaders.PRELUDE_FS + shaders.PHONG_FS, p),
outline : c.initShader(shaders.OUTLINE_VS,
shaders.PRELUDE_FS + shaders.OUTLINE_FS, p),
lines : c.initShader(shaders.LINES_VS,
shaders.PRELUDE_FS + shaders.LINES_FS, p),
text : c.initShader(shaders.TEXT_VS, shaders.TEXT_FS, p),
selectLines : c.initShader(shaders.SELECT_LINES_VS,
shaders.SELECT_LINES_FS, p),
Expand Down

0 comments on commit 70fd0c2

Please sign in to comment.