// TODO Should not derived from mesh?
import Mesh from '../Mesh';
import CubeGeometry from '../geometry/Cube';
import Shader from '../Shader';
import Material from '../Material';
import Texture from '../Texture';
import PerspectiveCamera from '../camera/Perspective';
import Matrix4 from '../math/Matrix4';
import skyboxEssl from '../shader/source/skybox.glsl.js';
Shader.import(skyboxEssl);
/**
* @constructor clay.plugin.Skybox
*
* @example
* var skyTex = new clay.TextureCube();
* skyTex.load({
* 'px': 'assets/textures/sky/px.jpg',
* 'nx': 'assets/textures/sky/nx.jpg'
* 'py': 'assets/textures/sky/py.jpg'
* 'ny': 'assets/textures/sky/ny.jpg'
* 'pz': 'assets/textures/sky/pz.jpg'
* 'nz': 'assets/textures/sky/nz.jpg'
* });
* var skybox = new clay.plugin.Skybox({
* scene: scene
* });
* skybox.material.set('environmentMap', skyTex);
*/
var Skybox = Mesh.extend(function () {
var skyboxShader = new Shader({
vertex: Shader.source('clay.skybox.vertex'),
fragment: Shader.source('clay.skybox.fragment')
});
var material = new Material({
shader: skyboxShader,
depthMask: false
});
return {
/**
* @type {clay.Scene}
* @memberOf clay.plugin.Skybox.prototype
*/
scene: null,
geometry: new CubeGeometry(),
material: material,
environmentMap: null,
culling: false,
_dummyCamera: new PerspectiveCamera()
};
}, function () {
var scene = this.scene;
if (scene) {
this.attachScene(scene);
}
if (this.environmentMap) {
this.setEnvironmentMap(this.environmentMap);
}
}, /** @lends clay.plugin.Skybox# */ {
/**
* Attach the skybox to the scene
* @param {clay.Scene} scene
*/
attachScene: function (scene) {
if (this.scene) {
this.detachScene();
}
scene.skybox = this;
this.scene = scene;
scene.on('beforerender', this._beforeRenderScene, this);
},
/**
* Detach from scene
*/
detachScene: function () {
if (this.scene) {
this.scene.off('beforerender', this._beforeRenderScene);
this.scene.skybox = null;
}
this.scene = null;
},
/**
* Dispose skybox
* @param {clay.Renderer} renderer
*/
dispose: function (renderer) {
this.detachScene();
this.geometry.dispose(renderer);
},
/**
* Set environment map
* @param {clay.TextureCube} envMap
*/
setEnvironmentMap: function (envMap) {
if (envMap.textureType === 'texture2D') {
this.material.define('EQUIRECTANGULAR');
// LINEAR filter can remove the artifacts in pole
envMap.minFilter = Texture.LINEAR;
}
else {
this.material.undefine('EQUIRECTANGULAR');
}
this.material.set('environmentMap', envMap);
},
/**
* Get environment map
* @return {clay.TextureCube}
*/
getEnvironmentMap: function () {
return this.material.get('environmentMap');
},
_beforeRenderScene: function(renderer, scene, camera) {
this.renderSkybox(renderer, camera);
},
renderSkybox: function (renderer, camera) {
var dummyCamera = this._dummyCamera;
dummyCamera.aspect = renderer.getViewportAspect();
dummyCamera.fov = camera.fov || 50;
dummyCamera.updateProjectionMatrix();
Matrix4.invert(dummyCamera.invProjectionMatrix, dummyCamera.projectionMatrix);
dummyCamera.worldTransform.copy(camera.worldTransform);
dummyCamera.viewMatrix.copy(camera.viewMatrix);
this.position.copy(camera.getWorldPosition());
this.update();
// Don't remember to disable blend
renderer.gl.disable(renderer.gl.BLEND);
if (this.material.get('lod') > 0) {
this.material.define('fragment', 'LOD');
}
else {
this.material.undefine('fragment', 'LOD');
}
renderer.renderPass([this], dummyCamera);
}
});
export default Skybox;