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);