1
0
mirror of https://github.com/psychopy/psychojs.git synced 2025-05-10 18:50:54 +00:00

added per grating and per window contrast filter; added separate stimuli PIXI container as a result of workaround with background; added grating blend mode support; started work on grating colors;

This commit is contained in:
lgtst 2022-05-05 19:37:30 +03:00
parent 496154442f
commit a1effe6969
15 changed files with 187 additions and 72 deletions

View File

@ -101,7 +101,7 @@ export class MinimalStim extends PsychObject
} }
else else
{ {
this.win._rootContainer.addChild(this._pixi); this._win.addPixiObject(this._pixi);
this.win._drawList.push(this); this.win._drawList.push(this);
} }
} }
@ -111,9 +111,9 @@ export class MinimalStim extends PsychObject
// from the window container, update it, then put it back: // from the window container, update it, then put it back:
if (this._needUpdate && typeof this._pixi !== "undefined") if (this._needUpdate && typeof this._pixi !== "undefined")
{ {
this.win._rootContainer.removeChild(this._pixi); this._win.removePixiObject(this._pixi);
this._updateIfNeeded(); this._updateIfNeeded();
this.win._rootContainer.addChild(this._pixi); this._win.addPixiObject(this._pixi);
} }
} }
} }
@ -140,7 +140,7 @@ export class MinimalStim extends PsychObject
// if the stimulus has a pixi representation, remove it from the root container: // if the stimulus has a pixi representation, remove it from the root container:
if (typeof this._pixi !== "undefined") if (typeof this._pixi !== "undefined")
{ {
this._win._rootContainer.removeChild(this._pixi); this._win.removePixiObject(this._pixi);
} }
} }
this.status = PsychoJS.Status.STOPPED; this.status = PsychoJS.Status.STOPPED;

View File

@ -26,7 +26,8 @@ import { Logger } from "./Logger.js";
* @param {string} [options.name] the name of the window * @param {string} [options.name] the name of the window
* @param {boolean} [options.fullscr= false] whether or not to go fullscreen * @param {boolean} [options.fullscr= false] whether or not to go fullscreen
* @param {Color} [options.color= Color('black')] the background color of the window * @param {Color} [options.color= Color('black')] the background color of the window
* @param {number} [options.gamma= 1] sets the delimiter for gamma correction. In other words gamma correction is calculated as pow(rgb, 1/gamma) * @param {number} [options.gamma= 1] sets the divisor for gamma correction. In other words gamma correction is calculated as pow(rgb, 1/gamma)
* @param {number} [options.contrast= 1] sets the contrast value
* @param {string} [options.units= 'pix'] the units of the window * @param {string} [options.units= 'pix'] the units of the window
* @param {boolean} [options.waitBlanking= false] whether or not to wait for all rendering operations to be done * @param {boolean} [options.waitBlanking= false] whether or not to wait for all rendering operations to be done
* before flipping * before flipping
@ -73,7 +74,11 @@ export class Window extends PsychObject
this._drawList = []; this._drawList = [];
this._addAttribute("fullscr", fullscr); this._addAttribute("fullscr", fullscr);
this._addAttribute("color", color); this._addAttribute("color", color, new Color("black"), () => {
if (this._backgroundSprite) {
this._backgroundSprite.tint = color.int;
}
});
this._addAttribute("gamma", gamma, 1, () => { this._addAttribute("gamma", gamma, 1, () => {
this._adjustmentFilter.gamma = this._gamma; this._adjustmentFilter.gamma = this._gamma;
}); });
@ -298,6 +303,28 @@ export class Window extends PsychObject
this._flipCallbacks.push({ function: flipCallback, arguments: flipCallbackArgs }); this._flipCallbacks.push({ function: flipCallback, arguments: flipCallbackArgs });
} }
/**
* Add PIXI.DisplayObject to the container displayed on the scene (window)
*
* @name module:core.Window#addPixiObject
* @function
* @public
*/
addPixiObject (pixiObject) {
this._stimsContainer.addChild(pixiObject);
}
/**
* Remove PIXI.DisplayObject from the container displayed on the scene (window)
*
* @name module:core.Window#removePixiObject
* @function
* @public
*/
removePixiObject (pixiObject) {
this._stimsContainer.removeChild(pixiObject);
}
/** /**
* Render the stimuli onto the canvas. * Render the stimuli onto the canvas.
* *
@ -385,9 +412,9 @@ export class Window extends PsychObject
{ {
if (stimulus._needUpdate && typeof stimulus._pixi !== "undefined") if (stimulus._needUpdate && typeof stimulus._pixi !== "undefined")
{ {
this._rootContainer.removeChild(stimulus._pixi); this._stimsContainer.removeChild(stimulus._pixi);
stimulus._updateIfNeeded(); stimulus._updateIfNeeded();
this._rootContainer.addChild(stimulus._pixi); this._stimsContainer.addChild(stimulus._pixi);
} }
} }
} }
@ -432,6 +459,7 @@ export class Window extends PsychObject
width: this._size[0], width: this._size[0],
height: this._size[1], height: this._size[1],
backgroundColor: this.color.int, backgroundColor: this.color.int,
powerPreference: "high-performance",
resolution: window.devicePixelRatio, resolution: window.devicePixelRatio,
}); });
this._renderer.view.style.transform = "translatez(0)"; this._renderer.view.style.transform = "translatez(0)";
@ -441,8 +469,25 @@ export class Window extends PsychObject
// we also change the background color of the body since the dialog popup may be longer than the window's height: // we also change the background color of the body since the dialog popup may be longer than the window's height:
document.body.style.backgroundColor = this._color.hex; document.body.style.backgroundColor = this._color.hex;
// filters in PIXI work in a slightly unexpected fashion:
// when setting this._rootContainer.filters, filtering itself
// ignores backgroundColor of this._renderer and in addition to that
// all child elements of this._rootContainer ignore backgroundColor when blending.
// To circumvent that creating a separate PIXI.Sprite that serves as background color.
// Then placing all Stims to a separate this._stimsContainer which hovers on top of
// background sprite so that if we need to move all stims at once, the background sprite
// won't get affected.
this._backgroundSprite = new PIXI.Sprite(PIXI.Texture.WHITE);
this._backgroundSprite.tint = this.color.int;
this._backgroundSprite.width = this._size[0];
this._backgroundSprite.height = this._size[1];
this._backgroundSprite.anchor.set(.5);
this._stimsContainer = new PIXI.Container();
this._stimsContainer.sortableChildren = true;
// create a top-level PIXI container: // create a top-level PIXI container:
this._rootContainer = new PIXI.Container(); this._rootContainer = new PIXI.Container();
this._rootContainer.addChild(this._backgroundSprite, this._stimsContainer);
this._rootContainer.interactive = true; this._rootContainer.interactive = true;
this._rootContainer.filters = [this._adjustmentFilter]; this._rootContainer.filters = [this._adjustmentFilter];

View File

@ -1009,8 +1009,8 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
this._stimuliClipMask.clear(); this._stimuliClipMask.clear();
this._stimuliClipMask.beginFill(0xFFFFFF); this._stimuliClipMask.beginFill(0xFFFFFF);
this._stimuliClipMask.drawRect( this._stimuliClipMask.drawRect(
this._win._rootContainer.position.x + this._leftEdge_px + 2, this._win._stimsContainer.position.x + this._leftEdge_px + 2,
this._win._rootContainer.position.y + this._bottomEdge_px + 2, this._win._stimsContainer.position.y + this._bottomEdge_px + 2,
this._size_px[0] - 4, this._size_px[0] - 4,
this._size_px[1] - 6, this._size_px[1] - 6,
); );

View File

@ -8,8 +8,8 @@
*/ */
import * as PIXI from "pixi.js-legacy"; import * as PIXI from "pixi.js-legacy";
import {AdjustmentFilter} from "@pixi/filter-adjustment";
import { Color } from "../util/Color.js"; import { Color } from "../util/Color.js";
import { ColorMixin } from "../util/ColorMixin.js";
import { to_pixiPoint } from "../util/Pixi.js"; import { to_pixiPoint } from "../util/Pixi.js";
import * as util from "../util/Util.js"; import * as util from "../util/Util.js";
import { VisualStim } from "./VisualStim.js"; import { VisualStim } from "./VisualStim.js";
@ -32,7 +32,6 @@ import raisedCosShader from "./shaders/raisedCosShader.frag";
* @name module:visual.GratingStim * @name module:visual.GratingStim
* @class * @class
* @extends VisualStim * @extends VisualStim
* @mixes ColorMixin
* @param {Object} options * @param {Object} options
* @param {String} options.name - the name used when logging messages from this stimulus * @param {String} options.name - the name used when logging messages from this stimulus
* @param {Window} options.win - the associated Window * @param {Window} options.win - the associated Window
@ -44,17 +43,17 @@ import raisedCosShader from "./shaders/raisedCosShader.frag";
* @param {Array.<number>} [options.pos= [0, 0]] - the position of the center of the stimulus * @param {Array.<number>} [options.pos= [0, 0]] - the position of the center of the stimulus
* @param {number} [options.ori= 0.0] - the orientation (in degrees) * @param {number} [options.ori= 0.0] - the orientation (in degrees)
* @param {number} [options.size] - the size of the rendered image (DEFAULT_STIM_SIZE_PX will be used if size is not specified) * @param {number} [options.size] - the size of the rendered image (DEFAULT_STIM_SIZE_PX will be used if size is not specified)
* @param {Color} [options.color= "white"] the background color * @param {Color} [options.color= "white"] - Foreground color of the stimulus. Can be String like "red" or "#ff0000" or Number like 0xff0000.
* @param {number} [options.opacity= 1.0] - the opacity * @param {number} [options.opacity= 1.0] - Set the opacity of the stimulus. Determines how visible the stimulus is relative to background.
* @param {number} [options.contrast= 1.0] - the contrast * @param {number} [options.contrast= 1.0] - Set the contrast of the stimulus, i.e. scales how far the stimulus deviates from the middle grey. Ranges [-1, 1].
* @param {number} [options.depth= 0] - the depth (i.e. the z order) * @param {number} [options.depth= 0] - the depth (i.e. the z order)
* @param {boolean} [options.interpolate= false] - whether or not the image is interpolated. NOT IMPLEMENTED YET. * @param {boolean} [options.interpolate= false] - whether or not the image is interpolated. NOT IMPLEMENTED YET.
* @param {String} [options.blendmode= 'avg'] - blend mode of the stimulus, determines how the stimulus is blended with the background. NOT IMPLEMENTED YET. * @param {String} [options.blendmode= "avg"] - blend mode of the stimulus, determines how the stimulus is blended with the background. Supported values: "avg", "add", "mul", "screen".
* @param {boolean} [options.autoDraw= false] - whether or not the stimulus should be automatically drawn on every frame flip * @param {boolean} [options.autoDraw= false] - whether or not the stimulus should be automatically drawn on every frame flip
* @param {boolean} [options.autoLog= false] - whether or not to log * @param {boolean} [options.autoLog= false] - whether or not to log
*/ */
export class GratingStim extends util.mix(VisualStim).with(ColorMixin) export class GratingStim extends VisualStim
{ {
/** /**
* An object that keeps shaders source code and default uniform values for them. * An object that keeps shaders source code and default uniform values for them.
@ -143,21 +142,23 @@ export class GratingStim extends util.mix(VisualStim).with(ColorMixin)
uniforms: { uniforms: {
uFreq: 1.0, uFreq: 1.0,
uPhase: 0.0, uPhase: 0.0,
uColor: [.5, 0, .5] uColor: [1., 1., 1.]
} }
}, },
sqr: { sqr: {
shader: sqrShader, shader: sqrShader,
uniforms: { uniforms: {
uFreq: 1.0, uFreq: 1.0,
uPhase: 0.0 uPhase: 0.0,
uColor: [1., 1., 1.]
} }
}, },
saw: { saw: {
shader: sawShader, shader: sawShader,
uniforms: { uniforms: {
uFreq: 1.0, uFreq: 1.0,
uPhase: 0.0 uPhase: 0.0,
uColor: [1., 1., 1.]
} }
}, },
tri: { tri: {
@ -165,27 +166,31 @@ export class GratingStim extends util.mix(VisualStim).with(ColorMixin)
uniforms: { uniforms: {
uFreq: 1.0, uFreq: 1.0,
uPhase: 0.0, uPhase: 0.0,
uPeriod: 1.0 uPeriod: 1.0,
uColor: [1., 1., 1.]
} }
}, },
sinXsin: { sinXsin: {
shader: sinXsinShader, shader: sinXsinShader,
uniforms: { uniforms: {
uFreq: 1.0, uFreq: 1.0,
uPhase: 0.0 uPhase: 0.0,
uColor: [1., 1., 1.]
} }
}, },
sqrXsqr: { sqrXsqr: {
shader: sqrXsqrShader, shader: sqrXsqrShader,
uniforms: { uniforms: {
uFreq: 1.0, uFreq: 1.0,
uPhase: 0.0 uPhase: 0.0,
uColor: [1., 1., 1.]
} }
}, },
circle: { circle: {
shader: circleShader, shader: circleShader,
uniforms: { uniforms: {
uRadius: 1.0 uRadius: 1.0,
uColor: [1., 1., 1.]
} }
}, },
gauss: { gauss: {
@ -193,26 +198,30 @@ export class GratingStim extends util.mix(VisualStim).with(ColorMixin)
uniforms: { uniforms: {
uA: 1.0, uA: 1.0,
uB: 0.0, uB: 0.0,
uC: 0.16 uC: 0.16,
uColor: [1., 1., 1.]
} }
}, },
cross: { cross: {
shader: crossShader, shader: crossShader,
uniforms: { uniforms: {
uThickness: 0.2 uThickness: 0.2,
uColor: [1., 1., 1.]
} }
}, },
radRamp: { radRamp: {
shader: radRampShader, shader: radRampShader,
uniforms: { uniforms: {
uSqueeze: 1.0 uSqueeze: 1.0,
uColor: [1., 1., 1.]
} }
}, },
raisedCos: { raisedCos: {
shader: raisedCosShader, shader: raisedCosShader,
uniforms: { uniforms: {
uBeta: 0.25, uBeta: 0.25,
uPeriod: 0.625 uPeriod: 0.625,
uColor: [1., 1., 1.]
} }
} }
}; };
@ -225,6 +234,13 @@ export class GratingStim extends util.mix(VisualStim).with(ColorMixin)
*/ */
static #DEFAULT_STIM_SIZE_PX = [256, 256]; // in pixels static #DEFAULT_STIM_SIZE_PX = [256, 256]; // in pixels
static #BLEND_MODES_MAP = {
avg: PIXI.BLEND_MODES.NORMAL,
add: PIXI.BLEND_MODES.ADD,
mul: PIXI.BLEND_MODES.MULTIPLY,
screen: PIXI.BLEND_MODES.SCREEN
};
constructor({ constructor({
name, name,
tex = "sin", tex = "sin",
@ -239,7 +255,7 @@ export class GratingStim extends util.mix(VisualStim).with(ColorMixin)
color, color,
colorSpace, colorSpace,
opacity, opacity,
contrast, contrast = 1,
depth, depth,
interpolate, interpolate,
blendmode, blendmode,
@ -250,36 +266,19 @@ export class GratingStim extends util.mix(VisualStim).with(ColorMixin)
{ {
super({ name, win, units, ori, opacity, depth, pos, size, autoDraw, autoLog }); super({ name, win, units, ori, opacity, depth, pos, size, autoDraw, autoLog });
this._addAttribute( this._adjustmentFilter = new AdjustmentFilter({
"tex", contrast
tex, });
); this._addAttribute("tex", tex);
this._addAttribute( this._addAttribute("mask", mask);
"mask", this._addAttribute("SF", sf, GratingStim.#SHADERS[tex] ? GratingStim.#SHADERS[tex].uniforms.uFreq || 1.0 : 1.0);
mask, this._addAttribute("phase", phase, GratingStim.#SHADERS[tex] ? GratingStim.#SHADERS[tex].uniforms.uPhase || 0.0 : 0.0);
); this._addAttribute("color", color, "white");
this._addAttribute( this._addAttribute("colorSpace", colorSpace, "RGB");
"SF", this._addAttribute("contrast", contrast, 1.0, () => {
sf, this._adjustmentFilter.contrast = this._contrast;
GratingStim.#SHADERS[tex] ? GratingStim.#SHADERS[tex].uniforms.uFreq || 1.0 : 1.0 });
); this._addAttribute("blendmode", blendmode, "avg");
this._addAttribute(
"phase",
phase,
GratingStim.#SHADERS[tex] ? GratingStim.#SHADERS[tex].uniforms.uPhase || 0.0 : 0.0
);
this._addAttribute(
"color",
color,
"white",
this._onChange(true, false),
);
this._addAttribute(
"contrast",
contrast,
1.0,
this._onChange(true, false),
);
this._addAttribute( this._addAttribute(
"interpolate", "interpolate",
interpolate, interpolate,
@ -521,6 +520,43 @@ export class GratingStim extends util.mix(VisualStim).with(ColorMixin)
} }
} }
/**
* Set color space value for the grating stimulus.
*
* @name module:visual.GratingStim#setColorSpace
* @public
* @param {String} colorSpaceVal - color space value
* @param {boolean} [log= false] - whether of not to log
*/
setColorSpace (colorSpaceVal = "RGB", log = false) {
let colorSpaceValU = colorSpaceVal.toUpperCase();
if (Color.COLOR_SPACE[colorSpaceValU] === undefined) {
colorSpaceValU = "RGB";
}
const hasChanged = this._setAttribute("colorSpace", colorSpaceValU, log);
if (hasChanged) {
this.setColor(this._color);
}
}
/**
* Set foreground color value for the grating stimulus.
*
* @name module:visual.GratingStim#setColor
* @public
* @param {Color} colorVal - color value, can be String like "red" or "#ff0000" or Number like 0xff0000.
* @param {boolean} [log= false] - whether of not to log
*/
setColor (colorVal = "white", log = false) {
const colorObj = (colorVal instanceof Color) ? colorVal : new Color(colorVal, Color.COLOR_SPACE[this._colorSpace])
this._setAttribute("color", colorObj, log);
if (this._pixi instanceof PIXI.Mesh) {
this._pixi.shader.uniforms.uColor = colorObj.rgb;
} else if (this._pixi instanceof PIXI.TilingSprite) {
}
}
/** /**
* Set spatial frequency value for the function. * Set spatial frequency value for the function.
* *
@ -543,6 +579,29 @@ export class GratingStim extends util.mix(VisualStim).with(ColorMixin)
} }
} }
/**
* Set blend mode of the grating stimulus.
*
* @name module:visual.GratingStim#setBlendmode
* @public
* @param {String} blendMode - blend mode, can be one of the following: ["avg", "add", "mul", "screen"].
* @param {boolean} [log=false] - whether or not to log
*/
setBlendmode (blendMode = "avg", log = false) {
this._setAttribute("blendmode", blendMode, log);
if (this._pixi !== undefined) {
let pixiBlendMode = GratingStim.#BLEND_MODES_MAP[blendMode];
if (pixiBlendMode === undefined) {
pixiBlendMode = PIXI.BLEND_MODES.NORMAL;
}
if (this._pixi.filters) {
this._pixi.filters[this._pixi.filters.length - 1].blendMode = pixiBlendMode;
} else {
this._pixi.blendMode = pixiBlendMode;
}
}
}
/** /**
* Update the stimulus, if necessary. * Update the stimulus, if necessary.
* *
@ -590,6 +649,7 @@ export class GratingStim extends util.mix(VisualStim).with(ColorMixin)
}); });
} }
this._pixi.pivot.set(this._pixi.width * 0.5, this._pixi.width * 0.5); this._pixi.pivot.set(this._pixi.width * 0.5, this._pixi.width * 0.5);
this._pixi.filters = [this._adjustmentFilter];
// add a mask if need be: // add a mask if need be:
if (typeof this._mask !== "undefined") if (typeof this._mask !== "undefined")

View File

@ -16,9 +16,10 @@ out vec4 shaderOut;
#define M_PI 3.14159265358979 #define M_PI 3.14159265358979
uniform float uRadius; uniform float uRadius;
uniform vec3 uColor;
void main() { void main() {
vec2 uv = vUvs; vec2 uv = vUvs;
float s = 1. - step(uRadius, length(uv * 2. - 1.)); float s = 1. - step(uRadius, length(uv * 2. - 1.));
shaderOut = vec4(vec3(s), 1.0); shaderOut = vec4(vec3(s) * uColor, 1.0);
} }

View File

@ -16,11 +16,12 @@ out vec4 shaderOut;
#define M_PI 3.14159265358979 #define M_PI 3.14159265358979
uniform float uThickness; uniform float uThickness;
uniform vec3 uColor;
void main() { void main() {
vec2 uv = vUvs; vec2 uv = vUvs;
float sx = step(uThickness, length(uv.x * 2. - 1.)); float sx = step(uThickness, length(uv.x * 2. - 1.));
float sy = step(uThickness, length(uv.y * 2. - 1.)); float sy = step(uThickness, length(uv.y * 2. - 1.));
float s = 1. - sx * sy; float s = 1. - sx * sy;
shaderOut = vec4(vec3(s), 1.0); shaderOut = vec4(vec3(s) * uColor, 1.0);
} }

View File

@ -18,6 +18,7 @@ out vec4 shaderOut;
uniform float uA; uniform float uA;
uniform float uB; uniform float uB;
uniform float uC; uniform float uC;
uniform vec3 uColor;
#define M_PI 3.14159265358979 #define M_PI 3.14159265358979
@ -26,5 +27,5 @@ void main() {
float c2 = uC * uC; float c2 = uC * uC;
float x = length(uv - .5); float x = length(uv - .5);
float g = uA * exp(-pow(x - uB, 2.) / c2 * .5); float g = uA * exp(-pow(x - uB, 2.) / c2 * .5);
shaderOut = vec4(vec3(g), 1.); shaderOut = vec4(vec3(g) * uColor, 1.);
} }

View File

@ -14,11 +14,12 @@ precision mediump float;
in vec2 vUvs; in vec2 vUvs;
out vec4 shaderOut; out vec4 shaderOut;
uniform float uSqueeze; uniform float uSqueeze;
uniform vec3 uColor;
#define M_PI 3.14159265358979 #define M_PI 3.14159265358979
void main() { void main() {
vec2 uv = vUvs; vec2 uv = vUvs;
float s = 1. - length(uv * 2. - 1.) * uSqueeze; float s = 1. - length(uv * 2. - 1.) * uSqueeze;
shaderOut = vec4(vec3(s), 1.0); shaderOut = vec4(vec3(s) * uColor, 1.0);
} }

View File

@ -18,6 +18,7 @@ out vec4 shaderOut;
#define M_PI 3.14159265358979 #define M_PI 3.14159265358979
uniform float uBeta; uniform float uBeta;
uniform float uPeriod; uniform float uPeriod;
uniform vec3 uColor;
void main() { void main() {
vec2 uv = vUvs; vec2 uv = vUvs;
@ -31,5 +32,5 @@ void main() {
} else if (absX > edgeArgument2) { } else if (absX > edgeArgument2) {
s = 0.; s = 0.;
} }
shaderOut = vec4(vec3(s), 1.0); shaderOut = vec4(vec3(s) * uColor, 1.0);
} }

View File

@ -18,10 +18,11 @@ out vec4 shaderOut;
#define M_PI 3.14159265358979 #define M_PI 3.14159265358979
uniform float uFreq; uniform float uFreq;
uniform float uPhase; uniform float uPhase;
uniform vec3 uColor;
void main() { void main() {
vec2 uv = vUvs; vec2 uv = vUvs;
float s = uFreq * uv.x + uPhase; float s = uFreq * uv.x + uPhase;
s = mod(s, 1.); s = mod(s, 1.);
shaderOut = vec4(vec3(s), 1.0); shaderOut = vec4(vec3(s) * uColor, 1.0);
} }

View File

@ -22,6 +22,6 @@ uniform vec3 uColor;
void main() { void main() {
vec2 uv = vUvs; vec2 uv = vUvs;
float s = sin((uFreq * uv.x + uPhase) * 2. * M_PI); float s = sin((uFreq * uv.x + uPhase) * 2. * M_PI) * .5 + .5;
shaderOut = vec4((.5 + .5 * vec3(s)) * uColor, 1.0); shaderOut = vec4(vec3(s) * uColor, 1.0);
} }

View File

@ -19,11 +19,12 @@ out vec4 shaderOut;
#define PI2 2.* M_PI #define PI2 2.* M_PI
uniform float uFreq; uniform float uFreq;
uniform float uPhase; uniform float uPhase;
uniform vec3 uColor;
void main() { void main() {
vec2 uv = vUvs; vec2 uv = vUvs;
float sx = sin((uFreq * uv.x + uPhase) * PI2); float sx = sin((uFreq * uv.x + uPhase) * PI2);
float sy = sin((uFreq * uv.y + uPhase) * PI2); float sy = sin((uFreq * uv.y + uPhase) * PI2);
float s = sx * sy * .5 + .5; float s = sx * sy * .5 + .5;
shaderOut = vec4(vec3(s), 1.0); shaderOut = vec4(vec3(s) * uColor, 1.0);
} }

View File

@ -18,9 +18,10 @@ out vec4 shaderOut;
#define M_PI 3.14159265358979 #define M_PI 3.14159265358979
uniform float uFreq; uniform float uFreq;
uniform float uPhase; uniform float uPhase;
uniform vec3 uColor;
void main() { void main() {
vec2 uv = vUvs; vec2 uv = vUvs;
float s = sign(sin((uFreq * uv.x + uPhase) * 2. * M_PI)); float s = sign(sin((uFreq * uv.x + uPhase) * 2. * M_PI)) * .5 + .5;
shaderOut = vec4(.5 + .5 * vec3(s), 1.0); shaderOut = vec4(vec3(s) * uColor, 1.0);
} }

View File

@ -19,11 +19,12 @@ out vec4 shaderOut;
#define PI2 2.* M_PI #define PI2 2.* M_PI
uniform float uFreq; uniform float uFreq;
uniform float uPhase; uniform float uPhase;
uniform vec3 uColor;
void main() { void main() {
vec2 uv = vUvs; vec2 uv = vUvs;
float sx = sign(sin((uFreq * uv.x + uPhase) * PI2)); float sx = sign(sin((uFreq * uv.x + uPhase) * PI2));
float sy = sign(sin((uFreq * uv.y + uPhase) * PI2)); float sy = sign(sin((uFreq * uv.y + uPhase) * PI2));
float s = sx * sy * .5 + .5; float s = sx * sy * .5 + .5;
shaderOut = vec4(vec3(s), 1.0); shaderOut = vec4(vec3(s) * uColor, 1.0);
} }

View File

@ -19,10 +19,11 @@ out vec4 shaderOut;
uniform float uFreq; uniform float uFreq;
uniform float uPhase; uniform float uPhase;
uniform float uPeriod; uniform float uPeriod;
uniform vec3 uColor;
void main() { void main() {
vec2 uv = vUvs; vec2 uv = vUvs;
float s = uFreq * uv.x + uPhase; float s = uFreq * uv.x + uPhase;
s = 2. * abs(s / uPeriod - floor(s / uPeriod + .5)); s = 2. * abs(s / uPeriod - floor(s / uPeriod + .5));
shaderOut = vec4(vec3(s), 1.0); shaderOut = vec4(vec3(s) * uColor, 1.0);
} }