/**
* @preserve @license Copyright 2014-Forever Secret Robot LLC. All rights reserved.
*/
/** @define {boolean} */
var DEBUG = false;
// jQuery-like helper.
/*
function $(id)
{
return document.getElementById( id );
}
*/
function rgb(r, g, b)
{
r = Math.floor(r);
g = Math.floor(g);
b = Math.floor(b);
return ["rgb(",r,",",g,",",b,")"].join("");
}
function rgba(r, g, b, a)
{
r = Math.floor(r);
g = Math.floor(g);
b = Math.floor(b);
return ["rgba(",r,",",g,",",b,",",a,")"].join("");
}
function UpdateSceneViz()
{
if (DEBUG)
{
var cubeFaceMeshIndex = 0;
cubeFaceMeshes.map(function(cubeFaceMesh)
{
var id = 'sceneRect' + cubeFaceMeshIndex.toString()
// var colorString = rgb(color.r * 255.0, color.g * 255.0, color.b * 255.0)
var element = $(id)
var sceneIndex = cubeScenes.indexOf(cubeFaceMesh.scene)
element.innerHTML = sceneIndex
var color = cubeFaceMesh.children[1].material.color
id = 'rect' + cubeFaceMeshIndex.toString()
var colorString = rgba(color.r * 255.0, color.g * 255.0, color.b * 255.0, cubeFaceMesh.isVisible ? 1.0 : 0.03)
element = $(id)
var before = element.style.backgroundColor
element.style.backgroundColor = colorString;
element.style.border = cubeFaceMesh.isVisible ? "1px solid black" : "1px dashed #dddddd";
element.style.color = cubeFaceMesh.isVisible ? "black" : "#bbbbbb";
cubeFaceMeshIndex += 1
});
}
}
/*
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
*/
var container; //
created in JS to hold the WebGL canvas.
var camera, scene, renderer;
var orbitControls;
var controlSchemes = []
var controls;
var vrmgr, effect;
var clock = new THREE.Clock(); // Used to advance animation.
var cubeScenes = []
var cubeFaceMeshes = []
var mainCubeFaceMesh
var sceneFilenameToCubeSceneMap = {}
var windowsObject
var moonCubeScene
var moonNormalMap
var faceMesh // Jumbled up vertices
/*
var initialized = [];
*/
var ambientLight; // Workaround: ??? what does this do ???
var pendingObjects = [];
var pendingCubeFaces = [];
var moonHouseFilename = 'Assets3D/Box - Moon House 010'
//var faceFilename = 'Assets3D/Box - Suzanne 002'
var caveFilename = 'Assets3D/EXPERIMENT - cave 005 - DELETE_ME_MANGLED_FOR_EXPORT 013'
var filenames = [
'Assets3D/Box - QR universe 006',
'Assets3D/Box - Test sphere 009',
moonHouseFilename,
'Assets3D/Box - Moon 001',
'Assets3D/Box - Cornell Cube 008',
caveFilename,
// faceFilename,
// 'Assets3D/Box - Rooms 001',
// 'Assets3D/Box - screens 001',
]
var sceneFilenames = filenames.map(function(filename) { return filename + '.obj'; })
var sceneMtlFilenames = filenames.map(function(filename) { return filename + '.mtl'; })
VR_INSTRUCTION_DEFAULT = 0
VR_INSTRUCTION_WAITING_FOR_LANDSCAPE = 1
VR_INSTRUCTION_COUNTING_DOWN = 2
VR_INSTRUCTION_IN_VR = 3
var vrInstructionState = VR_INSTRUCTION_DEFAULT
function log()
{
/*
var _console = document.getElementById('_console')
// console.log.apply(console, arguments);
// _console.innerHTML += arguments.join(",") + '\n' //'\nwindow.orientation: ' + window.orientation
_console.innerHTML += arguments[0] + '\n' //'\nwindow.orientation: ' + window.orientation
// if(console){
// console.log.apply(console, arguments);
// }
*/
}
$(function()
{
var result = init();
if (result !== false)
{
animate(); // Jumpstart the first of an "infinite" series of calls to animate().
}
})
/*
function WORKAROUND_FixEmptyHierarchyEntries(animation)
{
animation.hierarchy.splice(1,1)
}
*/
function ToggleWebVRInLandscape()
{
// var _console = document.getElementById('_console')
// _console.innerHTML += '\nwindow.orientation: ' + window.orientation
if (window.orientation == -90 || window.orientation == 90)
{
// Landscape orientation, hide divs - logo, blurb, etc.
$('.HideInVR').hide()
vrmgr.setVisibility(true)
// _console.innerHTML += '\nDivs: HIDDEN'
if (vrInstructionState == VR_INSTRUCTION_WAITING_FOR_LANDSCAPE)
{
// Start countdown!
$('#vrInstructionText1').hide()
$('#vrInstructionButtons').hide()
$('#vrInstructionText2').show()
$('#vrInstructionCountdown').show()
vrInstructionState = VR_INSTRUCTION_COUNTING_DOWN
// TODO Update countdown timer every second or so.
// Start timer to hide instructions & enter VR mode after 5 seconds
var startTime = new Date().getTime();
var startSeconds = new Date().getSeconds();
$('#countdownSpan').html('5')
var interval = setInterval(function()
{
if(new Date().getTime() - startTime > 5000)
{
clearInterval(interval);
return false;
}
var countDownValue = 5 - (new Date().getSeconds() - startSeconds)
$('#countdownSpan').html(countDownValue + '')
log(countDownValue)
//do whatever here..
}, 500);
setTimeout(function()
{
$('#vrInstructions1').hide()
}, 4500)
setTimeout(function()
{
$('#vrInstructionText1').show()
$('#vrInstructionButtons').show()
$('#vrInstructionText2').hide()
$('#vrInstructionCountdown').hide()
vrmgr.enterVR()
}, 5000)
}
}
else
{
// Exit VR when go back to portrait.
if (vrmgr.isVRMode())
vrmgr.exitVR()
// Portrait orientation, show divs - logo, blurb, etc.
$('.HideInVR').show()
vrmgr.setVisibility(false)
// _console.innerHTML += '\nDivs: SHOWN'
}
}
function IsWebGLSupported()
{
var canvas;
var ctx;
var exts;
try
{
canvas = document.createElement('canvas');
ctx = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
exts = ctx.getSupportedExtensions();
}
catch (e)
{
return false;
}
if (ctx !== undefined)
{
return true
// Modernizr.webglextensions = new Boolean(true);
}
for (var i = -1, len = exts.length; ++i < len; )
{
// Modernizr.webglextensions[exts[i]] = true;
}
canvas = undefined;
return false
}
function init()
{
container = document.createElement( 'div' );
document.body.appendChild( container );
if (!IsWebGLSupported())
{
console.log('Error initializing WebGL')
var error = $('#error').get(0)
error.removeAttribute( 'data-status' )
error.setAttribute( 'data-status', 'shown' );
var progress = $('#progress').get(0)
progress.removeAttribute( 'data-status' )
progress.setAttribute( 'data-status', 'removed' );
return false
}
try
{
renderer = new THREE.WebGLRenderer({ antialias: true, stencil: true });
}
catch (error)
{
}
camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 0.1, 100 );
// camera.position.x = 2;
camera.position.z = 2.5;
// Touch-based orbit controls, non-VR mode.
orbitControls = new THREE.OrbitControls(camera)
// orbitControls.damping = 0.2
orbitControls.momentumOn = true
orbitControls.momentumDampingFactor = 0.9 // How much we reduce momentum in every time step.
orbitControls.momentumScalingFactor = 0.005 //
// orbitControls.momentumScalingFactor = 0.05
// orbitControls.addEventListener('change', render); // NOTE: Don't need to trigger render when controls change, b/c we're already rendering every frame.
// orbitControls.userZoom = false
// orbitControls.userPan = false
orbitControls.noPan = true
orbitControls.noZoom = true
orbitControls.autoRotate = true
// Applies VR headset positional data to camera.
var vrControls = new THREE.VRControls(camera)
// We switch between 2 controls schemes: touch orbit & VR IMU controls. Touch orbit controls are the default.
controlSchemes = [orbitControls, vrControls]
controls = orbitControls
// var controls = new THREE.VRControls(camera);
// Apply VR stereo rendering to renderer
effect = new THREE.VREffect(renderer);
effect.setSize(window.innerWidth, window.innerHeight);
var _console = document.getElementById('_console')
// Create a VR manager helper to enter and exit VR mode.
vrmgr = new WebVRManager(effect);
// TODO Wait for WebVR manager to be initialized,
log("before setup ready callback")
/*
// $(window).load(function()
$(function()
{
*/
log("\nsetup event handlers")
// TODO Enable VR on desktop, for Oculus.
// Only enable VR when we're ready !!!
if (vrmgr.os == 'iOS' || vrmgr.os == 'Android')
{
$('#enterVRButton').show()
$('#enterVRButton').click(function(e)
{
e.preventDefault();
if (vrmgr.os == 'iOS' || vrmgr.os == 'Android')
{
$('#vrInstructions1').show(); // TODO Animate / fade in background
vrInstructionState = VR_INSTRUCTION_WAITING_FOR_LANDSCAPE
return false
}
else
{
vrmgr.enterVR()
}
})
}
$('#noVRPleaseButton').click(function(e)
{
e.preventDefault();
$('#vrInstructions1').hide(); // TODO Animate / fade in background
return false
})
/*
$('#dontHaveVRHeadsetButton').click(function(e)
{
e.preventDefault();
$('#vrInstructions1').hide(); // TODO Animate / fade in background
$('#whereToBuyVRHeadset').show(); // TODO Animate / fade in background
return false
})
*/
$('#dismissBuyVRHeadset').click(function(e)
{
e.preventDefault();
$('#whereToBuyVRHeadset').hide(); // TODO Animate / fade in background
return false
})
ToggleWebVRInLandscape()
log("DONE setup event handlers")
/*
})
*/
log("after setup ready callback")
ToggleWebVRInLandscape()
window.addEventListener("orientationchange", function()
{
ToggleWebVRInLandscape()
}, false);
/*
vrmgr.isHMDAvailable().then(function(isCompatible)
{
if (isCompatible)
{
// When enter landscape, just turn on VR mode by default.
if (window.orientation == -90 || window.orientation == 90)
{
// TODO Don't enter VR by default.
vrmgr.enterVR()
log("entered VR!")
log("" + vrmgr.isVRMode())
// Hide divs - logo, blurb, etc.
$('.HideInVR').hide()
}
}
else
{
// this.setMode(Modes.INCOMPATIBLE);
}
}.bind(this));
*/
// scene
scene = new THREE.Scene();
// var ambientLight = new THREE.AmbientLight( 0x101030 );
// var ambientLight = new THREE.AmbientLight( 0xffffff );
ambientLight = new THREE.AmbientLight( 0xffffff );
scene.add( ambientLight );
/*
var directionalLight = new THREE.DirectionalLight( 0xffeedd );
directionalLight.position.set( 0, 0, 1 );
scene.add( directionalLight );
*/
// texture
var manager = THREE.DefaultLoadingManager;
/*
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total )
{
console.log('LoadingManager - LOADED PROGRESS CALLBACK:', item, loaded, total );
var bar = 250;
var total = progress.totalModels + progress.totalTextures;
var loaded = progress.loadedModels + progress.loadedTextures;
if (total)
bar = Math.floor(bar * loaded / total);
$("bar").style.width = bar + "px";
// TODO Trigger the app to start when all are loaded.
};
*/
log("InitScenes()")
InitScenes(manager);
log("DONE InitScenes()")
//
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
renderer.setClearColor( 0xffffff, 1);
// renderer.setClearColor( 0x000000, 1);
// renderer.setClearColor( 0x333333, 1);
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
//
window.addEventListener( 'resize', onWindowResize, false );
log("DONE init()")
}
function Finalize()
{
console.log('%c Finalize -- DONE LOADING, STARTING 3D', 'background: magenta;')
log("BEGIN finalize()")
var maxAnisotropy = renderer.getMaxAnisotropy();
if (pendingObjects.length <= 0)
{
console.log('%cERROR','background: red', 'only', pendingObjects.length, 'pendingObjects')
}
pendingObjects.map(function(pendingObject)
{
var object = pendingObject[0];
var index = pendingObject[1];
var filename = pendingObject[2];
object.traverse( function ( child )
{
// if (child instanceof THREE.Mesh)
if (child instanceof THREE.Mesh && child.material.name.indexOf('__DONT_FIX_MATERIAL__') < 0)
{
// TODO Need to do this *after* texture has loaded, so setup asset setup in that order !!!
var map = child.material.map;
// child.material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
child.material = new THREE.MeshBasicMaterial( { color: child.material.color, name: child.material.name } );
child.material.map = map; // TODO ???
if (child.material.map != undefined)
{
// if (child.material.name.indexOf('__NO_ANISOTROPY__') < 0)
// {
child.material.map.anisotropy = maxAnisotropy;
// console.log('%cmaterial','background:cyan',child.material.name)
// }
// else
// {
if (child.material.name.indexOf('__CLAMP_TEXTURE_TO_EDGE__') >= 0)
{
child.material.map.wrapS = child.material.map.wrapT = THREE.ClampToEdgeWrapping;
}
}
}
} );
object.visible = false;
// This look super cool ! The interior box scenes get a really weird orientation relative to each other.
// object.rotation.y = Math.PI / 2.0 * index * Math.PI / 2.0;
// object.rotation.y = Math.PI / 2.0 * index - 3.0 * Math.PI / 2.0;
if (filename != 'Assets3D/Box - Moon 001.obj')
{
cubeScenes[index] = object;
// Initialize(index);
}
sceneFilenameToCubeSceneMap[filename] = object;
scene.add( object );
console.log('Loaded .OBJ file and added to scene:',filename,index);
});
// Pre-upload all textures.
// OPTIMIZATION: Do this *during load* so there's no "pop" when calling texImage2D() at "runtime".
// OPTIMIZATION: Fixes the issue where the scene pauses just as a new cube face becomes visible - due to blocking call uploading its textures.
scene.traverse(function(object)
{
// if (child instanceof THREE.Mesh)
if (object instanceof THREE.Mesh && object.material != undefined && object.material != null)
{
var map = object.material.map;
if (map != undefined && map != null)
{
renderer.uploadTexture(map)
}
}
});
if (cubeScenes.length != filenames.length)
{
console.log('%cERROR','background: red', cubeScenes.length, 'cubeScenes, but ', filenames.length, 'filenames!')
}
// Post-process scenes.
// var moonScene = sceneFilenameToCubeSceneMap['Assets3D/Box - Moon 001.obj']
var moonObject = scene.getObjectByName('__THE_MOON___Icosphere.001')
moonObject.traverse(function(child)
{
if (child.material != undefined && child.material.map != undefined)
{
// THREE.MeshPhongMaterial( { ambient: 0x000000, color: 0xff66aa, specular: 0x555555, shininess: 20 } ) );
// child.material = new THREE.MeshLambertMaterial( { color: child.material.color, map: child.material.map, normalMap: moonNormalMap } );
child.material = new THREE.MeshLambertMaterial( { color: child.material.color, map: child.material.map } );
}
});
// var faceScene = sceneFilenameToCubeSceneMap[faceFilename + '.obj']
// faceScene.add(faceMesh)
var faceNames = [
'Cube.002_Face2', // Cube face that's coincident with the "open face" of the cube.
'Cube_Face1',
'Cube.003_Face3',
'Cube.004_Face4',
'Cube.001_Face5', // Top
'Cube.005_Face6', // Bottom
];
if (pendingCubeFaces.length <= 0)
console.log('%cERROR','background: red', 'only', pendingObjects.length, 'pendingObjects');
pendingCubeFaces.map(function(object)
{
object.traverse( function ( child )
{
if (child.name != '' && faceNames.indexOf(child.name) >= 0)
{
// var index = faceNames.indexOf(child.name);
child.material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
// child.material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
// child.material.color = 0xff0000;
// child.material.wireframe = true;
// TODO Does order matter here?
// cubeFaceMeshes[index] = child;
cubeFaceMeshes.push(child);
}
});
scene.add( object );
console.log('Loaded box faces and added to scene:');
});
// Initialize each cube face:
// * assign its initial scene (duplicate are OK).
var i = 0;
cubeFaceMeshes.map(function(cubeFaceMesh)
{
cubeFaceMesh.isVisible = false
cubeFaceMesh.wasVisible = false
cubeFaceMesh.scene = cubeScenes[i]
i = (i + 1) % cubeScenes.length
if (cubeFaceMesh.scene == undefined)
console.log('%cERROR','background: red', 'cubeFaceMesh.scene is null!');
});
UpdateSceneViz();
var mainCubeFaceMesh = scene.getObjectByName('Cube.002_Face2', true)
// Hide all the special objects that we should hide...
var objectsToDelete = []
scene.traverse(function(child)
{
if (child.name.indexOf('__HIDE_ME__') > -1)
{
objectsToDelete.push(child)
/*
console.log('%cHID AN OBJECT','background:magenta',child)
child.visible = false;
child.traverse(function(subChild)
{
console.log('%cHID AN OBJECT','background:magenta',subChild)
subChild.visible = false;
});
*/
}
});
objectsToDelete.map(function(object)
{
THREE.SceneUtils.detach(object, object.parent, scene);
});
// Hide loading bar.
var progress = $('#progress').get(0)
progress.removeAttribute( 'data-status' )
progress.setAttribute( 'data-status', 'hidden' );
setTimeout( function() {
progress.removeAttribute( 'data-status' );
progress.setAttribute( 'data-status', 'removed' );
// state = $('progress').getAttribute( 'data-status' );
}, 1000 );
// $("progress").style.display = 'none';
log("DONE finalize()")
}
/*
function LoadVerticesAndColors(string)
{
var currentBuffer, vertices=[], colors=[]
var entries = string.split(',')
entries.forEach(function(string)
{
if (string.indexOf('vert-xyz') > -1)
{
currentBuffer = vertices
}
else if (string.indexOf('col-rgba') > -1)
{
currentBuffer = colors
}
else
{
currentBuffer.push( parseFloat(string) )
}
})
if (vertices.length/3 != colors.length/4)
{
console.log('%cERROR','vertex and color array lengths are not expected lengths! Should be multiple of 3 and 4, resp.',vertices,colors)
}
// // this is all pretty ad-hoc but it will work well enough for a demo
// if (vertices.length/3 === colors.length/4)
// {
// polys.setArrays(vertices, colors)
// vertBuffer.update( polys.vertArr )
// colBuffer.update( polys.colArr )
// }
return [vertices, colors]
}
function LoadVertexJumbleObject(url)
{
// TODO Use Three.JS XHR loader, so this is included in loading progress...
var loader = new THREE.XHRLoader();
// loader.setCrossOrigin( this.crossOrigin );
loader.load( url, function ( text )
{
Setup(text)
// onLoad( scope.parse( JSON.parse( text ) ) );
});
// var client = new XMLHttpRequest()
// client.open('GET', url);
// client.onreadystatechange = function()
// {
// // TODO Handle error !
// var verticesAndColorsString = client.responseText
// Setup(verticesAndColorsString)
// }
// client.send();
}
function SetupMaterial()
{
var attributes =
{
// customColor: { type: 'v4v', value: [] }
customColor: { type: 'v4', value: null }
};
// uniforms = { };
var shaderMaterial = new THREE.ShaderMaterial({
// var shaderMaterial = new THREE.RawShaderMaterial({
// uniforms: uniforms,
attributes: attributes,
vertexShader: document.getElementById( 'vertexshader' ).textContent,
fragmentShader: document.getElementById( 'fragmentshader' ).textContent,
// NOTE: AndyHall's projectron uses default GL blending, no depth test, transparency (blending), and double-sided triangles
// blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true,
side: THREE.DoubleSide,
name: '__DONT_FIX_MATERIAL__'
});
return shaderMaterial
}
function Setup(verticesAndColorsString)
{
var shaderMaterial = SetupMaterial()
var verticesAndColors = LoadVerticesAndColors(verticesAndColorsString)
var vertices = verticesAndColors[0] // Unpack multiple return values.
var vertexColors = verticesAndColors[1]
console.log('%cVERTICES','background:pink',vertices.length)
console.log('%cVERTEX COLORS','background:pink',vertexColors.length)
console.log('%cTRIS','background:pink',vertices.length / 9)
console.log('%cTRIS','background:pink',vertexColors.length / 12)
// Populate attribute buffer w/ RGBA vertex colors.
// var vertices = mesh.geometry.vertices;
// var bufferGeometry = new THREE.BufferGeometry()
// var verticesArray = new Float32Array(vertices.length); verticesArray.set(vertices)
// bufferGeometry.addAttribute('position', new THREE.BufferAttribute(verticesArray, 3))
// var vertexColorsArray = new Float32Array(vertexColors.length); vertexColorsArray.set(vertexColors)
// bufferGeometry.addAttribute('customColor', new THREE.BufferAttribute(vertexColorsArray, 4))
// var bufferGeometry = new THREE.BufferGeometry()
// var verticesArray = new Float32Array(vertices.length); verticesArray.set(vertices)
// bufferGeometry.addAttribute('position', new THREE.BufferAttribute(verticesArray, 3))
// var vertexColorsArray = new Float32Array(vertexColors.length); vertexColorsArray.set(vertexColors)
// var vertexColorsBufferAttribute = new THREE.BufferAttribute(vertexColorsArray, 4)
// bufferGeometry.addAttribute('customColor', vertexColorsBufferAttribute)
// var mesh = new THREE.Mesh(bufferGeometry, shaderMaterial)
// console.log('%cVERTICES','background:pink',verticesArray.length)
// console.log('%cVERTEX COLORS','background:pink',vertexColorsArray.length)
// var values_color = shaderMaterial.attributes.customColor.value;
// for (var vertexColorIndex = 0; vertexColorIndex < vertexColors.length / 4; vertexColorIndex ++)
// {
// // values_color[vertexColorIndex] = new THREE.Vector4(vertexColors[vertexColorIndex*4+0], vertexColors[vertexColorIndex*4+1], vertexColors[vertexColorIndex*4+2], vertexColors[vertexColorIndex*4+3]);
// var vertexColor = new THREE.Vector4(vertexColors[vertexColorIndex*4+0], vertexColors[vertexColorIndex*4+1], vertexColors[vertexColorIndex*4+2], vertexColors[vertexColorIndex*4+3])
// values_color.push(vertexColor)
// }
// var geometry = new THREE.Geometry();
// for (var triangleIndex = 0; triangleIndex < vertices.length / 9; triangleIndex++)
// {
// // geometry.vertices.push(
// // new THREE.Vector3( vertices[triangleIndex*3+0], vertices[triangleIndex*3+1], vertices[triangleIndex*3+2]),
// // new THREE.Vector3( vertices[triangleIndex*3+3], vertices[triangleIndex*3+4], vertices[triangleIndex*3+5]),
// // new THREE.Vector3( vertices[triangleIndex*3+6], vertices[triangleIndex*3+7], vertices[triangleIndex*3+8])
// // );
// geometry.vertices.push(new THREE.Vector3( vertices[triangleIndex*3+0], vertices[triangleIndex*3+1], vertices[triangleIndex*3+2]))
// geometry.vertices.push(new THREE.Vector3( vertices[triangleIndex*3+3], vertices[triangleIndex*3+4], vertices[triangleIndex*3+5]))
// geometry.vertices.push(new THREE.Vector3( vertices[triangleIndex*3+6], vertices[triangleIndex*3+7], vertices[triangleIndex*3+8]))
// var face = new THREE.Face3(triangleIndex*3 + 0, triangleIndex*3 + 1, triangleIndex*3 + 2)
// // var vertexColorArray = [ ??? ]
// // var face = new THREE.Face3(vertexIndex + 0, vertexIndex + 1, vertexIndex + 2, undefined, vertexColorArray)
// // var face = new THREE.Face3(vertexIndex + 0, vertexIndex + 1, vertexIndex + 2, undefined, vertexColorArray, materialIndex)
// // var face = new THREE.Face3(vertexIndex + 0, vertexIndex + 1, vertexIndex + 2, normal, color, materialIndex)
// // var face = new THREE.Face3(vertexIndex + 0, vertexIndex + 1, vertexIndex + 2)
// geometry.faces.push(face)
// }
// geometry.dynamic = true;
// // geometry.computeBoundingSphere() // TODO ???
// shaderMaterial.attributes.customColor.needsUpdate = true;
// var mesh = new THREE.Mesh(geometry, shaderMaterial)
// // mesh.position.set(-1,-1,-1)
// // mesh.scale.set(2,2,2)
// mesh.rotation.y = Math.PI / 2.0
// // mesh.position.set(-.5,-.5,-.5)
// // mesh.scale.set(1,1,-1)
// var scale = 2
// mesh.scale.set(2,2,-2)
// mesh.position.set(0,-scale/2.0,scale/2.0)
// var scale = 4
// mesh.scale.set(scale,scale,-1)
// mesh.position.set(1,-scale/2.0,scale/2.0)
// scene.add(mesh)
faceMesh = mesh
// cubeScenes.push(mesh) // TODO ???
// sceneFilenameToCubeSceneMap['Plato'] = mesh // TODO ???
// TODO "Taper-scale" vertices either (a) beforehand, or (b) in vertex shader
}
*/
function InitScenes(manager)
{
THREE.DefaultLoadingManager.onProgress = function(event, loaded, total)
{
console.log('%c THREE.DefaultLoadingManager.onProgress', 'background: green;', event)
console.log('\t', loaded, total)
/*
var bar = 250;
var total = progress.totalModels + progress.totalTextures;
var loaded = progress.loadedModels + progress.loadedTextures;
if (total)
bar = Math.floor(bar * loaded / total);
$("bar").style.width = bar + "px";
*/
// When both are true, then everything is loaded and we can proceed:
// (a) loaded === total
// (b) AND we submitted calls to load every scene
/*
if (loaded === total)
{
console.log('FINALIZING...')
Finalize();
}
else
{
console.log('*NOT* FINALIZING...', loaded, total)
}
*/
}
THREE.DefaultLoadingManager.onLoad = function()
{
/*
$("progress").style.display = 'none';
*/
console.log('FINALIZING...')
Finalize();
}
/*
var originalItemStart = THREE.DefaultLoadingManager.itemStart;
THREE.DefaultLoadingManager.itemStart = function(url)
{
originalItemStart(url);
}
var originalItemEnd = THREE.DefaultLoadingManager.itemEnd;
THREE.DefaultLoadingManager.itemEnd = function(url)
{
originalItemEnd(url);
}
*/
// var texture = new THREE.Texture();
var onProgress = function ( xhr )
{
// console.log('%c onProgress', 'background: yellow;', xhr)
console.log('%c onProgress', 'background: yellow;', xhr.target.responseURL)
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round(percentComplete, 2) + '% downloaded' );
/*
var bar = 250;
var total = progress.totalModels + progress.totalTextures;
var loaded = progress.loadedModels + progress.loadedTextures;
if (total)
bar = Math.floor(bar * loaded / total);
$("bar").style.width = bar + "px";
*/
// var bar = 250;
// bar = Math.floor(bar * percentComplete / 100.0);
// $("bar").style.width = bar + "px";
}
};
var onError = function ( xhr )
{
};
/*
// textureFilenames = ['Assets/QRTexture001.png', 'Assets/BakeCornellBox001.png', undefined]
sceneFilenames = ['Assets/Box - QR Universe 003.obj', 'Assets/Box 002.obj', 'Assets/Box - flat earth - 003.obj', 'Assets/Box - test sphere - 003.obj'];
sceneMtlFilenames = ['Assets/Box - QR Universe 003.mtl', 'Assets/Box 002.mtl', 'Assets/Box - flat earth - 003.mtl', 'Assets/Box - test sphere - 003.mtl'];
*/
/*
sceneFilenames.map(function(filename)
{
initialized.push(false);
});
// initialized = [false, false];
*/
// Load all the OBJ files.
function ProcessAndAddObject(object, index, filename)
{
// console.log(object)
pendingObjects.push([object, index, filename])
}
/*
// var imageLoader = new THREE.ImageLoader(manager)
THREE.ImageUtils.loadTexture ('Assets/moon_normal.png', undefined, function(texture) { moonNormalMap = texture })
*/
// var objLoader = new THREE.OBJLoader( manager );
var objLoader = new THREE.OBJMTLLoader(manager);
sceneFilenames.map(function(filename)
{
var index = sceneFilenames.indexOf(filename)
var mtlFilename = sceneMtlFilenames[index]
// Ugh ugly workaround to make a 'curried' function with extra scope variables.
function MakeClosure() {
return function (object) {
return ProcessAndAddObject(object, index, filename)
}
}
objLoader.load( filename, mtlFilename, MakeClosure(), onProgress, onError );
})
//new TWEEN.Tween( cube.rotation ).to( { y:Math.random()}, 1000 ).easing( TWEEN.Easing.Quadratic.EaseOut).start();)
function ProcessAndAddObject2(object)
{
pendingCubeFaces.push(object)
}
objLoader.load('Assets3D/Box -- META - box face meshes 005.obj', 'Assets3D/Box -- META - box face meshes 005.mtl', ProcessAndAddObject2, onProgress, onError);
// objLoader.load('Assets/BoxFaces001.obj', 'Assets/BoxFaces001.mtl', ProcessAndAddObject2, onProgress, onError);
// objLoader.load( 'EXPERIMENT_AUTO_EXPORT_ASSETS/BoxFaces001.obj', 'EXPERIMENT_AUTO_EXPORT_ASSETS/BoxFaces001.mtl', function ( object )
// LoadVertexJumbleObject('Assets/Plato_VerticesAndColors002.txt')
}
// ____ _ _ _ _
// / ___|__ _| | | |__ __ _ ___| | _____
// | | / _` | | | '_ \ / _` |/ __| |/ / __|
// | |__| (_| | | | |_) | (_| | (__| <\__ \
// \____\__,_|_|_|_.__/ \__,_|\___|_|\_\___/
function onWindowResize()
{
/*
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
*/
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
var damper = new Damper(2.0, 2000.0);
function onDocumentMouseDown( event )
{
damper.dampen();
damper.pause();
}
function onDocumentMouseUp( event )
{
damper.dampen();
damper.resume();
}
function onDocumentMouseMove( event )
{
}
/*
function onKeyDown(event)
{
switch (event.keyCode)
{
case 37: // Left
log('left')
break;
case 38: // Up
log('up')
break;
case 39: // Right
log('right')
break
case 40: // Down
log('down')
break
}
}
window.addEventListener('keydown', onKeyDown, false)
*/
function PositionCameraOrbitVR()
{
if (!vrmgr.isVRMode())
return;
// 1) Find the camera vector
var cameraVector = new THREE.Vector3( 0, 0, -1 ); // Camera points down -Z by default.
cameraVector.applyQuaternion(camera.quaternion);
// 2) Position the camera along that vector, at fixed distance from the origin
camera.position.copy(cameraVector);
// camera.position.multiplyScalar(-2.5) // TODO Use a constant, this is the same value used below.
camera.position.multiplyScalar(-3) // TODO Use a constant, this is the same value used below.
}
function animate() {
ToggleWebVRInLandscape()
// log("vrmgr.isVRMode(): " + vrmgr.isVRMode())
// log("vrmgr.mode: " + vrmgr.mode)
requestAnimationFrame( animate );
if (vrmgr.isVRMode())
{
// TODO
}
controls = vrmgr.isVRMode() ? controlSchemes[1] : controlSchemes[0];
controls.update();
if (!vrmgr.isVRMode()) {
damper.update();
console.log(damper);
orbitControls.autoRotateSpeed = damper.getValue();
}
PositionCameraOrbitVR()
// ??? If we invert the "Z" (3rd) vector of the matrix, then the camera is pointed in the opposition direction ???
// To do this, negate 3rd entry in identity matrix.
/*
var m = new THREE.Matrix4();
m = m.makeBasis(new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, -1 ))
camera.matrixWorld.applyMatrix4(m)
*/
/*
// var worldNormal = normal.applyMatrix3(normalMatrix).normalize();
var cameraVector = new THREE.Vector3( 0, 0, -1 ); // Camera points down -Z by default.
cameraVector.applyQuaternion(camera.quaternion);
// var ray = new THREE.Raycaster(camera.position, cube.position.clone().sub(camera.position).normalize() );
// NOTE: THIS IS NEEDED FOR VISIBILITY TESTING
camera.updateMatrixWorld()
*/
THREE.AnimationHandler.update( clock.getDelta() );
render();
}
// ___ _ _ _ __ ___ _ _ _ _ _ _ _ _ _
// / _ \| |__ (_) ___ ___| |_ \ \ / (_)___(_) |__ (_) (_) |_ _ _ | | | | ___| |_ __ ___ _ __ ___
// | | | | '_ \| |/ _ \/ __| __| \ \ / /| / __| | '_ \| | | | __| | | | | |_| |/ _ \ | '_ \ / _ \ '__/ __|
// | |_| | |_) | | __/ (__| |_ \ V / | \__ \ | |_) | | | | |_| |_| | | _ | __/ | |_) | __/ | \__ \
// \___/|_.__// |\___|\___|\__| \_/ |_|___/_|_.__/|_|_|_|\__|\__, | |_| |_|\___|_| .__/ \___|_| |___/
// |__/ |___/ |_|
function ShowAll()
{
scene.traverse(function(child)
{
child.visible = true;
});
if (cubeFaceMeshes.length > 0)
{
cubeFaceMeshes[0].parent.visible = false;
cubeFaceMeshes[0].visible = false;
cubeFaceMeshes[1].visible = false;
cubeFaceMeshes[2].visible = false;
cubeFaceMeshes[3].visible = false;
}
}
function HideAllBut(object)
{
scene.traverse(function(child)
{
if ( !(child instanceof THREE.Scene) && !(child instanceof THREE.Light) && !(child instanceof THREE.AmbientLight))
{
child.visible = false;
}
});
object.visible = true;
// TODO Walk up hierarchy.
var current = object.parent;
while (current != undefined && current != current.parent)
{
current.visible = true;
current = current.parent;
}
/*
if (object.parent != undefined)
{
object.parent.visible = true;
}
*/
object.traverse(function(child)
{
child.visible = true; // TODO Fix this workaround!!!
});
// console.log(object);
}
function HideAllButCubeFace(index)
{
if (cubeFaceMeshes.length > 0)
{
HideAllBut(cubeFaceMeshes[index])
}
else
{
// console.error('Cube face not yet defined', index);
}
/*
scene.traverse(function(child)
{
if ( !(child instanceof THREE.Scene) && !(child instanceof THREE.Light))
{
child.visible = false;
}
});
if (cubeFaceMeshes.length > 0)
{
cubeFaceMeshes[0].parent.visible = true;
cubeFaceMeshes[0].visible = false;
cubeFaceMeshes[1].visible = false;
cubeFaceMeshes[2].visible = false;
cubeFaceMeshes[3].visible = false;
cubeFaceMeshes[index].visible = true;
}
*/
}
function HideAllButMesh(index)
{
if (cubeScenes.length > 0 && cubeScenes[index] != undefined)
{
var object = cubeScenes[index];
HideAllBut(object);
/*
object.traverse(function(child)
{
child.visible = true; // TODO Fix this workaround!!!
});
cubeScenes[index].children.map(function(child)
{
child.visible = true; // TODO Fix this workaround!!!
});
*/
// console.log('made visible',cubeScenes[index],cubeScenes[index].children.length)
// if (cubeScenes[index].children.length > 0)
// {
// cubeScenes[index].children[0].visible = true; // TODO Fix this workaround!!!
// }
}
else
{
// console.error('Mesh not yet defined', index);
}
}
/*
Idea:
2 stencil bits:
1. cube face
2. windows
Cube face looks at just first bit
Moon looks at first AND second bit - ANDs them together
stencil op:
* fail action - (GL_KEEP)
* stencil pass & depth test fail action - (GL_KEEP)
* stencil fail & depth test fail action - (GL_KEEP)
stencil func:
* test function - (GL_ALWAYS)
* reference value, 0-255 - (0)
* mask - (0xffffffff) - mask AND'd with both the reference value and the stored stencil value when the test is done.
GL_NOTEQUAL - ( ref & mask ) != ( stencil & mask )
GL_EQUAL - ( ref & mask ) == ( stencil & mask )
*/
/*
*** use GL_KEEP, since we only modify the stencil buffer by explicitly drawing geometry into it
house -- (1 & 1) == (stencil & 1) // only first bit must pass
moon -- (3 & 3) == (stencil & 3) // *both* bits must pass
// Clear stencil buffer
context.StencilOp(context.REPLACE, context.REPLACE, context.REPLACE)
context.stencilFunc(context.ALWAYS, 0, 0xffffffff);
...
// Draw cube face to 1st bit of stencil
context.StencilOp(context.KEEP, context.KEEP, context.KEEP)
context.stencilFunc(context.ALWAYS, 1, 0xffffffff);
...
// Draw windows to 2nd bit of stencil
context.StencilOp(context.KEEP, context.KEEP, context.KEEP)
context.stencilFunc(context.ALWAYS, 2, 0xffffffff);
...
// Draw house scene w/ stencil test for 1st bit of stencil
context.StencilOp(context.KEEP, context.KEEP, context.KEEP)
context.stencilFunc(context.EQUAL, 1, 1);
...
// Draw moon scene
context.StencilOp(context.KEEP, context.KEEP, context.KEEP)
context.stencilFunc(context.EQUAL, 3, 3);
...
*/
// ____ _
// | _ \ ___ _ __ __| | ___ _ __
// | |_) / _ \ '_ \ / _` |/ _ \ '__|
// | _ < __/ | | | (_| | __/ |
// |_| \_\___|_| |_|\__,_|\___|_|
function DoRender(scene, camera, renderTarget, forceClear)
{
// Render the scene through the VREffect, but only if it's in VR mode.
if (vrmgr.isVRMode())
{
// effect.render(scene, camera);
effect.render(scene, camera, renderTarget, forceClear)
}
else
{
renderer.render(scene, camera, renderTarget, forceClear)
}
}
function DrawMoonHouse(firstBitStencilObject, firstBitRenderObject, secondBitStencilObject, secondBitRenderObject)
{
var context = renderer.context
// don't update color or depth
context.colorMask(false, false, false, false)
context.depthMask(false)
// Enable & clear stencil.
context.enable(context.STENCIL_TEST)
context.clearStencil(0)
// Draw cube face into the stencil buffer w/ stencil value = 1.
context.stencilMask(1) // Only write to 1st stencil bit.
//context.depthMask(true) // Write to the depth buffer, so subsequent pass is depth-tested.
context.stencilOp(context.REPLACE, context.REPLACE, context.REPLACE)
context.stencilFunc(context.ALWAYS, 1, 1)
HideAllBut(firstBitStencilObject) // Hide all but the cube face
DoRender(scene, camera, undefined, false)
// Draw windows into the stencil buffer w/ stencil value = 2.
//context.depthMask(false) // Don't write to depth buffer.
// Draw moon house scene to depth buffer, so its depth masks the subsequent render of windows.
//renderer.setDepthTest(true)
context.stencilMask(0)
context.depthMask(true) // Enable write to depth buffer.
context.stencilOp(context.KEEP, context.KEEP, context.KEEP) // Don't modify stencil buffer.
context.stencilFunc(context.EQUAL, 1, 1) // Only draw in the cube face region
HideAllBut(firstBitRenderObject); // Hide all but the moon house scene
// Hide the windows - don't draw them!
secondBitStencilObject.visible = false; secondBitStencilObject.traverse(function(child) {child.visible = false;})
DoRender(scene, camera, undefined, false)
context.depthMask(false) // Disable write to depth buffer.
context.stencilMask(2) // Only write to 2nd stencil bit.
context.depthMask(true) // Enable write to depth buffer.
context.stencilOp(context.KEEP, context.KEEP, context.REPLACE) // Only modify stencil for fragments that pass both stencil & depth tests.
context.stencilFunc(context.ALWAYS, 2, 2)
HideAllBut(secondBitStencilObject); // Hide all but the windows object.
DoRender(scene, camera, undefined, false)
renderer.clear(true, true, false) // Clear color, depth, but not stencil
//context.stencilMask(0xffffffff)
context.stencilMask(0x0)
context.colorMask(true, true, true, true) // Enable write to color buffer.
context.depthMask(true) // Enable write to depth buffer.
// Draw moon scene
context.stencilFunc(context.EQUAL, 3, 0xffffffff) // draw if == 3
context.stencilOp(context.KEEP, context.KEEP, context.KEEP)
HideAllBut(secondBitRenderObject)
DoRender(scene, camera, undefined, false)
// NOTE:
// NOTE:
// NOTE:
// NOTE: Uncomment this line to see how "out-of-the-box" render looks.
//context.disable(context.STENCIL_TEST)
// NOTE:
// NOTE:
// NOTE:
// Draw house scene
// re-enable update of color and depth
// Only render where stencil is set to EXACTLY 1
context.stencilFunc( context.EQUAL, 1, 0xffffffff) // draw if == 1
// context.stencilFunc( context.EQUAL, 1, 0x1) // draw if == 1
context.stencilOp( context.KEEP, context.KEEP, context.KEEP )
HideAllBut(firstBitRenderObject) // Hide all but the moon house scene
// Hide the windows - don't draw them!
secondBitStencilObject.visible = false; secondBitStencilObject.traverse(function(child) {child.visible = false;})
DoRender(scene, camera, undefined, false)
context.stencilMask(0xffffffff)
}
function DrawImpossibleCubeFace(index)
{
var forceClear = false; // ???
var inverse = false; // ???
// Stencil write & clear values.
var writeValue = inverse ? 0 : 1; // "Reference value" for glStencilFunc()
var clearValue = inverse ? 1 : 0; // clear value for glClearStencil()
var context = renderer.context;
// HideAllButCubeFace(index);
// don't update color or depth
context.colorMask(false, false, false, false);
context.depthMask(false);
// Enable stencil.
context.enable(context.STENCIL_TEST);
context.stencilOp(context.REPLACE, context.REPLACE, context.REPLACE);
context.stencilFunc(context.ALWAYS, writeValue, 0xffffffff);
context.clearStencil(clearValue);
// draw into the stencil buffer
// renderer.render( scene, camera, readBuffer, forceClear );
// renderer.render( scene, camera, writeBuffer, forceClear );
DoRender(scene, camera, undefined, forceClear)
// re-enable update of color and depth
context.colorMask(true, true, true, true);
context.depthMask(true);
// only render where stencil is set to 1
context.stencilFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
context.stencilOp( context.KEEP, context.KEEP, context.KEEP );
}
/*
function Initialize(index)
{
if (!initialized[index] && textures[index] != undefined && cubeScenes[index] != undefined)
{
initialized[index] = true;
var object = cubeScenes[index];
object.traverse( function ( child )
{
if ( child instanceof THREE.Mesh )
{
// TODO Need to do this *after* texture has loaded, so setup asset setup in that order !!!
child.material.map = textures[index]; // TODO ???
}
} );
console.log('Initialized',index)
}
}
*/
function IsFaceVisible(cameraVector, object, face)
{
/*
// Transform face from world space to window space.
// Cull if *signed area* is negative.
var normal = face.normal
var cameraNormal = normal.clone().applyMatrix3(camera.matrixWorldInverse).normalize()
*/
// Transform face's normal from local (object) space to world space.
var normal = face.normal.clone();
var normalMatrix = new THREE.Matrix3().getNormalMatrix(object.matrixWorld);
var worldNormal = normal.applyMatrix3(normalMatrix).normalize();
// var normal = face.normal;
var dotProduct = worldNormal.dot(cameraVector)
return dotProduct < 0;
}
function IsCubeFaceVisible(cameraVector, cubeFaceMesh)
{
var faces = cubeFaceMesh.children[1].geometry.faces;
var partiallyApplied_IsFaceVisible = IsFaceVisible.bind(null, cameraVector, cubeFaceMesh);
return faces.some(partiallyApplied_IsFaceVisible );
}
function randomIntFromInterval(min,max)
{
return Math.floor(Math.random()*(max-min+1)+min);
}
// Returns the least-recently-used scene that isn't currently associated with a visible cube face.
var timeStamp = 0 // The incrementing value that scenes are tagged with each time they're "chosen".
function GetHiddenScene()
{
timeStamp += 1
PositionCameraOrbitVR()
var cameraVector = new THREE.Vector3( 0, 0, -1 ); // Camera points down -Z by default.
cameraVector.applyQuaternion(camera.quaternion);
// var visibleScenes = cubeFaceMeshes.filter(function(cubeFaceMesh) { return IsCubeFaceVisible(cameraVector, cubeFaceMesh); })
var visibleScenes = cubeFaceMeshes.filter(function(cubeFaceMesh) { return cubeFaceMesh.isVisible; })
visibleScenes = _.uniq(visibleScenes)
visibleScenes = visibleScenes.map(function(cubeFaceMesh) { return cubeFaceMesh.scene; })
var hiddenScenes = _.difference(cubeScenes, visibleScenes);
if (hiddenScenes.length == 0)
{
console.log('%cERROR!!!','background:red','no unused scenes available!!!',cubeScenes,visibleScenes)
return undefined
}
else
{
var sortedHiddenScenes = _.sortBy(hiddenScenes, function(hiddenScene) { return hiddenScene.timeStamp == undefined ? 0 : hiddenScene.timeStamp; })
var hiddenSceneIndex = randomIntFromInterval(0, sortedHiddenScenes.length-1)
var scene = sortedHiddenScenes[hiddenSceneIndex]
// var scene = _.min(hiddenScenes, function(hiddenScene) { return hiddenScene.timeStamp == undefined ? 0 : hiddenScene.timeStamp; })
// NOTE: The following lines implement uniformly-random-picking.
// var hiddenSceneIndex = randomIntFromInterval(0, hiddenScenes.length-1)
// var scene = hiddenScenes[hiddenSceneIndex]
scene.timeStamp = timeStamp // Tag the scene with the
return scene
}
}
//var cameraRotation = 0;
var moonRotation = 0;
function render()
{
// Initialize(0);
// Initialize(1);
// camera.position.y = 0;
camera.lookAt( scene.position );
// Rotate the scene.
// scene.rotation.y += 0.005;
// cameraRotation += 0.005;
// scene.rotation.y = cameraRotation;
var cameraVector = new THREE.Vector3( 0, 0, -1 ); // Camera points down -Z by default.
cameraVector.applyQuaternion(camera.quaternion);
// var ray = new THREE.Raycaster(camera.position, cube.position.clone().sub(camera.position).normalize() );
// NOTE: THIS IS NEEDED FOR VISIBILITY TESTING
camera.updateMatrixWorld()
controls = vrmgr.isVRMode() ? controlSchemes[1] : controlSchemes[0];
controls.update();
cubeFaceMeshes.map(function(cubeFaceMesh)
{
/*
var isVisible = IsCubeFaceVisible(cameraVector, cubeFaceMesh)
*/
// Get camera location in world space
var result = camera.matrixWorld.applyToVector3Array(new THREE.Vector3(0,0,0))
// var cameraLocation = camera.matrixWorld.applyToVector3Array(new THREE.Vector3(0,0,0))
var cameraLocation = new THREE.Vector3()
cameraLocation.applyMatrix4(camera.matrixWorld) // Get face location in world space
var faceLocation = cubeFaceMesh.localToWorld(cubeFaceMesh.children[1].geometry.vertices[cubeFaceMesh.children[1].geometry.faces[0].a]);
// var faceLocation = cubeFaceMesh.matrixWorld camera.matrixWorld.applyToVector3Array([THREE.Vector3(0,0,0)])[0]
// Form the vector from the face to the camera location, and normalize it.
var cameraToFaceVector = new THREE.Vector3()
cameraToFaceVector.subVectors( faceLocation, cameraLocation )
cameraToFaceVector = cameraToFaceVector.normalize()
// var isVisible = IsCubeFaceVisible(cameraVector, cubeFaceMesh)
var isVisible = IsCubeFaceVisible(cameraToFaceVector, cubeFaceMesh)
cubeFaceMesh.wasVisible = cubeFaceMesh.isVisible; // Use value from last frame.
cubeFaceMesh.isVisible = isVisible;
});
cubeFaceMeshes.map(function(cubeFaceMesh)
{
if (!cubeFaceMesh.wasVisible && cubeFaceMesh.isVisible)
{
// Cube face just became visible, assign an unused scene!
var newScene = GetHiddenScene()
if (newScene == undefined)
console.log('%cERROR','background:red','GetHiddenScene() returned undefined');
else
cubeFaceMesh.scene = newScene;
// Orient scene
// var face1 = mainCubeFaceMesh.children[1].geometry.faces[0]
var face1 = cubeFaceMeshes[4].children[1].geometry.faces[0]
// var faceN = cubeFaceMeshes[n].children[1].geometry.faces[0]
var faceN = cubeFaceMesh.children[1].geometry.faces[0]
var v1 = face1.normal
var vN = faceN.normal
var quaternion = new THREE.Quaternion().setFromUnitVectors( v1, vN );
/*
cubeFaceMesh.scene.matrixAutoUpdate = true
cubeFaceMesh.scene.quaternion = quaternion
// cubeFaceMesh.scene.useQuaternion = true;
// cubeFaceMesh.scene.updateMatrix();
*/
// NOTE: **Do not auto-update (or even manually update) object's matrix** -- b/c that will clobber whatever we set the quaternion to!
cubeFaceMesh.scene.matrixAutoUpdate = false;
cubeFaceMesh.scene.matrix.makeRotationFromQuaternion(quaternion);
// cubeFaceMesh.scene.matrix.setPosition(THREE.Vector3(0,0,0));
if (cubeFaceMesh.scene == sceneFilenameToCubeSceneMap[moonHouseFilename + '.obj'])
{
var moonCubeScene = sceneFilenameToCubeSceneMap['Assets3D/Box - Moon 001.obj']
moonCubeScene.matrixAutoUpdate = false;
moonCubeScene.matrix.makeRotationFromQuaternion(quaternion);
}
/*
var euler = new THREE.Euler()
euler.setFromQuaternion(quaternion, 'XYZ')
// console.log('%c rotate scene', 'background: #00ffff;', quaternion)
console.log('%c rotate scene', 'background: #00ffff;', euler)
*/
}
UpdateSceneViz()
});
renderer.autoClear = false;
renderer.autoClearColor = false;
renderer.autoClearDepth = false;
renderer.autoClearStencil = false;
// Clear color, depth, stencil.
renderer.clear(true, true, true);
// ShowAll();
// HideAllButCubeFace(3);
// // Clear depth.
// renderer.clear(false, true, false);
/*
var cameraVector = new THREE.Vector3( 0, 0, -1 ); // Camera points down -Z by default.
cameraVector.applyQuaternion(camera.quaternion);
*/
// var visibleScenes = cubeFaceMeshes.filter(function(cubeFaceMesh) { return IsCubeFaceVisible(cameraVector, cubeFaceMesh); })
var visibleCubeFaceMeshes = _.uniq(cubeFaceMeshes.filter(function(cubeFaceMesh) { return cubeFaceMesh.isVisible; }))
visibleCubeFaceMeshes.map(function(visibleCubeFaceMesh)
{
var i = cubeFaceMeshes.indexOf(visibleCubeFaceMesh)
// Clear depth & stencil.
renderer.clear(false, true, true);
if (visibleCubeFaceMesh.scene == sceneFilenameToCubeSceneMap[moonHouseFilename + '.obj'])
{
var moonCubeScene = sceneFilenameToCubeSceneMap['Assets3D/Box - Moon 001.obj']
var windowsObject
scene.traverse( function ( child )
{
if (child.name.indexOf('__WINDOWS__') > -1)
{
windowsObject = child
}
});
moonRotation -= 0.001;
scene.getObjectByName('__THE_MOON___Icosphere.001').children[1].position.set(-3,0.25,-0.5);
scene.getObjectByName('__THE_MOON___Icosphere.001').children[1].scale.set(2,2,2);
scene.getObjectByName('__THE_MOON___Icosphere.001').children[1].rotation.y = moonRotation;
scene.getObjectByName('__THE_MOON___Icosphere.001').children[1].updateMatrix();
/*
sceneFilenameToCubeSceneMap['Assets3D/Box - Moon 001.obj'].rotation.y = moonRotation;
sceneFilenameToCubeSceneMap['Assets3D/Box - Moon 001.obj'].updateMatrix();
*/
DrawMoonHouse(visibleCubeFaceMesh, visibleCubeFaceMesh.scene, windowsObject, moonCubeScene) // firstBitStencilObject, firstBitRenderObject, secondBitStencilObject, secondBitRenderObject
// console.log('%cFOUND','background:yellow')
/*
// (1) render cube face to stencil
HideAllButCubeFace(i)
DrawImpossibleCubeFace(i)
*/
/*
// TODO:
// (2) AND windows to stencil
// (3) render moon scene to color, depth
HideAllButMesh(sceneFilenameToCubeSceneMap['Assets3D/Box - Moon 001.obj'])
renderer.render(scene, camera)
*/
}
// else if (visibleCubeFaceMesh.scene == sceneFilenameToCubeSceneMap[caveFilename + '.obj'])
// {
// }
else
{
HideAllButCubeFace(i);
DrawImpossibleCubeFace(i);
HideAllButMesh(cubeScenes.indexOf(visibleCubeFaceMesh.scene));
DoRender(scene, camera)
}
})
/*
// MOST RECENT WORKING VERSION !!!!!
var i = 0;
cubeScenes.map(function(object)
{
// Clear depth & stencil.
renderer.clear(false, true, true);
HideAllButCubeFace(i);
DrawImpossibleCubeFace(i);
HideAllButMesh(i);
renderer.render(scene, camera);
i += 1;
});
*/
/*
// Stencil each face, then draw the corresponding scene.
HideAllButCubeFace(3);
DrawImpossibleCubeFace(3);
HideAllButMesh(1);
renderer.render(scene, camera);
renderer.clear(false, true, true);
HideAllButCubeFace(0);
DrawImpossibleCubeFace(0);
HideAllButMesh(0);
renderer.render(scene, camera);
renderer.clear(false, true, true);
HideAllButCubeFace(2);
DrawImpossibleCubeFace(2);
HideAllButMesh(2);
renderer.render(scene, camera);
*/
/*
HideAllButMesh(0);
renderer.render(scene, camera);
*/
}