elation-engine
Version:
WebGL/WebVR engine written in Javascript
193 lines (135 loc) • 4.77 kB
JavaScript
;(function() {
"use strict";
var root = this
var has_require = typeof require !== 'undefined'
var THREE = root.THREE || has_require && require('three')
if( !THREE )
throw new Error( 'CubemapToEquirectangular requires three.js' )
var vertexShader = [
"attribute vec3 position; ",
"attribute vec2 uv; ",
"uniform mat4 projectionMatrix; ",
"uniform mat4 modelViewMatrix; ",
"varying vec2 vUv; ",
"void main() { ",
" vUv = vec2( 1.- uv.x, uv.y ); ",
" gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); ",
"} ",
].join('\n');
var fragmentShader = [
"precision mediump float; ",
"uniform samplerCube map; ",
"varying vec2 vUv; ",
"#define M_PI 3.1415926535897932384626433832795 ",
"void main() { ",
" vec2 uv = vUv; ",
" float longitude = uv.x * 2. * M_PI - M_PI + M_PI / 2.; ",
" float latitude = uv.y * M_PI; ",
" vec3 dir = vec3( ",
" - sin( longitude ) * sin( latitude ), ",
" cos( latitude ), ",
" - cos( longitude ) * sin( latitude ) ",
" ); ",
" normalize( dir ); ",
" gl_FragColor = vec4( textureCube( map, dir ).rgb, 1. ); ",
"} ",
].join('\n');
function CubemapToEquirectangular( renderer, provideCubeCamera ) {
this.width = 1;
this.height = 1;
this.renderer = renderer;
this.material = new THREE.RawShaderMaterial( {
uniforms: {
map: { type: 't', value: null }
},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
side: THREE.DoubleSide
} );
this.scene = new THREE.Scene();
this.quad = new THREE.Mesh(
new THREE.PlaneGeometry( 1, 1 ),
this.material
);
this.scene.add( this.quad );
this.camera = new THREE.OrthographicCamera( 1 / - 2, 1 / 2, 1 / 2, 1 / - 2, -10000, 10000 );
this.canvas = document.createElement( 'canvas' );
this.ctx = this.canvas.getContext( '2d' );
this.cubeCamera = null;
this.attachedCamera = null;
this.setSize( 4096, 2048 );
var gl = this.renderer.getContext();
this.cubeMapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE )
if( provideCubeCamera ) {
this.getCubeCamera( 2048 )
}
}
CubemapToEquirectangular.prototype.setSize = function( width, height ) {
this.width = width;
this.height = height;
this.quad.scale.set( this.width, this.height, 1 );
this.camera.left = this.width / - 2;
this.camera.right = this.width / 2;
this.camera.top = this.height / 2;
this.camera.bottom = this.height / - 2;
this.camera.updateProjectionMatrix();
this.output = new THREE.WebGLRenderTarget( this.width, this.height, {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
wrapS: THREE.ClampToEdgeWrapping,
wrapT: THREE.ClampToEdgeWrapping,
format: THREE.RGBAFormat,
type: THREE.UnsignedByteType
});
this.canvas.width = this.width;
this.canvas.height = this.height;
}
CubemapToEquirectangular.prototype.getCubeCamera = function( size ) {
this.cubeCamera = new THREE.CubeCamera( .1, 1000, Math.min( this.cubeMapSize, size ) );
return this.cubeCamera;
}
CubemapToEquirectangular.prototype.attachCubeCamera = function( camera ) {
this.getCubeCamera();
this.attachedCamera = camera;
}
CubemapToEquirectangular.prototype.convert = function( cubeCamera, type ) {
this.quad.material.uniforms.map.value = cubeCamera.renderTarget.texture;
let prevRenderTarget = this.renderer.getRenderTarget();
this.renderer.setRenderTarget(this.output);
this.renderer.clear();
this.renderer.render( this.scene, this.camera);
this.renderer.setRenderTarget(prevRenderTarget);
var pixels = new Uint8Array( 4 * this.width * this.height );
this.renderer.readRenderTargetPixels( this.output, 0, 0, this.width, this.height, pixels );
var imageData = new ImageData( new Uint8ClampedArray( pixels ), this.width, this.height );
this.ctx.putImageData( imageData, 0, 0 );
var type = type || 'image/png';
var promise = new Promise(function(resolve, reject) {
/*
this.canvas.toBlob( function( blob ) {
var url = URL.createObjectURL(blob);
}, type );
*/
var base64 = this.canvas.toDataURL(type);
resolve(base64);
}.bind(this));
return promise;
}
CubemapToEquirectangular.prototype.update = function( camera, scene ) {
var autoClear = this.renderer.autoClear;
this.renderer.autoClear = true;
this.cubeCamera.position.copy( camera.position );
this.cubeCamera.updateCubeMap( this.renderer, scene );
this.renderer.autoClear = autoClear;
this.convert( this.cubeCamera );
}
if( typeof exports !== 'undefined' ) {
if( typeof module !== 'undefined' && module.exports ) {
exports = module.exports = CubemapToEquirectangular
}
exports.CubemapToEquirectangular = CubemapToEquirectangular
}
else {
root.CubemapToEquirectangular = CubemapToEquirectangular
}
}).call(this);