diff --git a/examples/browser/control.html b/examples/browser/control.html
index 5176caa..9aaae04 100644
--- a/examples/browser/control.html
+++ b/examples/browser/control.html
@@ -43,24 +43,31 @@
Jocly on Github -
diff --git a/examples/browser/js/control.js b/examples/browser/js/control.js
index 7465a08..8841b66 100644
--- a/examples/browser/js/control.js
+++ b/examples/browser/js/control.js
@@ -132,7 +132,7 @@ $(document).ready(function () {
if(options.autocomplete!==undefined)
$("#options-autocomplete").show().children("input").prop("checked",options.autocomplete);
- $("#options").on("change",function() {
+ $("#view-options").on("change",function() {
var opts={};
if($("#options-skin").is(":visible"))
opts.skin=$("#options-skin").val();
@@ -151,6 +151,13 @@ $(document).ready(function () {
})
});
+ $("#anaglyph-input").on("change",function() {
+ if($(this).is(":checked"))
+ match.viewControl("enterAnaglyph");
+ else
+ match.viewControl("exitAnaglyph");
+ });
+
// the match need to be attached to a DOM element for displaying the board
match.attachElement(area)
.then( () => {
diff --git a/gulpfile.js b/gulpfile.js
index 04c95f7..c449b60 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -286,6 +286,7 @@ gulp.task("build-browser-xdview",function() {
lib+"threex.domevent.js",
lib+"threex.domevent.object3d.js",
lib+"StereoEffect.js",
+ lib+"AnaglyphEffect.js",
srcLib+"VRGamepad.js",
lib+"VRControls.js",
lib+"VREffect.js",
diff --git a/src/browser/jocly.xd-view.js b/src/browser/jocly.xd-view.js
index ec476c0..8171582 100644
--- a/src/browser/jocly.xd-view.js
+++ b/src/browser/jocly.xd-view.js
@@ -2495,6 +2495,7 @@ if(window.JoclyXdViewCleanup)
threeCtx.camera.updateProjectionMatrix();
} else {
threeCtx.renderer.setSize(this.mGeometry.width,this.mGeometry.height);
+ threeCtx.anaglyphEffect.setSize(this.mGeometry.width,this.mGeometry.height);
threeCtx.camera.aspect=this.mGeometry.width/this.mGeometry.height;
threeCtx.camera.updateProjectionMatrix();
}
@@ -2726,6 +2727,25 @@ if(window.JoclyXdViewCleanup)
options = options || {};
var promise = new Promise( function(resolve, reject) {
switch(cmd) {
+ case "enterAnaglyph":
+ if(threeCtx) {
+ threeCtx.anaglyph = true;
+ var factor = 2.5;
+ threeCtx.scene.scale.set(1/factor,1/factor,1/factor);
+ threeCtx.camera.scale.set(factor,factor,factor);
+ threeCtx.animControl.trigger();
+ };
+ resolve();
+ break;
+ case "exitAnaglyph":
+ if(threeCtx) {
+ threeCtx.anaglyph = false;
+ threeCtx.scene.scale.set(1,1,1);
+ threeCtx.camera.scale.set(1,1,1);
+ threeCtx.animControl.trigger();
+ };
+ resolve();
+ break;
default:
reject(new Error("ViewControl: unsupported command "+cmd));
}
@@ -3045,6 +3065,9 @@ if(window.JoclyXdViewCleanup)
var stereoEffect = new THREE.StereoEffect(renderer);
stereoEffect.setSize( area.width(), area.height() );
+ var anaglyphEffect = new THREE.AnaglyphEffect( renderer );
+ anaglyphEffect.setSize( area.width(), area.height() );
+
var gamepads = new VRGamepads({
camera: camera,
scene: scene,
@@ -3204,7 +3227,9 @@ if(window.JoclyXdViewCleanup)
if(stereo) {
gamepads.update();
stereoEffect.render( scene, camera );
- } else
+ } else if(ctx.anaglyph)
+ anaglyphEffect.render(scene,camera);
+ else
renderer.render( scene, camera );
}
if(showStats) {
@@ -3279,6 +3304,8 @@ if(window.JoclyXdViewCleanup)
body: body,
harbor: harbor,
defaultHarborQuaternion: harbor.quaternion.clone(),
+ anaglyphEffect: anaglyphEffect,
+ anaglyph: false
};
function VRGetIntersect(position,direction,callback) {
diff --git a/third-party/AnaglyphEffect.js b/third-party/AnaglyphEffect.js
new file mode 100644
index 0000000..a5a8f45
--- /dev/null
+++ b/third-party/AnaglyphEffect.js
@@ -0,0 +1,152 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author marklundin / http://mark-lundin.com/
+ * @author alteredq / http://alteredqualia.com/
+ * @author tschw
+ */
+
+THREE.AnaglyphEffect = function ( renderer, width, height ) {
+
+ // Matrices generated with angler.js https://github.com/tschw/angler.js/
+ // (in column-major element order, as accepted by WebGL)
+
+ this.colorMatrixLeft = new THREE.Matrix3().fromArray( [
+
+ 1.0671679973602295, -0.0016435992438346148, 0.0001777536963345483, // r out
+ -0.028107794001698494, -0.00019593400065787137, -0.0002875397040043026, // g out
+ -0.04279090091586113, 0.000015809757314855233, -0.00024287120322696865 // b out
+
+ ] );
+
+ // red green blue in
+
+ this.colorMatrixRight = new THREE.Matrix3().fromArray( [
+
+ -0.0355340838432312, -0.06440307199954987, 0.018319187685847282, // r out
+ -0.10269022732973099, 0.8079727292060852, -0.04835830628871918, // g out
+ 0.0001224992738571018, -0.009558862075209618, 0.567823588848114 // b out
+
+ ] );
+
+ var _camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
+
+ var _scene = new THREE.Scene();
+
+ var _stereo = new THREE.StereoCamera();
+
+ var _params = { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat };
+
+ if ( width === undefined ) width = 512;
+ if ( height === undefined ) height = 512;
+
+ var _renderTargetL = new THREE.WebGLRenderTarget( width, height, _params );
+ var _renderTargetR = new THREE.WebGLRenderTarget( width, height, _params );
+
+ var _material = new THREE.ShaderMaterial( {
+
+ uniforms: {
+
+ "mapLeft": { value: _renderTargetL.texture },
+ "mapRight": { value: _renderTargetR.texture },
+
+ "colorMatrixLeft": { value: this.colorMatrixLeft },
+ "colorMatrixRight": { value: this.colorMatrixRight }
+
+ },
+
+ vertexShader: [
+
+ "varying vec2 vUv;",
+
+ "void main() {",
+
+ " vUv = vec2( uv.x, uv.y );",
+ " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+ "}"
+
+ ].join( "\n" ),
+
+ fragmentShader: [
+
+ "uniform sampler2D mapLeft;",
+ "uniform sampler2D mapRight;",
+ "varying vec2 vUv;",
+
+ "uniform mat3 colorMatrixLeft;",
+ "uniform mat3 colorMatrixRight;",
+
+ // These functions implement sRGB linearization and gamma correction
+
+ "float lin( float c ) {",
+ " return c <= 0.04045 ? c * 0.0773993808 :",
+ " pow( c * 0.9478672986 + 0.0521327014, 2.4 );",
+ "}",
+
+ "vec4 lin( vec4 c ) {",
+ " return vec4( lin( c.r ), lin( c.g ), lin( c.b ), c.a );",
+ "}",
+
+ "float dev( float c ) {",
+ " return c <= 0.0031308 ? c * 12.92",
+ " : pow( c, 0.41666 ) * 1.055 - 0.055;",
+ "}",
+
+
+ "void main() {",
+
+ " vec2 uv = vUv;",
+
+ " vec4 colorL = lin( texture2D( mapLeft, uv ) );",
+ " vec4 colorR = lin( texture2D( mapRight, uv ) );",
+
+ " vec3 color = clamp(",
+ " colorMatrixLeft * colorL.rgb +",
+ " colorMatrixRight * colorR.rgb, 0., 1. );",
+
+ " gl_FragColor = vec4(",
+ " dev( color.r ), dev( color.g ), dev( color.b ),",
+ " max( colorL.a, colorR.a ) );",
+
+ "}"
+
+ ].join( "\n" )
+
+ } );
+
+ var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), _material );
+ _scene.add( mesh );
+
+ this.setSize = function ( width, height ) {
+
+ renderer.setSize( width, height );
+
+ var pixelRatio = renderer.getPixelRatio();
+
+ _renderTargetL.setSize( width * pixelRatio, height * pixelRatio );
+ _renderTargetR.setSize( width * pixelRatio, height * pixelRatio );
+
+ };
+
+ this.render = function ( scene, camera ) {
+
+ scene.updateMatrixWorld();
+
+ if ( camera.parent === null ) camera.updateMatrixWorld();
+
+ _stereo.update( camera );
+
+ renderer.render( scene, _stereo.cameraL, _renderTargetL, true );
+ renderer.render( scene, _stereo.cameraR, _renderTargetR, true );
+ renderer.render( _scene, _camera );
+
+ };
+
+ this.dispose = function() {
+
+ if ( _renderTargetL ) _renderTargetL.dispose();
+ if ( _renderTargetR ) _renderTargetR.dispose();
+
+ };
+
+};