Dear Magnificent Community and Developers,
There's a PixiJs filter which is based on a shader ""Godrays" by alaingalvan", but it is required to somehow achieve such a filter/shader which does lighten certain areas where "lights" exist on a transparent stage without darkening the background.
The current version creates dark places ('0x000000') where the "lights" are not shown, but the darkness must not surpass the background ('0x333333' or '0xffffff' as in CSS), so it would look like a transparent filter in the result. This is the incorrect behavior since it creates black background where the "lights" are (it is correct that it affects the background):
const uniformData = {
time: {
type: 'float',
value: 0.0
},
lacunarity: {
type: 'float',
value: 30.0
},
gain: {
type: 'float',
value: 1.0
},
parallel: {
type: 'b',
value: true
},
light: {
type: 'v2',
value: [0.0, 0.0]
},
dimensions: {
type: 'v2',
value: [800, 400]
},
aspect: {
type: 'float',
value: 1.0
}
};
// 3D gradient Noise
// MIT License
// Copyright © 2013 Inigo Quilez
// https://www.shadertoy.com/view/Xsl3Dl
// Original: https://codepen.io/alaingalvan/pen/gOoEpW
const fragSource = '' +
`precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform vec4 filterArea;
uniform vec2 dimensions;
uniform vec2 light;
uniform bool parallel;
uniform float aspect;
uniform float gain;
uniform float lacunarity;
uniform float time;
vec3 hash(vec3 p) {
p = vec3(
dot(p, vec3(127.1, 311.7, 74.7)),
dot(p, vec3(269.5, 183.3, 246.1)),
dot(p, vec3(113.5, 271.9, 124.6))
);
return -1.0 + 2.0 * fract(sin(p) * 43758.5453123);
}
float noise(in vec3 p) {
vec3 i = floor(p);
vec3 f = fract(p);
vec3 u = f * f * (3.0 - 2.0 * f);
return mix(
mix(
mix(
dot(hash(i + vec3(0.0, 0.0, 0.0)), f - vec3(0.0, 0.0, 0.0)),
dot(hash(i + vec3(1.0, 0.0, 0.0)), f - vec3(1.0, 0.0, 0.0)),
u.x
),
mix(
dot(hash(i + vec3(0.0, 1.0, 0.0)), f - vec3(0.0, 1.0, 0.0)),
dot(hash(i + vec3(1.0, 1.0, 0.0)), f - vec3(1.0, 1.0, 0.0)),
u.x
),
u.y
),
mix(
mix(
dot(hash(i + vec3(0.0, 0.0, 1.0)), f - vec3(0.0, 0.0, 1.0)),
dot(hash(i + vec3(1.0, 0.0, 1.0)), f - vec3(1.0, 0.0, 1.0)),
u.x
),
mix(
dot(hash(i + vec3(0.0, 1.0, 1.0)), f - vec3(0.0, 1.0, 1.0)),
dot(hash(i + vec3(1.0, 1.0, 1.0)), f - vec3(1.0, 1.0, 1.0)),
u.x
),
u.y
),
u.z
);
}
float turb(vec3 pos, float lacunarity, float gain) {
float f, totalGain;
totalGain = gain;
vec3 q = 2.0 * pos;
f = totalGain * noise(q);
q = q * 2.01 * lacunarity;
totalGain *= gain;
f += totalGain * noise(q);
q = q * 3.02 * lacunarity;
totalGain *= gain;
f += totalGain * noise(q);
q = q * 3.03 * lacunarity;
totalGain *= gain;
f += totalGain * noise(q);
q = q * 3.01 * lacunarity;
totalGain *= gain;
f += totalGain * noise(q);
q = q * 3.99 * lacunarity;
totalGain *= gain;
f += totalGain * noise(q);
q = q * 3.98 * lacunarity;
totalGain *= gain;
f += totalGain * noise(q);
f = 3.0 * f;
return abs(f);
}
void main(void) {
gl_FragColor = texture2D(uSampler, vTextureCoord);
float d = 0.0;
vec2 coord = vTextureCoord;
if (parallel) {
float _cos = light.x;
float _sin = light.y;
d = (_cos * coord.x) + (_sin * coord.y * aspect);
} else {
float dx = coord.x - light.x / dimensions.x;
float dy = (coord.y - light.y / dimensions.y) * aspect;
float dis = sqrt(dx * dx + dy * dy) + 0.00001;
d = dy / dis;
}
vec2 dir = vec2(d, d);
float noise = turb(vec3(dir, 0.0) + vec3(time, 0.0, 62.1 + time) * 0.1, lacunarity, gain);
vec4 mist = vec4(noise, noise, noise, 1.0);
noise = mix(noise, 0.0, 0.3);
mist *= 1.0 - coord.y;
mist = clamp(mist, 0.0, 1.0);
gl_FragColor += mist;
}`;
class Rays extends PIXI.Filter
{
_options = {
angle: 30,
lacunarity: 1.5,
gain: 0.4,
parallel: Math.round(Math.random()),
speed: 0.0003
}
_timeInit = null;
constructor()
{
super(null, fragSource, uniformData);
this._timeInit = Date.now() - Math.floor(Math.random() * 99999999);
}
apply(filterManager, input, output, clearMode, _currentState)
{
this.uniforms.time = (Date.now() - this._timeInit) * this._options.speed;
this.uniforms.lacunarity = this._options.lacunarity;
this.uniforms.gain = this._options.gain;
this.uniforms.parallel = this._options.parallel;
const radians = this._options.angle * Math.PI / 180.0;
this.uniforms.light[0] = Math.cos(radians);
this.uniforms.light[1] = Math.sin(radians);
const {width, height} = input.filterFrame;
this.uniforms.dimensions[0] = width;
this.uniforms.dimensions[1] = height;
this.uniforms.aspect = height / width;
filterManager.applyFilter(this, input, output, clearMode);
}
}
// -------------------------------
class App
{
_app = null;
_resources = null;
constructor() {
this._app = new PIXI.Application({
view: canvas,
width: 800,
height: 600,
transparent: true,
resolution: window.devicePixelRatio
});
this._init();
}
addRelativeFeather(x, y) {
const feather = new PIXI.Sprite(this._resources.feather.texture);
const scale = Math.max(
this._app.screen.width / (feather.width * 3),
this._app.screen.height / (feather.height * 3)
);
feather.scale.set(scale, scale);
feather.position.set(x * feather.width, y * feather.height);
feather.filters = [new Rays()];
this._app.stage.addChild(feather);
}
_main() {
this.addRelativeFeather(0, 0);
this.addRelativeFeather(1, 0);
this.addRelativeFeather(2, 0);
this.addRelativeFeather(0, 1);
this.addRelativeFeather(2, 1);
}
_init() {
const loader = PIXI.Loader.shared;
loader.add({
name: 'feather',
// Icon "feather": https://www.flaticon.com/free-icon/feathers_6981026
url: 'https://cdn-icons-png.flaticon.com/512/6981/6981026.png',
});
loader.onComplete.once((loaderProcessed, resources) => {
this._resources = resources;
this._main();
});
loader.load();
}
}
const app = new App();
* {
margin: 0;
padding: 0;
background: #333;
}
<script src="https://pixijs.download/v6.5.8/pixi.js"></script>
<canvas id="canvas"></canvas>
Is it possible using this filter/shader? Is it correct that the issue is in the color matrix ("float noise(in vec3 p)")?
Also, it's probably the mist = clamp(mist, 0.0, 1.0); where the second parameter might assume the minimum allowed if that makes sense.
Would it be correct to somehow base a pixel color on the source and only increase its "gain" instead?
I would highly appreciate any suggestion since I have already tried various options but it still darkens the origin!
Best and kind regards ✨
const uniformData = {
time: {
type: 'float',
value: 0.0
},
lacunarity: {
type: 'float',
value: 30.0
},
gain: {
type: 'float',
value: 1.0
},
parallel: {
type: 'b',
value: true
},
light: {
type: 'v2',
value: [0.0, 0.0]
},
dimensions: {
type: 'v2',
value: [800, 400]
},
aspect: {
type: 'float',
value: 1.0
}
};
// 3D gradient Noise
// MIT License
// Copyright © 2013 Inigo Quilez
// https://www.shadertoy.com/view/Xsl3Dl
// Original: https://codepen.io/alaingalvan/pen/gOoEpW
const fragSource = '' +
`precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform vec4 filterArea;
uniform vec2 dimensions;
uniform vec2 light;
uniform bool parallel;
uniform float aspect;
uniform float gain;
uniform float lacunarity;
uniform float time;
vec3 hash(vec3 p) {
p = vec3(
dot(p, vec3(127.1, 311.7, 74.7)),
dot(p, vec3(269.5, 183.3, 246.1)),
dot(p, vec3(113.5, 271.9, 124.6))
);
return -1.0 + 2.0 * fract(sin(p) * 43758.5453123);
}
float noise(in vec3 p) {
vec3 i = floor(p);
vec3 f = fract(p);
vec3 u = f * f * (3.0 - 2.0 * f);
return mix(
mix(
mix(
dot(hash(i + vec3(0.0, 0.0, 0.0)), f - vec3(0.0, 0.0, 0.0)),
dot(hash(i + vec3(1.0, 0.0, 0.0)), f - vec3(1.0, 0.0, 0.0)),
u.x
),
mix(
dot(hash(i + vec3(0.0, 1.0, 0.0)), f - vec3(0.0, 1.0, 0.0)),
dot(hash(i + vec3(1.0, 1.0, 0.0)), f - vec3(1.0, 1.0, 0.0)),
u.x
),
u.y
),
mix(
mix(
dot(hash(i + vec3(0.0, 0.0, 1.0)), f - vec3(0.0, 0.0, 1.0)),
dot(hash(i + vec3(1.0, 0.0, 1.0)), f - vec3(1.0, 0.0, 1.0)),
u.x
),
mix(
dot(hash(i + vec3(0.0, 1.0, 1.0)), f - vec3(0.0, 1.0, 1.0)),
dot(hash(i + vec3(1.0, 1.0, 1.0)), f - vec3(1.0, 1.0, 1.0)),
u.x
),
u.y
),
u.z
);
}
float turb(vec3 pos, float lacunarity, float gain) {
float f, totalGain;
totalGain = gain;
vec3 q = 2.0 * pos;
f = totalGain * noise(q);
q = q * 2.01 * lacunarity;
totalGain *= gain;
f += totalGain * noise(q);
q = q * 3.02 * lacunarity;
totalGain *= gain;
f += totalGain * noise(q);
q = q * 3.03 * lacunarity;
totalGain *= gain;
f += totalGain * noise(q);
q = q * 3.01 * lacunarity;
totalGain *= gain;
f += totalGain * noise(q);
q = q * 3.99 * lacunarity;
totalGain *= gain;
f += totalGain * noise(q);
q = q * 3.98 * lacunarity;
totalGain *= gain;
f += totalGain * noise(q);
f = 3.0 * f;
return abs(f);
}
void main(void) {
gl_FragColor = texture2D(uSampler, vTextureCoord);
float d = 0.0;
vec2 coord = vTextureCoord;
if (parallel) {
float _cos = light.x;
float _sin = light.y;
d = (_cos * coord.x) + (_sin * coord.y * aspect);
} else {
float dx = coord.x - light.x / dimensions.x;
float dy = (coord.y - light.y / dimensions.y) * aspect;
float dis = sqrt(dx * dx + dy * dy) + 0.00001;
d = dy / dis;
}
vec2 dir = vec2(d, d);
float noise = turb(vec3(dir, 0.0) + vec3(time, 0.0, 62.1 + time) * 0.1, lacunarity, gain);
vec4 mist = vec4(noise, noise, noise, noise);
noise = mix(noise, 0.0, 0.3);
mist *= 1.0 - coord.y;
mist = clamp(mist, 0.0, 1.0);
gl_FragColor += mist;
}`;
class Rays extends PIXI.Filter
{
_options = {
angle: 30,
lacunarity: 1.5,
gain: 0.4,
parallel: Math.round(Math.random()),
speed: 0.0003
}
_timeInit = null;
constructor()
{
super(null, fragSource, uniformData);
this._timeInit = Date.now() - Math.floor(Math.random() * 99999999);
}
apply(filterManager, input, output, clearMode, _currentState)
{
this.uniforms.time = (Date.now() - this._timeInit) * this._options.speed;
this.uniforms.lacunarity = this._options.lacunarity;
this.uniforms.gain = this._options.gain;
this.uniforms.parallel = this._options.parallel;
const radians = this._options.angle * Math.PI / 180.0;
this.uniforms.light[0] = Math.cos(radians);
this.uniforms.light[1] = Math.sin(radians);
const {width, height} = input.filterFrame;
this.uniforms.dimensions[0] = width;
this.uniforms.dimensions[1] = height;
this.uniforms.aspect = height / width;
filterManager.applyFilter(this, input, output, clearMode);
}
}
// -------------------------------
class App
{
_app = null;
_resources = null;
constructor() {
this._app = new PIXI.Application({
view: canvas,
width: 800,
height: 600,
transparent: true,
resolution: window.devicePixelRatio
});
this._init();
}
addRelativeFeather(x, y) {
const feather = new PIXI.Sprite(this._resources.feather.texture);
const scale = Math.max(
this._app.screen.width / (feather.width * 3),
this._app.screen.height / (feather.height * 3)
);
feather.scale.set(scale, scale);
feather.position.set(x * feather.width, y * feather.height);
feather.filters = [new Rays()];
this._app.stage.addChild(feather);
}
_main() {
this.addRelativeFeather(0, 0);
this.addRelativeFeather(1, 0);
this.addRelativeFeather(2, 0);
this.addRelativeFeather(0, 1);
this.addRelativeFeather(2, 1);
}
_init() {
const loader = PIXI.Loader.shared;
loader.add({
name: 'feather',
// Icon "feather": https://www.flaticon.com/free-icon/feathers_6981026
url: 'https://cdn-icons-png.flaticon.com/512/6981/6981026.png',
});
loader.onComplete.once((loaderProcessed, resources) => {
this._resources = resources;
this._main();
});
loader.load();
}
}
const app = new App();
* {
margin: 0;
padding: 0;
background: #333;
}
<script src="https://pixijs.download/v6.5.8/pixi.js"></script>
<canvas id="canvas"></canvas>
The shader defines the following vec4 for painting with hardcoded 1.0 alpha:
vec4 mist = vec4(noise, noise, noise, 1.0);
Use the whiteness of the noise value as alpha as following to get rid of the black background:
vec4 mist = vec4(noise, noise, noise, noise);
I am relatily new to GLSL.
I want to create a solar system model and use it as a wallpaper (using shadertoy) (Something like this and while i have the planets moving correctly i cant figure out how to do the helix paths that follow those planets.
Here is my code so far
uniform vec2 iResolution;
uniform float iTime;
#define pi 3.141592653589
float circ(vec2 uv, vec2 pos, float rad, float blur) {
return smoothstep(blur, 0., length(-uv + pos)-rad); //draws a circle to the screen
}
float line(vec2 uv, vec3 start, vec3 end, float width) {
vec2 p = uv - start.xy;
vec2 d = end.xy - start.xy;
float l = length(d);
d = normalize(d); //direction
float t = clamp(dot(p, d), 0., l);
return (length(p - d*t)) < width ? 1 : 0.;
}
float helix(vec2 uv, vec3 start, vec3 direction, float width, float length, float angle) {
float delta = iTime / angle;
vec2 p = uv - start.xy;
vec2 d = (normalize(direction) * length).xy;
float l = length(d);
d /= l;
float t = clamp(dot(p, d), 0., l);
return (length(p - d*t)) < width ? 1 : 0.;
}
vec3 rotate(vec3 point, vec3 angle) {
mat3 rot = mat3(
cos(angle.y)*cos(angle.z), cos(angle.z)*sin(angle.x)*sin(angle.y)-cos(angle.x)*sin(angle.z), cos(angle.x)*cos(angle.z)*sin(angle.y)+sin(angle.x)*sin(angle.z),
cos(angle.y)*sin(angle.z), cos(angle.x)*cos(angle.z)+sin(angle.x)*sin(angle.y)*sin(angle.z), -cos(angle.z)*sin(angle.x)+cos(angle.x)*sin(angle.y)*sin(angle.z),
-sin(angle.y), cos(angle.y)*sin(angle.x), cos(angle.x)*cos(angle.y));
return rot * point;
}
void main() {
vec2 uv = fragCoord / iResolution.xy;
float ratio = iResolution.x / iResolution.y;
uv -= .5; //center origin
uv.x = uv.x * ratio;//make screen square
uv /= .3;//zoom
float planetA[5] = float[](0., iTime / 0.241, iTime / 0.6152, iTime, iTime / 1.8809);
vec3 planets[5] = vec3[](
vec3(0.), // sun
vec3(cos(planetA[1]) * .4, sin(planetA[1]) * .4, 0.), // mercury
vec3(cos(planetA[2]) * .7, sin(planetA[2]) * .7, 0.), // venus
vec3(cos(planetA[3]), sin(planetA[3]), 0.), // earth
vec3(cos(planetA[4])*1.5, sin(planetA[4])*1.5, 0.)// mars
);
vec3 planetsC[5] = vec3[](
vec3(0.89, 0.9, 0.45), // sun
vec3(0.54, 0.57, 0.63), // mercury
vec3(0.9, 0.5, 0.2), // venus
vec3(0.2, 0.3, 0.8), // earth
vec3(0.8, 0.3, 0.2)// mars
);
vec3 rotVec = vec3(-pi/4, pi/4, 0.);
fragColor = vec4(0.);
fragColor = mix(fragColor, vec4(1.), line(uv, vec3(0.), rotate(vec3(0., 0., 2.), rotVec), 0.01)); //sun trail
for (int i = 1; i < planets.length(); i++) {
planets[i] = rotate(planets[i], vec3(-pi/4., pi/4., 0.)); //rotate the planet
fragColor = mix(fragColor, vec4(planetsC[i], 1.), helix(uv, planets[i], rotate(vec3(0., 0., 2.), rotVec), 0.01, 2., planetA[i])); //planet trail
}
for (int i = 0; i < planets.length(); i++) { //draws the planets
fragColor = mix(fragColor, vec4(planetsC[i], 1.), circ(uv, planets[i].xy, 0.05, 0.01));
}
}
the helix function is currently only a modified version of the line method but i want it to curve around the suns trail.
Any advice and/or help would be appreciated as i am still learing.
I have tried to convert the helix equation:
x = r * cos(t) y = r * sin(t) z = t but havent gotten it to work
heres the method currently, although it only displays a straigt line:
float helix(vec2 uv, vec3 start, vec3 direction, float width, float length, float angle) {
float delta = iTime / angle;
vec2 p = uv - start.xy;
vec2 d = (normalize(direction) * length).xy;
float l = length(d);
d /= l;
float t = clamp(dot(p, d), 0., l);
return (length(p - d*t)) < width ? 1 : 0.;
}
I know have a many solve make effect for image. But i choice GPUImage (GPUImageLookupFilter) make my image.
My source code i use.
GPUImagePicture *sourceImagePic = [[GPUImagePicture alloc] initWithImage:sourceImage];
GPUImagePicture *lookupImageSource = [[GPUImagePicture alloc] initWithImage:[UIImage imageNamed:#"lookup.png"]];
GPUImageLookupFilter *lookupImageFilter = [[GPUImageLookupFilter alloc] init];
[sourceImagePic addTarget:lookupImageFilter];
[lookupImageSource addTarget:lookupImageFilter];
[lookupImageFilter useNextFrameForImageCapture];
[sourceImagePic processImage];
[lookupImageSource processImage];
resultImage = [lookupImageFilter imageFromCurrentFramebufferWithOrientation:UIImageOrientationUp];
return resultImage;
First i use lookup image 8x8 (5122)
But when i working with array image (thumb in video or choice many image in library) memory higher.
I think if i use small lookup image (4x4) memory can reduced. I make a lookup image 4x4(162).
And i try edit code of GPUImageLookupFilter but it not work.
void main(){
highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
highp float blueColor = textureColor.b * 63.0;
highp vec2 quad1;
quad1.y = floor(floor(blueColor) / 8.0);
quad1.x = floor(blueColor) - (quad1.y * 8.0);
highp vec2 quad2;
quad2.y = floor(ceil(blueColor) / 8.0);
quad2.x = ceil(blueColor) - (quad2.y * 8.0);
highp vec2 texPos1;
texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
highp vec2 texPos2;
texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
lowp vec4 newColor1 = texture2D(inputImageTexture2, texPos1);
lowp vec4 newColor2 = texture2D(inputImageTexture2, texPos2);
lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));
gl_FragColor = mix(textureColor, vec4(newColor.rgb, textureColor.w), intensity);
}
You can help me edit this code work with image 4x4.
Thank you!.
The following algorithm will work for any size of the lookup texture. You just have to adapt tiles to the number of the tiles in the x and y direction, and colTexSize to the full size of the color lookup texture.
The algorithm is identical to the original algorithm, except the constant size values, which have been replaced by the variables tiles and colTexSize.
void main()
{
vec2 tiles = vec2( 4.0, 4.0 ); // original texture vec2( 8.0, 8.0 )
vec2 colTexSize = vec2( 64.0, 64.0 ) // original texture vec2( 512.0, 512.0 )
highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
highp float blueColor = textureColor.b * ((tiles.x*tiles.y)-1.0);
highp vec2 quad1;
quad1.y = floor(floor(blueColor) / tiles.y);
quad1.x = floor(blueColor) - (quad1.y * tiles.x);
highp vec2 quad2;
quad2.y = floor(ceil(blueColor) / tiles.y);
quad2.x = ceil(blueColor) - (quad2.y * tiles.x);
highp vec2 texPos1;
texPos1.x = (quad1.x / tiles.x) + 0.5/colTexSize.x + (1.0/(tiles.x - colTexSize.x) * textureColor.r);
texPos1.y = (quad1.y / tiles.y) + 0.5/colTexSize.y + (1.0/(tiles.y - colTexSize.y) * textureColor.g);
highp vec2 texPos2;
texPos2.x = (quad2.x / tiles.x) + 0.5/colTexSize.x + (1.0/(tiles.x - colTexSize.x) * textureColor.r);
texPos2.y = (quad2.y / tiles.y) + 0.5/colTexSize.y + (1.0/(tiles.y - colTexSize.y) * textureColor.g);
lowp vec4 newColor1 = texture2D(inputImageTexture2, texPos1);
lowp vec4 newColor2 = texture2D(inputImageTexture2, texPos2);
lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));
gl_FragColor = mix(textureColor, vec4(newColor.rgb, textureColor.w), intensity);
}