/**
* This Material renders a georeferenced texture on a mesh without using textureCoordinates, but realWorldCoordinates of each fragment(pixel).
*
* @namespace GIScene
* @class RasterOverlayMaterial
* @constructor
* @param {Object} config an Object with config properties
* @example
* rasterOverlayMaterial = new GIScene.RasterOverlayMaterial({
lowerLeft: new GIScene.Coordinate2(llX, llY), //the lower left coordinate of the image boundingBox
upperRight: new GIScene.Coordinate2(urX, urY), //the upper right coordinate of the image boundingBox
offset2: new GIScene.Coordinate2(offsetX,offsetY), //optional
url:"http://www.example.com/rasterimage.jpg",
crossOrigin:"anonymous"
// texture: texture //instead of url you can also pass an existing texture
});
*
*/
GIScene.RasterOverlayMaterial = function(config) {
//config-options:
//url or texture
//crossOrigin default "anonymous" || "use-credentials"
//lowerLeft (compute BBOX)
//upperRight (compute BBOX)--> no offset needed
//??? sceneOffset or LayerOffset??? translate??
var defaults = {
texture: null,
url: null,
crossOrigin : "anonymous",
lowerLeft : new GIScene.Coordinate2(-100,-100), //GIScene.Coordinate2
upperRight: new GIScene.Coordinate2(100,100), //GIScene.Coordinate2
offset2: null, //GIScene.Coordinate2
isShared:true, //if object will be disosed do not dispose material and its textures
//standards
emissive : new THREE.Color(0x000000)
};
/**
* The config which is used to initialize the RasterOverlayMaterial. Merged from defaults and passed config Object.
*
* @property config
* @type Object
*/
this.config = GIScene.Utils.mergeObjects(defaults, config || {});
//@TODO convert geo coordinates into system coordinates inclusive substraction of offset
// var offset = (offset) ? offset : new THREE.Vector2(0,0);
// var lowerLeft = lowerLeft.sub(offset) || new THREE.Vector2(-100,-100);
// var upperRight = upperRight.sub(offset) || new THREE.Vector2(100,100);
this.url = this.config.url;
this.crossOrigin = this.config.crossOrigin;
this.offset2 = (this.config.offset2) ? this.config.offset2 : new GIScene.Coordinate2(0,0);
this.lowerLeft = this.config.lowerLeft.sub(this.offset2) || new GIScene.Coordinate2(-100,-100);
this.upperRight = this.config.upperRight.sub(this.offset2) || new GIScene.Coordinate2(100,100);
this.texture = this.config.texture || new THREE.Texture();
this.isShared = this.config.isShared;
//standards
var em = this.config.emissive;
Object.defineProperty(this, 'emissive', {
get: function() {
console.log('get! emissive');
return em;
},
set: function(value) {
em = value;
this.uniforms.emissive.value = value;
}
});
if (this.url){
this.setTextureFromUrl(this.url, this.crossOrigin);
}
var parameters = {
transparent:true,
lights: true,
side:0,
shading: THREE.SmoothShading,
uniforms: THREE.UniformsUtils.merge( [
THREE.UniformsLib[ "common" ],
THREE.UniformsLib[ "fog" ],
THREE.UniformsLib[ "lights" ],
THREE.UniformsLib[ "shadowmap" ],
{
"diffuse" : { type: "c", value: new THREE.Color( 0x36421E ) },
"ambient" : { type: "c", value: new THREE.Color( 0x36421E ) },
"emissive" : { type: "c", value: this.emissive/*new THREE.Color( 0x000000 ) */},
"wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) },
// "mNear": { type: "f", value: near },
// "mFar" : { type: "f", value: far }
"tOverlay" : { type: "t", value : this.texture},
"lowerLeft" : { type: "v2", value : this.lowerLeft},
"upperRight" : { type: "v2", value : this.upperRight}
}
] ),
vertexShader: [
"varying vec3 vWorldPosition;",
"#define LAMBERT",
"varying vec3 vLightFront;",
"varying vec3 vLightingOnly;",//mca
"#ifdef DOUBLE_SIDED",
"varying vec3 vLightBack;",
"#endif",
THREE.ShaderChunk[ "map_pars_vertex" ],
THREE.ShaderChunk[ "lightmap_pars_vertex" ],
THREE.ShaderChunk[ "envmap_pars_vertex" ],
THREE.ShaderChunk[ "lights_lambert_pars_vertex" ],
THREE.ShaderChunk[ "color_pars_vertex" ],
THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
THREE.ShaderChunk[ "skinning_pars_vertex" ],
THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
"void main() {",
THREE.ShaderChunk[ "map_vertex" ],
THREE.ShaderChunk[ "lightmap_vertex" ],
THREE.ShaderChunk[ "color_vertex" ],
THREE.ShaderChunk[ "morphnormal_vertex" ],
THREE.ShaderChunk[ "skinbase_vertex" ],
THREE.ShaderChunk[ "skinnormal_vertex" ],
THREE.ShaderChunk[ "defaultnormal_vertex" ],
THREE.ShaderChunk[ "morphtarget_vertex" ],
THREE.ShaderChunk[ "skinning_vertex" ],
THREE.ShaderChunk[ "default_vertex" ],
THREE.ShaderChunk[ "worldpos_vertex" ],
THREE.ShaderChunk[ "envmap_vertex" ],
//mca THREE.ShaderChunk[ "lights_lambert_vertex" ],
"vLightFront = vec3( 0.0 );",
"#ifdef DOUBLE_SIDED",
"vLightBack = vec3( 0.0 );",
"#endif",
"transformedNormal = normalize( transformedNormal );",
"#if MAX_DIR_LIGHTS > 0",
"for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {",
"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
"vec3 dirVector = normalize( lDirection.xyz );",
"float dotProduct = dot( transformedNormal, dirVector );",
"vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );",
"#ifdef DOUBLE_SIDED",
"vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
"#ifdef WRAP_AROUND",
"vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
"#endif",
"#endif",
"#ifdef WRAP_AROUND",
"vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
"directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );",
"#ifdef DOUBLE_SIDED",
"directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );",
"#endif",
"#endif",
"vLightFront += directionalLightColor[ i ] * directionalLightWeighting;",
"#ifdef DOUBLE_SIDED",
"vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;",
"#endif",
"}",
"#endif",
"#if MAX_POINT_LIGHTS > 0",
"for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
"float lDistance = 1.0;",
"if ( pointLightDistance[ i ] > 0.0 )",
"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
"lVector = normalize( lVector );",
"float dotProduct = dot( transformedNormal, lVector );",
"vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );",
"#ifdef DOUBLE_SIDED",
"vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
"#ifdef WRAP_AROUND",
"vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
"#endif",
"#endif",
"#ifdef WRAP_AROUND",
"vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
"pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );",
"#ifdef DOUBLE_SIDED",
"pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );",
"#endif",
"#endif",
"vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;",
"#ifdef DOUBLE_SIDED",
"vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;",
"#endif",
"}",
"#endif",
"#if MAX_SPOT_LIGHTS > 0",
"for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
"vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
"float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );",
"if ( spotEffect > spotLightAngleCos[ i ] ) {",
"spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );",
"float lDistance = 1.0;",
"if ( spotLightDistance[ i ] > 0.0 )",
"lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );",
"lVector = normalize( lVector );",
"float dotProduct = dot( transformedNormal, lVector );",
"vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );",
"#ifdef DOUBLE_SIDED",
"vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
"#ifdef WRAP_AROUND",
"vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
"#endif",
"#endif",
"#ifdef WRAP_AROUND",
"vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
"spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );",
"#ifdef DOUBLE_SIDED",
"spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );",
"#endif",
"#endif",
"vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;",
"#ifdef DOUBLE_SIDED",
"vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;",
"#endif",
"}",
"}",
"#endif",
"#if MAX_HEMI_LIGHTS > 0",
"for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
"vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
"vec3 lVector = normalize( lDirection.xyz );",
"float dotProduct = dot( transformedNormal, lVector );",
"float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
"float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;",
"vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
"#ifdef DOUBLE_SIDED",
"vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );",
"#endif",
"}",
"#endif",
"vLightingOnly = vLightFront;", //mca
"vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;",
"#ifdef DOUBLE_SIDED",
"vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;",
"#endif",
THREE.ShaderChunk[ "shadowmap_vertex" ],
"vWorldPosition = worldPosition.xyz;",
"}"
].join("\n"),
fragmentShader: [
//mca
// "uniform float mNear;",
// "uniform float mFar;",
"varying vec3 vWorldPosition;",
"uniform vec2 lowerLeft;",
"uniform vec2 upperRight;",
"uniform sampler2D tOverlay;",
"uniform vec3 ambient;",
"uniform vec3 diffuse;",
"uniform vec3 emissive;",
"uniform vec3 ambientLightColor;",
"uniform float opacity;",
"varying vec3 vLightFront;",
"varying vec3 vLightingOnly;",//mca
"#ifdef DOUBLE_SIDED",
"varying vec3 vLightBack;",
"#endif",
THREE.ShaderChunk[ "color_pars_fragment" ],
THREE.ShaderChunk[ "map_pars_fragment" ],
THREE.ShaderChunk[ "lightmap_pars_fragment" ],
THREE.ShaderChunk[ "envmap_pars_fragment" ],
THREE.ShaderChunk[ "fog_pars_fragment" ],
THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
THREE.ShaderChunk[ "specularmap_pars_fragment" ],
"void main() {",
"gl_FragColor = vec4( vec3 ( 1.0 ), opacity );",
THREE.ShaderChunk[ "map_fragment" ],
// "if(vWorldPosition.x >= lowerLeft.x && vWorldPosition.x <= upperRight.x && -vWorldPosition.z >= lowerLeft.y && -vWorldPosition.z <= upperRight.y)",
// "{",
// "vec2 worldPosGeo = vec2(vWorldPosition.x, -vWorldPosition.z);",
// "vec4 tColor = texture2D(tOverlay, (worldPosGeo-lowerLeft) / (upperRight - lowerLeft));",
// // use emissive for selection, don't subtract it "gl_FragColor = mix(gl_FragColor,vec4(((gl_FragColor.rgb - emissive - (ambient * ambientLightColor) )/diffuse) * tColor.rgb, opacity ),tColor.a) ;",
// "gl_FragColor = mix(gl_FragColor,vec4((((gl_FragColor.rgb - emissive - (ambient * ambientLightColor) )/diffuse) +emissive)* tColor.rgb, opacity ),tColor.a) ;",
//
// //new test
//
// // "gl_FragColor = mix(vec4(1.0),tColor, tColor.a);",
//
// "}",
THREE.ShaderChunk[ "alphatest_fragment" ],
THREE.ShaderChunk[ "specularmap_fragment" ],
"#ifdef DOUBLE_SIDED",
//"float isFront = float( gl_FrontFacing );",
//"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;",
"if ( gl_FrontFacing )",
"gl_FragColor.xyz *= vLightFront;",
"else",
"gl_FragColor.xyz *= vLightBack;",
"#else",
"gl_FragColor.xyz *= vLightFront;",
"#endif",
THREE.ShaderChunk[ "lightmap_fragment" ],
//this was ShaderChunk color_fragment
"#ifdef USE_COLOR",
"gl_FragColor = gl_FragColor * vec4( vColor, opacity );",
"#endif",
THREE.ShaderChunk[ "envmap_fragment" ],
THREE.ShaderChunk[ "shadowmap_fragment" ],
THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
THREE.ShaderChunk[ "fog_fragment" ],
//mca
// "float depth_ = gl_FragCoord.z / gl_FragCoord.w;",
// "float distOpacity = smoothstep( mNear, mFar, depth_ );",
// "gl_FragColor = vec4( gl_FragColor.rgb, distOpacity );",
// "if (distOpacity < 0.01) discard;", //depthBuffer will not be written
"if(vWorldPosition.x >= lowerLeft.x && vWorldPosition.x <= upperRight.x && -vWorldPosition.z >= lowerLeft.y && -vWorldPosition.z <= upperRight.y)",
"{",
"vec2 worldPosGeo = vec2(vWorldPosition.x, -vWorldPosition.z);",
"vec4 tColor = texture2D(tOverlay, (worldPosGeo-lowerLeft) / (upperRight - lowerLeft));",
// use emissive for selection, don't subtract it "gl_FragColor = mix(gl_FragColor,vec4(((gl_FragColor.rgb - emissive - (ambient * ambientLightColor) )/diffuse) * tColor.rgb, opacity ),tColor.a) ;",
//"gl_FragColor = mix(gl_FragColor,vec4(((gl_FragColor.rgb - (ambient * ambientLightColor) )/diffuse) * tColor.rgb, opacity ),tColor.a) ;",
//new test
//"gl_FragColor = mix(vec4(vec3(1.0),opacity),vec4(tColor.rgb* (((vLightFront-emissive-(ambient * ambientLightColor))/diffuse)+emissive), opacity), tColor.a);",
//"gl_FragColor = mix(gl_FragColor,vec4(tColor.rgb* (((vLightFront-emissive-(ambient * ambientLightColor))/diffuse)+emissive+ambientLightColor), opacity), tColor.a);",
//"gl_FragColor = mix(gl_FragColor,vec4(tColor.rgb* (((vLightFront-emissive-(ambient * ambientLightColor)))+emissive+ambientLightColor), opacity), tColor.a);",
//"gl_FragColor = mix(gl_FragColor,vec4(tColor.rgb* (((vLightFront-emissive-(ambient * ambientLightColor)) / diffuse)+emissive+ambientLightColor), opacity), tColor.a);",
"gl_FragColor = mix(gl_FragColor,vec4(tColor.rgb * (vLightingOnly + ambientLightColor + emissive), opacity), tColor.a);",
"}",
"}"
].join("\n")
};
THREE.ShaderMaterial.call(this, parameters);
};
GIScene.RasterOverlayMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
/**
* Sets the upper right corner coordinate of the bounding box which georeferences the texture
* @method setUpperRight
* @param {GIScene.Coordinate2} coord2 Coordinate in CRS units
*/
GIScene.RasterOverlayMaterial.prototype.setUpperRight = function(coord2) {
this.upperRight = coord2.sub(this.offset2);
this.uniforms.upperRight.value = this.upperRight;
};
/**
* Sets the lower left corner coordinate of the bounding box which georeferences the texture
* @method setLowerLeft
* @param {GIScene.Coordinate2} coord2 Coordinate in CRS units
*/
GIScene.RasterOverlayMaterial.prototype.setLowerLeft = function(coord2) {
this.lowerLeft = coord2.sub(this.offset2);
this.uniforms.lowerLeft.value = this.lowerLeft;
};
/**
* Sets a raster image as overlay texture
* @method setTexture
* @param {THREE.Texture} texture
*/
GIScene.RasterOverlayMaterial.prototype.setTexture = function(texture) {
this.texture = this.uniforms.tOverlay.value = texture;
/**
*@event settexture fires after a new texture has been set to the material
*/
this.dispatchEvent({type:"settexture", content:{texture:texture}});
};
/**
* asyncronously loads and attaches a texture by specifiing a url to an image and optionally updates the material uniforms (lowerLeft and upperRight)
*
* @method setTextureFromUrl
* @param {String} url
* @param {String} crossOrigin either "anonymous" or "use-credentials"
* @param {Function} callback function after texture has been loaded and attached to material
*/
GIScene.RasterOverlayMaterial.prototype.setTextureFromUrl = function(url, crossOrigin, onSetTexture) {
this.crossOrigin = (crossOrigin)? crossOrigin : this.crossOrigin;
this.url = url;
var texLoader = new THREE.TextureLoader();
texLoader.setCrossOrigin(this.crossOrigin);
var onOverlayLoad = function(e){
if(onSetTexture) {onSetTexture();}
this.setTexture(e);
}.bind(this);
texLoader.load(this.url, onOverlayLoad);
};
/**
* Sets an offset which will be subtracted from real world coordinates in case the geometry uses also an offset (scene.offset)
* @method setOffset2
* @param {GIScene.Coordinate2} coord2
*/
GIScene.RasterOverlayMaterial.prototype.setOffset2 = function(coord2) {
var offset2Old = this.offset2;
this.offset2 = coord2;
this.setLowerLeft(this.lowerLeft.add(offset2Old));
this.setUpperRight(this.upperRight.add(offset2Old));
};
/**
* Clones the material. BUT reuses the texture without cloning it.
* @method clone
* @return {GIScene.RasterOverlayMaterial} material
*/
GIScene.RasterOverlayMaterial.prototype.clone = function() {
var material = new GIScene.RasterOverlayMaterial();
material.config = GIScene.Utils.mergeObjects(material.config, this.config);
material.url = this.url;
material.crossOrigin = this.crossOrigin;
material.offset2 = this.offset2;
material.lowerLeft = this.lowerLeft;
material.upperRight = this.upperRight;
material.texture = this.texture;
material.uniforms.lowerLeft.value = this.uniforms.lowerLeft.value;
material.uniforms.upperRight.value = this.uniforms.upperRight.value;
material.uniforms.tOverlay.value = this.uniforms.tOverlay.value;
// THREE.ShaderMaterial.prototype.clone.call(this);
return material;
};