diff --git a/CHANGES.md b/CHANGES.md index 13ffa1d10515..77192e4c6e89 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ Change Log * Added `Globe.showSkirts` to support the ability to hide terrain skirts when viewing terrain from below the surface. [#8489](https://github.com/AnalyticalGraphicsInc/cesium/pull/8489) * Fixed `BoundingSphere.projectTo2D` when the bounding sphere’s center is at the origin. [#8482](https://github.com/AnalyticalGraphicsInc/cesium/pull/8482) +* Added `minificationFilter` and `magnificationFilter` options to `Material` to control texture filtering. [#8473](https://github.com/AnalyticalGraphicsInc/cesium/pull/8473) ##### Fixes :wrench: * Fixed a bug where the camera could go underground during mouse navigation. [#8504](https://github.com/AnalyticalGraphicsInc/cesium/pull/8504) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 6346f2b35a77..399f335b9a65 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -140,6 +140,8 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu * [Ian Lilley](https://github.com/IanLilleyT) * [Northrop Grumman](http://www.northropgrumman.com) * [Joseph Stein](https://github.com/nahgrin) +* [EOX IT Services GmbH](https://eox.at) + * [Daniel Santillan](https://github.com/santilland) ## [Individual CLA](Documentation/Contributors/CLAs/individual-contributor-license-agreement-v1.0.pdf) * [Victor Berchet](https://github.com/vicb) diff --git a/Source/Scene/Material.js b/Source/Scene/Material.js index 36b7041a0f3a..91f950d5d022 100644 --- a/Source/Scene/Material.js +++ b/Source/Scene/Material.js @@ -31,8 +31,11 @@ import PolylineDashMaterial from '../Shaders/Materials/PolylineDashMaterial.js'; import PolylineGlowMaterial from '../Shaders/Materials/PolylineGlowMaterial.js'; import PolylineOutlineMaterial from '../Shaders/Materials/PolylineOutlineMaterial.js'; import RimLightingMaterial from '../Shaders/Materials/RimLightingMaterial.js'; +import Sampler from '../Renderer/Sampler.js'; import SlopeRampMaterial from '../Shaders/Materials/SlopeRampMaterial.js'; import StripeMaterial from '../Shaders/Materials/StripeMaterial.js'; +import TextureMagnificationFilter from '../Renderer/TextureMagnificationFilter.js'; +import TextureMinificationFilter from '../Renderer/TextureMinificationFilter.js'; import WaterMaterial from '../Shaders/Materials/Water.js'; import when from '../ThirdParty/when.js'; @@ -225,6 +228,8 @@ import when from '../ThirdParty/when.js'; * @param {Boolean} [options.strict=false] Throws errors for issues that would normally be ignored, including unused uniforms or materials. * @param {Boolean|Function} [options.translucent=true] When true or a function that returns true, the geometry * with this material is expected to appear translucent. + * @param {TextureMinificationFilter} [options.minificationFilter=TextureMinificationFilter.LINEAR] The {@link TextureMinificationFilter} to apply to this material's textures. + * @param {TextureMagnificationFilter} [options.magnificationFilter=TextureMagnificationFilter.LINEAR] The {@link TextureMagnificationFilter} to apply to this material's textures. * @param {Object} options.fabric The fabric JSON used to generate the material. * * @constructor @@ -298,6 +303,9 @@ import when from '../ThirdParty/when.js'; */ this.translucent = undefined; + this._minificationFilter = defaultValue(options.minificationFilter, TextureMinificationFilter.LINEAR); + this._magnificationFilter = defaultValue(options.magnificationFilter, TextureMagnificationFilter.LINEAR); + this._strict = undefined; this._template = undefined; this._count = undefined; @@ -415,6 +423,11 @@ import when from '../ThirdParty/when.js'; uniformId = loadedImage.id; var image = loadedImage.image; + var sampler = new Sampler({ + minificationFilter : this._minificationFilter, + magnificationFilter : this._magnificationFilter + }); + var texture; if (defined(image.internalFormat)) { texture = new Texture({ @@ -424,12 +437,14 @@ import when from '../ThirdParty/when.js'; height : image.height, source : { arrayBufferView : image.bufferView - } + }, + sampler : sampler }); } else { texture = new Texture({ context : context, - source : image + source : image, + sampler : sampler }); } @@ -462,7 +477,11 @@ import when from '../ThirdParty/when.js'; negativeY : images[3], positiveZ : images[4], negativeZ : images[5] - } + }, + sampler : new Sampler({ + minificationFilter : this._minificationFilter, + magnificationFilter : this._magnificationFilter + }) }); this._textures[uniformId] = cubeMap; @@ -725,9 +744,14 @@ import when from '../ThirdParty/when.js'; } if (!defined(texture) || texture === context.defaultTexture) { + var sampler = new Sampler({ + minificationFilter : material._minificationFilter, + magnificationFilter : material._magnificationFilter + }); texture = new Texture({ context : context, - source : uniformValue + source : uniformValue, + sampler : sampler }); material._textures[uniformId] = texture; return; diff --git a/Specs/Scene/MaterialSpec.js b/Specs/Scene/MaterialSpec.js index 6bb0f20456d2..fdce8eca34d4 100644 --- a/Specs/Scene/MaterialSpec.js +++ b/Specs/Scene/MaterialSpec.js @@ -11,6 +11,8 @@ import { Material } from '../../Source/Cesium.js'; import { MaterialAppearance } from '../../Source/Cesium.js'; import { PolylineCollection } from '../../Source/Cesium.js'; import { Primitive } from '../../Source/Cesium.js'; +import { TextureMagnificationFilter } from '../../Source/Cesium.js'; +import { TextureMinificationFilter } from '../../Source/Cesium.js'; import createScene from '../createScene.js'; import pollToPromise from '../pollToPromise.js'; @@ -20,13 +22,13 @@ describe('Scene/Material', function() { var rectangle = Rectangle.fromDegrees(-10.0, -10.0, 10.0, 10.0); var polygon; - var backgroundColor = [0, 0, 255, 255]; + var backgroundColor = [0, 0, 128, 255]; var polylines; var polyline; beforeAll(function() { scene = createScene(); - Color.unpack(backgroundColor, 0, scene.backgroundColor); + Color.fromBytes(backgroundColor[0], backgroundColor[1], backgroundColor[2], backgroundColor[3], scene.backgroundColor); scene.primitives.destroyPrimitives = false; scene.camera.setView({destination : rectangle}); }); @@ -77,7 +79,9 @@ describe('Scene/Material', function() { expect(scene).toRender(backgroundColor); } + scene.primitives.removeAll(); scene.primitives.add(polygon); + expect(scene).toRenderAndCall(function(rgba) { expect(rgba).not.toEqual(backgroundColor); if (defined(callback)) { @@ -90,7 +94,9 @@ describe('Scene/Material', function() { polyline.material = material; expect(scene).toRender(backgroundColor); + scene.primitives.removeAll(); scene.primitives.add(polylines); + var result; expect(scene).toRenderAndCall(function(rgba) { result = rgba; @@ -595,6 +601,55 @@ describe('Scene/Material', function() { }); }); + it('creates material with custom texture filter', function() { + var materialLinear = new Material({ + fabric : { + type : 'DiffuseMap', + uniforms : { + image : './Data/Images/BlueOverRed.png' + } + }, + minificationFilter : TextureMinificationFilter.LINEAR, + magnificationFilter : TextureMagnificationFilter.LINEAR + }); + + var materialNearest = new Material({ + fabric : { + type : 'DiffuseMap', + uniforms : { + image : './Data/Images/BlueOverRed.png' + } + }, + minificationFilter : TextureMinificationFilter.NEAREST, + magnificationFilter : TextureMagnificationFilter.NEAREST + }); + + var purple = [127, 0, 127, 255]; + + var ignoreBackground = true; + renderMaterial(materialLinear, ignoreBackground); // Populate the scene with the primitive prior to updating + return pollToPromise(function() { + var imageLoaded = materialLinear._loadedImages.length !== 0; + scene.renderForSpecs(); + return imageLoaded; + }).then(function() { + renderMaterial(materialLinear, ignoreBackground, function(rgba) { + expect(rgba).toEqualEpsilon(purple, 1); + }); + }).then(function() { + renderMaterial(materialNearest, ignoreBackground); // Populate the scene with the primitive prior to updating + return pollToPromise(function() { + var imageLoaded = materialNearest._loadedImages.length !== 0; + scene.renderForSpecs(); + return imageLoaded; + }).then(function() { + renderMaterial(materialNearest, ignoreBackground, function(rgba) { + expect(rgba).not.toEqualEpsilon(purple, 1); + }); + }); + }); + }); + it('throws with source and components in same template', function () { expect(function() { return new Material({ @@ -788,10 +843,13 @@ describe('Scene/Material', function() { var material = Material.fromType(Material.DiffuseMapType); material.uniforms.image = './Data/Images/Green.png'; - pollToPromise(function() { - return material._loadedImages.length !== 0; + renderMaterial(material); + + return pollToPromise(function() { + var result = material._loadedImages.length !== 0; + scene.renderForSpecs(); + return result; }).then(function() { - renderMaterial(material); material.destroy(); expect(material.isDestroyed()).toEqual(true); }); @@ -820,11 +878,13 @@ describe('Scene/Material', function() { }); material.materials.diffuseMap.uniforms.image = './Data/Images/Green.png'; - pollToPromise(function() { - return material.materials.diffuseMap._loadedImages.length !== 0; - }).then(function() { - renderMaterial(material); + renderMaterial(material); + return pollToPromise(function() { + var result = material.materials.diffuseMap._loadedImages.length !== 0; + scene.renderForSpecs(); + return result; + }).then(function() { var diffuseMap = material.materials.diffuseMap; material.destroy(); expect(material.isDestroyed()).toEqual(true);