diff --git a/src/color/setting.js b/src/color/setting.js index ad004f7e62..220943852b 100644 --- a/src/color/setting.js +++ b/src/color/setting.js @@ -359,6 +359,11 @@ p5.prototype.colorMode = function(mode, max1, max2, max3, maxA) { * and all named color strings are supported. In this case, an alpha number * value as a second argument is not supported, the RGBA form should be used. * + * In webgl, calling this will use the color set by this function when calculating + * the ambient term in the lighting process. If instead you want to use your own + * set color, you should call this function and then call ambientMaterial() to set it + * before drawing. + * * A p5.Color object can also be provided to set the fill color. * * @method fill diff --git a/src/webgl/material.js b/src/webgl/material.js index f6d58811bf..741935b6a9 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -388,6 +388,12 @@ p5.prototype.resetShader = function() { * You can view more materials in this * example. * + * If you call this, the color used when computing the ambient term for lighting + * will be the same color as determined by the texture. + * If you want to use a different color than the one given by the texture, + * you should set it by calling ambientMaterial() after calling this but before + * drawing. + * * @method texture * @param {p5.Image|p5.MediaElement|p5.Graphics|p5.Texture|p5.Framebuffer|p5.FramebufferTexture} tex image to use as texture * @chainable @@ -512,11 +518,10 @@ p5.prototype.texture = function(tex) { } this._renderer.drawMode = constants.TEXTURE; - this._renderer._useSpecularMaterial = false; - this._renderer._useEmissiveMaterial = false; this._renderer._useNormalMaterial = false; this._renderer._tex = tex; this._renderer._setProperty('_doFill', true); + this._renderer._hasSetAmbient = false; return this; }; @@ -719,8 +724,12 @@ p5.prototype.normalMaterial = function(...args) { /** * Sets the ambient color of the material. * - * The ambientMaterial() color is the color the object will reflect - * under **any** lighting. + * The color set with ambientMaterial() is multiplied by the color set + * with ambientLight() and adding up during lighting calculations. + * However, if you call fill() or texture() after calling this, + * the colors determined by those will be used instead. + * Therefore, when using the colors set here, you must either not use + * these functions, or call this function after calling these functions. * * Consider an ambientMaterial() with the color yellow (255, 255, 0). * If the light emits the color white (255, 255, 255), then the object @@ -825,7 +834,6 @@ p5.prototype.ambientMaterial = function(v1, v2, v3) { this._renderer.curAmbientColor = color._array; this._renderer._useNormalMaterial = false; this._renderer._enableLighting = true; - this._renderer._tex = null; this._renderer._setProperty('_doFill', true); return this; }; @@ -897,7 +905,6 @@ p5.prototype.emissiveMaterial = function(v1, v2, v3, a) { this._renderer._useEmissiveMaterial = true; this._renderer._useNormalMaterial = false; this._renderer._enableLighting = true; - this._renderer._tex = null; return this; }; @@ -952,6 +959,38 @@ p5.prototype.emissiveMaterial = function(v1, v2, v3, a) { * } * * + * + * @example + *
+ * + * let img; + * function preload() { + * img = loadImage('assets/rockies128.jpg'); + * } + * + * function setup() { + * createCanvas(100, 100, WEBGL); + * noStroke(); + * describe('textured torus with specular material'); + * } + * + * function draw() { + * background(0); + * texture(img); + * + * ambientLight(60); + * + * // add point light to showcase specular material + * let locX = mouseX - width / 2; + * let locY = mouseY - height / 2; + * pointLight(255, 255, 255, locX, locY, 50); + * + * specularMaterial(250); + * shininess(50); + * torus(30, 10, 64, 64); + * } + * + *
* @alt * torus with specular material */ @@ -984,7 +1023,6 @@ p5.prototype.specularMaterial = function(v1, v2, v3, alpha) { this._renderer._useSpecularMaterial = true; this._renderer._useNormalMaterial = false; this._renderer._enableLighting = true; - this._renderer._tex = null; return this; }; diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js index c3a3d1183a..dd9251f830 100644 --- a/src/webgl/p5.RendererGL.js +++ b/src/webgl/p5.RendererGL.js @@ -711,6 +711,7 @@ p5.RendererGL.prototype.fill = function(v1, v2, v3, a) { this.drawMode = constants.FILL; this._useNormalMaterial = false; this._tex = null; + this._hasSetAmbient = false; }; /** diff --git a/test/unit/webgl/p5.RendererGL.js b/test/unit/webgl/p5.RendererGL.js index 786d42b160..ad7c3b44a1 100644 --- a/test/unit/webgl/p5.RendererGL.js +++ b/test/unit/webgl/p5.RendererGL.js @@ -389,6 +389,114 @@ suite('p5.RendererGL', function() { expect(pixel[1]).to.equal(128); expect(pixel[2]).to.equal(128); }); + + test('fill() sets _hasSetAmbient to false', function() { + myp5.createCanvas(100, 100, myp5.WEBGL); + myp5.noStroke(); + myp5.lights(); + myp5.ambientMaterial(255, 255, 255); + myp5.fill(255, 0, 0); + myp5.plane(100); + const pixel = myp5.get(50, 50); + expect(pixel[0]).to.equal(221); + expect(pixel[1]).to.equal(0); + expect(pixel[2]).to.equal(0); + }); + + test('texture() sets _hasSetAmbient to false', function() { + myp5.createCanvas(100, 100, myp5.WEBGL); + const tex = myp5.createGraphics(256, 256); + tex.noStroke(); + for (let i=0; i<256; i++) { + tex.fill(i, i, 255); + tex.rect(0, i, 256, 1); + } + myp5.noStroke(); + myp5.lights(); + myp5.ambientMaterial(128, 128, 128); + myp5.texture(tex); + myp5.plane(100); + const pixel = myp5.get(50, 50); + expect(pixel[0]).to.equal(112); + expect(pixel[1]).to.equal(112); + expect(pixel[2]).to.equal(221); + }); + + test('texture() does not set _useSpecularMaterial to false', + function() { + myp5.createCanvas(100, 100, myp5.WEBGL); + const tex = myp5.createGraphics(256, 256); + tex.noStroke(); + for (let i=0; i<256; i++) { + tex.fill(i, i, 255); + tex.rect(0, i, 256, 1); + } + myp5.noStroke(); + myp5.lights(); + myp5.specularMaterial(128, 128, 128); + myp5.texture(tex); + myp5.plane(100); + const pixel = myp5.get(50, 50); + expect(pixel[0]).to.equal(240); + expect(pixel[1]).to.equal(240); + expect(pixel[2]).to.equal(255); + } + ); + + test('ambientMaterial() does not null texture', function() { + myp5.createCanvas(100, 100, myp5.WEBGL); + const tex = myp5.createGraphics(256, 256); + tex.noStroke(); + for (let i=0; i<256; i++) { + tex.fill(i, i, 255); + tex.rect(0, i, 256, 1); + } + myp5.noStroke(); + myp5.lights(); + myp5.texture(tex); + myp5.ambientMaterial(128, 128, 128); + myp5.plane(100); + const pixel = myp5.get(50, 50); + expect(pixel[0]).to.equal(111); + expect(pixel[1]).to.equal(111); + expect(pixel[2]).to.equal(158); + }); + test('specularMaterial() does not null texture', function() { + myp5.createCanvas(100, 100, myp5.WEBGL); + const tex = myp5.createGraphics(256, 256); + tex.noStroke(); + for (let i=0; i<256; i++) { + tex.fill(i, i, 255); + tex.rect(0, i, 256, 1); + } + myp5.noStroke(); + myp5.lights(); + myp5.texture(tex); + myp5.specularMaterial(128, 128, 128); + myp5.plane(100); + const pixel = myp5.get(50, 50); + expect(pixel[0]).to.equal(240); + expect(pixel[1]).to.equal(240); + expect(pixel[2]).to.equal(255); + }); + test('emissiveMaterial() does not null texture', function() { + myp5.createCanvas(100, 100, myp5.WEBGL); + const tex = myp5.createGraphics(256, 256); + tex.noStroke(); + for (let i=0; i<256; i++) { + tex.fill(i, i, 255); + tex.rect(0, i, 256, 1); + } + myp5.noStroke(); + myp5.lights(); + myp5.texture(tex); + myp5.emissiveMaterial(128, 128, 128); + myp5.plane(100); + const pixel = myp5.get(50, 50); + expect(pixel[0]).to.equal(240); + expect(pixel[1]).to.equal(240); + expect(pixel[2]).to.equal(255); + }); }); suite('loadpixels()', function() {