/**
* Skybox allows to render a cubemap or polar image as a background for the 3D scene
* @class Skybox
* @namespace LS.Components
* @constructor
* @param {Object} object [optional] to configure from
*/
function Skybox(o)
{
this.enabled = true;
this.texture = null;
this.material = null;
this._intensity = 1;
this.use_environment = true;
this.gamma = false;
this._bake_to_cubemap = false;
if(o)
this.configure(o);
}
Skybox.icon = "mini-icon-dome.png";
//vars
Skybox["@material"] = { type: LS.TYPES.MATERIAL };
Skybox["@texture"] = { type: LS.TYPES.TEXTURE };
Skybox.prototype.onAddedToNode = function(node)
{
LEvent.bind(node, "collectRenderInstances", this.onCollectInstances, this);
}
Skybox.prototype.onRemovedFromNode = function(node)
{
LEvent.unbind(node, "collectRenderInstances", this.onCollectInstances, this);
}
Skybox.prototype.onAddedToScene = function(scene)
{
LEvent.bind(scene, "start", this.onStart, this);
}
Skybox.prototype.onRemovedFromScene = function(scene)
{
LEvent.unbind(scene, "start", this.onStart, this);
}
Object.defineProperty( Skybox.prototype, "intensity", {
set: function(v){
this._intensity = v;
if(this._material)
this._material._color.set([v,v,v,1]);
},
get: function()
{
return this._intensity;
},
enumerable: true
});
Object.defineProperty( Skybox.prototype, "bake_to_cubemap", {
set: function(v){
this._bake_to_cubemap = v;
if(v)
this.bakeToCubemap();
},
get: function()
{
return this._bake_to_cubemap;
},
enumerable: true
});
Skybox.prototype.getResources = function(res)
{
if(this.texture && this.texture.constructor === String)
res[this.texture] = GL.Texture;
if(this.material && this.material.constructor === String)
res[this.material] = LS.Material;
return res;
}
Skybox.prototype.onResourceRenamed = function (old_name, new_name, resource)
{
if(this.texture == old_name)
this.texture = new_name;
}
Skybox.prototype.onCollectInstances = function(e, instances)
{
if(!this._root || !this.enabled)
return;
var mesh = this._mesh;
if(!mesh)
mesh = this._mesh = GL.Mesh.cube({size: 10});
var node = this._root;
var RI = this._render_instance;
if(!RI)
{
this._render_instance = RI = new LS.RenderInstance(this._root, this);
RI.priority = 100;
//to position the skybox on top of the camera
RI.onPreRender = function(render_settings) {
var camera = LS.Renderer._current_camera;
var cam_pos = camera.getEye();
mat4.identity(this.matrix);
mat4.setTranslation( this.matrix, cam_pos );
var size = (camera.near + camera.far) * 0.5;
//mat4.scale( this.matrix, this.matrix, [ size, size, size ]);
if(this.node.transform)
{
var R = this.node.transform.getGlobalRotationMatrix();
mat4.multiply( this.matrix, this.matrix, R );
}
//this.updateAABB(); this node doesnt have AABB (its always visible)
vec3.copy( this.center, cam_pos );
};
}
var mat = null;
if(this.material)
{
mat = LS.ResourcesManager.getResource( this.material );
}
else
{
var texture_name = null;
if (this.use_environment && LS.Renderer._current_scene.info )
texture_name = LS.Renderer._current_scene.info.textures["environment"];
else
texture_name = this.texture;
if(!texture_name)
return;
var texture = LS.ResourcesManager.textures[ texture_name ];
if(!texture)
return;
mat = this._material;
if(!mat)
{
mat = this._material = new LS.ShaderMaterial({
flags: {
two_sided: true,
cast_shadows: false,
receive_shadows: false,
ignore_frustum: true,
ignore_lights: true,
depth_test: false
},
use_scene_ambient:false,
color: [ this.intensity, this.intensity, this.intensity ]
});
mat.shader_code = new LS.ShaderCode( Skybox.shader_code );
}
else
mat.color.set([this.intensity, this.intensity, this.intensity]);
mat.setProperty( "Texture", texture_name );
/*
var sampler = mat.setTexture( LS.Material.COLOR, texture_name );
//sampler.gamma = this.gamma;
if(texture && texture.texture_type == gl.TEXTURE_2D)
{
sampler.uvs = "polar_vertex";
texture.bind(0);
texture.setParameter( gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); //to avoid going up
texture.setParameter( gl.TEXTURE_MIN_FILTER, gl.LINEAR ); //avoid ugly error in atan2 edges
}
else
sampler.uvs = "0";
*/
}
RI.setMesh( mesh );
RI.setMaterial( mat );
instances.push(RI);
//if we have a material we can bake and it has changed...
if( this.material && mat && this._bake_to_cubemap && (this._prev_mat != mat || this._mat_version != mat.version ) )
{
this._prev_mat = mat;
this._mat_version = mat.version;
this.bakeToCubemap();
}
}
Skybox.prototype.onStart = function(e)
{
if( this._bake_to_cubemap )
this.bakeToCubemap();
}
Skybox.prototype.bakeToCubemap = function( size, render_settings )
{
var that = this;
size = size || 512;
render_settings = render_settings || new LS.RenderSettings();
if( !this.root || !this.root.scene )
return;
var scene = this.root.scene;
if( !this._render_instance || !this._render_instance.material ) //generate the skybox render instance
{
//wait till we have the material loaded
setTimeout( function(){ that.bakeToCubemap.bind( that ); },500 );
return;
}
//this will ensure the materials and instances are in the queues
var instances = [];
this.onCollectInstances(null, instances);
LS.Renderer.processVisibleData( scene, render_settings, null, instances, true );
render_settings.render_helpers = false;
this._baked_texture = LS.Renderer.renderToCubemap( vec3.create(), size, this._baked_texture, render_settings, 0.001, 100, vec4.create(), instances);
LS.ResourcesManager.registerResource( ":baked_skybox", this._baked_texture );
if( this.root.scene.info )
this.root.scene.info.textures[ "environment" ] = ":baked_skybox";
}
Skybox.shader_code = "\n\
\\js\n\
this.createSampler(\"Texture\",\"u_color_texture\", { magFilter: GL.LINEAR, missing: \"white\"} );\n\
this.queue = LS.RenderQueue.BACKGROUND;\n\
this.render_state.cull_face = false;\n\
this.render_state.front_face = GL.CW;\n\
this.render_state.depth_test = false;\n\
this.render_state.front_face = GL.CW;\n\
this.flags.ignore_frustum = true;\n\
this.flags.ignore_lights = true;\n\
this.flags.cast_shadows = false;\n\
this.flags.receive_shadows = false;\n\
\n\
\\color.vs\n\
precision mediump float;\n\
attribute vec3 a_vertex;\n\
varying vec3 v_world_position;\n\
uniform mat4 u_model;\n\
uniform mat4 u_viewprojection;\n\
void main() {\n\
vec4 vertex4 = u_model * vec4(a_vertex,1.0);\n\
v_world_position = vertex4.xyz;\n\
gl_Position = u_viewprojection * vertex4;\n\
}\n\
\\color.fs\n\
precision mediump float;\n\
varying vec3 v_world_position;\n\
uniform vec4 u_material_color;\n\
uniform vec3 u_camera_eye;\n\
uniform samplerCube u_color_texture;\n\
vec2 polarToCartesian(in vec3 V)\n\
{\n\
return vec2( 0.5 - (atan(V.z, V.x) / -6.28318531), asin(V.y) / 1.57079633 * 0.5 + 0.5);\n\
}\n\
void main() {\n\
vec3 E = normalize( v_world_position - u_camera_eye);\n\
vec4 color = textureCube( u_color_texture, E );\n\
gl_FragColor = u_material_color * color;\n\
}\n\
\\picking.vs\n\
precision mediump float;\n\
attribute vec3 a_vertex;\n\
uniform mat4 u_model;\n\
uniform mat4 u_viewprojection;\n\
void main() {\n\
vec4 vertex4 = vec4(a_vertex,1.0);\n\
gl_Position = (u_viewprojection * u_model) * vertex4;\n\
}\n\
\\picking.fs\n\
precision mediump float;\n\
uniform vec4 u_material_color;\n\
void main() {\n\
gl_FragColor = u_material_color;\n\
}\n\
";
LS.registerComponent(Skybox);
LS.Skybox = Skybox;