Porting ShaderToy to THREE.JS issue - three.js

I'm trying to port this shader https://www.shadertoy.com/view/MsB3WR to
THREE.JS and actually it's almost there, but I have an issue with UV mapping,
so by now have something like this:
SHADER CODE:
vertexShader:
void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }
fragmentShader:
//mouse.z - left click
//mouse.w - right click
//texture A > iChannel0 > assets/textureA.png
//texture B > iChannel1 > assets/textureB.png
//texture C > iChannel2 > assets/textureC.png
#define BUMPFACTOR 0.1
#define EPSILON 0.1
#define BUMPDISTANCE 60.
//(iGlobalTime + 285.)
uniform float time;
uniform sampler2D textureA;
uniform sampler2D textureB;
uniform sampler2D textureC;
uniform vec2 resolution;
uniform vec3 mouse;
mat2 rot(const in float a) { return mat2(cos(a), sin(a), -sin(a), cos(a)); }
const mat2 m2 = mat2( 0.60, -0.80, 0.80, 0.60 );
const mat3 m3 = mat3( 0.00, 0.80, 0.60, -0.80, 0.36, -0.48, -0.60, -0.48, 0.64 );
float noise( const in vec2 x ) {
vec2 p = floor(x);
vec2 f = fract(x);
f = f * f * (3.0 - 2.0 * f);
vec2 uv = (p.xy) + f.xy;
return texture2D( textureA, (uv + 0.5) / 256.0, 0.0 ).x;
}
float noise( const in vec3 x ) {
vec3 p = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
vec2 uv = (p.xy + vec2(37.0, 17.0) * p.z) + f.xy;
vec2 rg = texture2D( textureA, (uv + 0.5) / 256.0, 0.0 ).yx;
return mix( rg.x, rg.y, f.z );
}
float fbm( in vec3 p ) {
float f = 0.0;
f += 0.5000 * noise(p); p = m3 * p * 2.02;
f += 0.2500 * noise(p); p = m3 * p * 2.03;
f += 0.1250 * noise(p); p = m3 * p * 2.01;
f += 0.0625 * noise(p);
return f / 0.9375;
}
float hash( in float n ) { return fract(sin(n) * 43758.5453); }
//INTERSECTION FUNCTION
bool intersectPlane(const in vec3 ro, const in vec3 rd, const in float height, inout float dist) {
if (rd.y == 0.0) { return false; }
float d = -(ro.y - height)/rd.y;
d = min(100000.0, d);
if( d > 0. && d < dist ) {
dist = d;
return true;
}
return false;
}
//LIGHT DIRECTION
vec3 lig = normalize(vec3( 0.3, 0.5, 0.6));
vec3 bgColor( const in vec3 rd ) {
float sun = clamp( dot(lig, rd), 0.0, 1.0 );
vec3 col = vec3(0.5, 0.52, 0.55) - rd.y * 0.2 * vec3(1.0, 0.8, 1.0) + 0.15 * 0.75;
col += vec3(1.0, 0.6, 0.1) * pow( sun, 8.0 );
col *= 0.95;
return col;
}
//CLOUDS
#define CLOUDSCALE (500. / (64. * 0.03))
float cloudMap( const in vec3 p, const in float ani ) {
vec3 r = p / CLOUDSCALE;
float den = -1.8 + cos(r.y * 5.-4.3);
float f;
vec3 q = 2.5 * r * vec3(0.75, 1.0, 0.75) + vec3(1.0, 1.0, 15.0) * ani * 0.15;
f = 0.50000 * noise(q); q = q * 2.02 - vec3(-1.0,1.0,-1.0) * ani * 0.15;
f += 0.25000 * noise(q); q = q * 2.03 + vec3(1.0, -1.0, 1.0) * ani * 0.15;
f += 0.12500 * noise(q); q = q * 2.01 - vec3(1.0, 1.0, -1.0) * ani * 0.15;
f += 0.06250 * noise(q); q = q * 2.02 + vec3(1.0, 1.0, 1.0) * ani * 0.15;
f += 0.03125 * noise(q);
return 0.065 * clamp( den + 4.4 * f, 0.0, 1.0 );
}
vec3 raymarchClouds( const in vec3 ro, const in vec3 rd, const in vec3 bgc, const in vec3 fgc, const in float startdist, const in float maxdist, const in float ani ) {
float t = startdist + CLOUDSCALE * 0.02 * hash(rd.x + 35.6987221 * rd.y + time);
vec4 sum = vec4( 0.0 );
for( int i=0; i<64; i++ ) {
if( sum.a > 0.99 || t > maxdist ) continue;
vec3 pos = ro + t*rd;
float a = cloudMap( pos, ani );
float dif = clamp(0.1 + 0.8*(a - cloudMap( pos + lig*0.15*CLOUDSCALE, ani )), 0., 0.5);
vec4 col = vec4( (1.+dif)*fgc, a );
col.rgb *= col.a;
sum = sum + col*(1.0 - sum.a);
t += (0.03*CLOUDSCALE)+t*0.012;
}
sum.xyz = mix( bgc, sum.xyz/(sum.w+0.0001), sum.w );
return clamp( sum.xyz, 0.0, 1.0 );
}
//TERRAIN
float terrainMap( const in vec3 p ) {
return (texture2D( textureB, (-p.zx*m2)*0.000046, 0. ).x*600.) * smoothstep( 820., 1000., length(p.xz) ) - 2. + noise(p.xz*0.5)*15.;
}
vec3 raymarchTerrain( const in vec3 ro, const in vec3 rd, const in vec3 bgc, const in float startdist, inout float dist ) {
float t = startdist;
vec4 sum = vec4( 0.0 );
bool hit = false;
vec3 col = bgc;
for( int i=0; i<80; i++ ) {
if( hit ) break;
t += 8. + t/300.;
vec3 pos = ro + t*rd;
if( pos.y < terrainMap(pos) ) {
hit = true;
}
}
if( hit ) {
float dt = 4.+t/400.;
t -= dt;
vec3 pos = ro + t*rd;
t += (0.5 - step( pos.y , terrainMap(pos) )) * dt;
for( int j=0; j<2; j++ ) {
pos = ro + t*rd;
dt *= 0.5;
t += (0.5 - step( pos.y , terrainMap(pos) )) * dt;
}
pos = ro + t*rd;
vec3 dx = vec3( 100.*EPSILON, 0., 0. );
vec3 dz = vec3( 0., 0., 100.*EPSILON );
vec3 normal = vec3( 0., 0., 0. );
normal.x = (terrainMap(pos + dx) - terrainMap(pos-dx) ) / (200. * EPSILON);
normal.z = (terrainMap(pos + dz) - terrainMap(pos-dz) ) / (200. * EPSILON);
normal.y = 1.;
normal = normalize( normal );
col = vec3(0.2) + 0.7 * texture2D( textureC , pos.xz * 0.01 ).xyz *
vec3(1.0, 0.9, 0.6);
float veg = 0.3*fbm(pos*0.2)+normal.y;
if( veg > 0.75 ) {
col = vec3( 0.45, 0.6, 0.3 )*(0.5+0.5*fbm(pos*0.5))*0.6;
} else
if( veg > 0.66 ) {
col = col*0.6+vec3( 0.4, 0.5, 0.3 )*(0.5+0.5*fbm(pos*0.25))*0.3;
}
col *= vec3(0.5, 0.52, 0.65)*vec3(1.,.9,0.8);
vec3 brdf = col;
float diff = clamp( dot( normal, -lig ), 0., 1.);
col = brdf*diff*vec3(1.0,.6,0.1);
col += brdf*clamp( dot( normal, lig ), 0., 1.)*vec3(0.8,.6,0.5)*0.8;
col += brdf*clamp( dot( normal, vec3(0.,1.,0.) ), 0., 1.)*vec3(0.8,.8,1.)*0.2;
dist = t;
t -= pos.y*3.5;
col = mix( col, bgc, 1.0-exp(-0.0000005*t*t) );
}
return col;
}
float waterMap( vec2 pos ) { vec2 posm = pos * m2; return abs( fbm( vec3( 8. * posm, time ))-0.5 ) * 0.1; }
void main(void)
{
vec2 q = gl_FragCoord.xy / resolution.xy;
vec2 p = -1.0 + 2.0 * q;
p.x *= resolution.x / resolution.y;
vec3 ro = vec3(0.0, 0.5, 0.0);
vec3 ta = vec3(0.0, 0.45,1.0);
if (mouse.z >= 1.0) { ta.xz *= rot( (mouse.x / resolution.x - 0.5) * 7.0 ); }
ta.xz *= rot( mod(time * 0.05, 6.2831852) );
vec3 ww = normalize( ta - ro);
vec3 uu = normalize(cross( vec3(0.0,1.0,0.0), ww ));
vec3 vv = normalize(cross(ww,uu));
vec3 rd = normalize( p.x*uu + p.y*vv + 2.5*ww );
float fresnel, refldist = 5000., maxdist = 5000.;
bool reflected = false;
vec3 normal, col = bgColor( rd );
vec3 roo = ro, rdo = rd, bgc = col;
if( intersectPlane( ro, rd, 0., refldist ) && refldist < 200. ) {
ro += refldist*rd;
vec2 coord = ro.xz;
float bumpfactor = BUMPFACTOR * (1. - smoothstep( 0., BUMPDISTANCE, refldist) );
vec2 dx = vec2( EPSILON, 0. );
vec2 dz = vec2( 0., EPSILON );
normal = vec3( 0., 1., 0. );
normal.x = -bumpfactor * (waterMap(coord + dx) - waterMap(coord-dx) ) / (2. * EPSILON);
normal.z = -bumpfactor * (waterMap(coord + dz) - waterMap(coord-dz) ) / (2. * EPSILON);
normal = normalize( normal );
float ndotr = dot(normal,rd);
fresnel = pow(1.0-abs(ndotr),5.);
rd = reflect( rd, normal);
reflected = true;
bgc = col = bgColor( rd );
}
col = raymarchTerrain( ro, rd, col, reflected?(800.-refldist):800., maxdist );
col = raymarchClouds( ro, rd, col, bgc, reflected?max(0.,min(150.,(150.-refldist))):150., maxdist, time*0.05 );
if( reflected ) {
col = mix( col.xyz, bgc, 1.0-exp(-0.0000005 *refldist * refldist) );
col *= fresnel * 0.9;
vec3 refr = refract( rdo, normal, 1./1.3330 );
intersectPlane( ro, refr, -2., refldist );
col += mix( texture2D( textureC, (roo+refldist*refr).xz*1.3 ).xyz * vec3(1.0, 0.9, 0.6), vec3(1.0, 0.9, 0.8)*0.5, clamp( refldist / 3.0, 0.0, 1.0) ) * (1.-fresnel)*0.125;
}
col = pow( col, vec3(0.7) );
col = col * col * (3.0-2.0 * col);
col = mix( col, vec3(dot(col,vec3(0.33))), -0.5 );
col *= 0.25 + 0.75*pow( 16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.1 );
//vec4 color = texture2D( textureA, vUv );
gl_FragColor = vec4( col, 1.0 );
}
And JavaScript [initialising]:
clock = new THREE.Clock();
mouse = new THREE.Vector4();
var loaderA = new THREE.TextureLoader();
var bitmapA = loaderA.load("assets/textureA.png");
var loaderB = new THREE.TextureLoader();
var bitmapB = loaderB.load("assets/textureB.png");
var loaderC = new THREE.TextureLoader();
var bitmapC = loaderC.load("assets/textureC.png");
var uniforms = {
textureA: { type: 't', value: bitmapA },
textureB: { type: 't', value: bitmapB },
textureC: { type: 't', value: bitmapC },
time: {
type: 'f',
value: clock.getDelta() + 285.
},
resolution: {
type: 'v2',
value: new THREE.Vector2( window.innerWidth, window.innerHeight)
},
mouse: {
type: 'v4',
value: new THREE.Vector4(window.innerWidth / 2, window.innerHeight / 2, 0.0, 0.0)
}
};
var glslMat = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: document.getElementById("vertexShader").textContent,
fragmentShader: document.getElementById("fragmentShader").textContent
} );
var geometry = new THREE.PlaneGeometry(window.innerWidth * 4 , window.innerHeight * 4, 1, 1);
var plane = new THREE.Mesh(geometry, glslMat);
Any suggestions?

The issue was solved by implementing texture wrapping and its sampling
var loaderA = new THREE.TextureLoader();
var bitmapA = loaderA.load( 'assets/originalRGBA.png', function ( texture ) {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.offset.set( 0, 0 );
texture.repeat.set( 2, 2 );
} );

Related

three.js WebGL: INVALID_OPERATION: drawElements: no valid shader program in use

My three.js version is v-125, the code blew is initializing and rendering the ShaderMaterial on six PlaneGeometry, it is modified from the code in version 88.
This is the shaders 's code.
import noise from 'glsl-noise/classic/3d';
varying vec2 vUv;
uniform int index;
uniform float seed;
uniform float resolution;
uniform float res1;
uniform float res2;
uniform float resMix;
uniform float mixScale;
uniform float doesRidged;
const int octaves = 16;
// #define M_PI 3.1415926535897932384626433832795;
vec3 getSphericalCoord(int index, float x, float y, float width) {
width /= 2.0;
x -= width;
y -= width;
vec3 coord = vec3(0.0, 0.0, 0.0);
if (index == 0) {coord.x=width; coord.y=-y; coord.z=-x;}
else if (index == 1) {coord.x=-width; coord.y=-y; coord.z=x;}
else if (index == 2) {coord.x=x; coord.y=width; coord.z=y;}
else if (index == 3) {coord.x=x; coord.y=-width; coord.z=-y;}
else if (index == 4) {coord.x=x; coord.y=-y; coord.z=width;}
else if (index == 5) {coord.x=-x; coord.y=-y; coord.z=-width;}
return normalize(coord);
}
float simplexRidged(vec3 pos, float seed) {
float n = noise(vec3(pos + seed));
n = (n + 1.0) * 0.5;
n = 2.0 * (0.5 - abs(0.5 - n));
return n;
}
float simplex(vec3 pos, float seed) {
float n = noise(vec3(pos + seed));
return (n + 1.0) * 0.5;
}
float baseNoise(vec3 pos, float frq, float seed ) {
float amp = 0.5;
float n = 0.0;
float gain = 1.0;
for(int i=0; i<octaves; i++) {
n += simplex(vec3(pos.x*gain/frq, pos.y*gain/frq, pos.z*gain/frq), seed+float(i)*10.0) * amp/gain;
gain *= 2.0;
}
// increase contrast
n = ( (n - 0.5) * 2.0 ) + 0.5;
return n;
}
float ridgedNoise(vec3 pos, float frq, float seed) {
float amp = 0.5;
float n = 0.0;
float gain = 1.0;
for(int i=0; i<octaves; i++) {
n += simplexRidged(vec3(pos.x*gain/frq, pos.y*gain/frq, pos.z*gain/frq), seed+float(i)*10.0) * amp/gain;
gain *= 2.0;
}
n = pow(n, 4.0);
return n;
}
float invRidgedNoise(vec3 pos, float frq, float seed) {
float amp = 0.5;
float n = 0.0;
float gain = 1.0;
for(int i=0; i<octaves; i++) {
n += simplexRidged(vec3(pos.x*gain/frq, pos.y*gain/frq, pos.z*gain/frq), seed+float(i)*10.0) * amp/gain;
gain *= 2.0;
}
n = pow(n, 4.0);
n = 1.0 - n;
return n;
}
float cloud(vec3 pos, float seed) {
float n = noise(vec3(pos + seed));
// n = sin(n*4.0 * cos(n*2.0));
n = sin(n*5.0);
// n = abs(sin(n*5.0));
// n = 1.0 - n;
n = n*0.5 + 0.5;
// n = 1.0-n;
// n = n*1.2;
// n = 1.0-n;
return n;
}
float cloudNoise(vec3 pos, float frq, float seed) {
float amp = 0.5;
float n = 0.0;
float gain = 1.0;
for(int i=0; i<octaves; i++) {
n += cloud(vec3(pos.x*gain/frq, pos.y*gain/frq, pos.z*gain/frq), seed+float(i)*10.0) * amp/gain;
gain *= 2.0;
}
// n = pow(n, 5.0);
n = 1.0-n;
n = pow(n, 1.0);
n = 1.0-n;
return n;
}
void main() {
float x = vUv.x;
float y = 1.0 - vUv.y;
vec3 sphericalCoord = getSphericalCoord(index, x*resolution, y*resolution, resolution);
float sub1, sub2, sub3, n;
float resMod = 1.0; // overall res magnification
float resMod2 = mixScale; // minimum res mod
if (doesRidged == 0.0) {
sub1 = cloudNoise(sphericalCoord, res1*resMod, seed+11.437);
sub2 = cloudNoise(sphericalCoord, res2*resMod, seed+93.483);
sub3 = cloudNoise(sphericalCoord, resMix*resMod, seed+23.675);
n = cloudNoise(sphericalCoord + vec3((sub1/sub3)*0.1), resMod2+sub2, seed+78.236);
}
else if (doesRidged == 1.0) {
sub1 = ridgedNoise(sphericalCoord, res1*resMod, seed+83.706);
sub2 = ridgedNoise(sphericalCoord, res2*resMod, seed+29.358);
sub3 = ridgedNoise(sphericalCoord, resMix*resMod, seed+53.041);
n = ridgedNoise(sphericalCoord + vec3((sub1/sub3)*0.1), resMod2+sub2, seed+34.982);
}
else if (doesRidged == 2.0) {
sub1 = invRidgedNoise(sphericalCoord, res1*resMod, seed+49.684);
sub2 = invRidgedNoise(sphericalCoord, res2*resMod, seed+136.276);
sub3 = invRidgedNoise(sphericalCoord, resMix*resMod, seed+3.587);
n = invRidgedNoise(sphericalCoord + vec3((sub1/sub3)*0.1), resMod2+sub2, seed+33.321);
}
else {
sub1 = baseNoise(sphericalCoord, res1*resMod, seed+52.284);
sub2 = baseNoise(sphericalCoord, res2*resMod, seed+137.863);
sub3 = baseNoise(sphericalCoord, resMix*resMod, seed+37.241);
float alpha = sub1*3.14*2.0;
float beta = sub2*3.14*2.0;
float fx = cos(alpha)*cos(beta);
float fz = sin(alpha)*cos(beta);
float fy = sin(beta);
n = baseNoise(sphericalCoord + (vec3(fx,fy,fz) * sub3), 1.0, seed+28.634);
}
gl_FragColor = vec4(vec3(n), 1.0);
}
This is the code to apply shader to the
import * as THREE from 'three'
import fragShader from './flowNoiseMap.frag'
import seedrandom from 'seedrandom';
class NoiseMap
{
constructor() {
window.rng = seedrandom('adfadfadf');
this.setupMaterial();
this.setupPlane();
let resMin = 0.01;
let resMax = 5.0;
this.resolution = 1024;
this.seed = this.randRange(0, 1) * 1000.0;
this.render({
seed: this.seed,
resolution: this.resolution,
res1: this.randRange(resMin, resMax),
res2: this.randRange(resMin, resMax),
resMix: this.randRange(resMin, resMax),
mixScale: this.randRange(0.5, 1.0),
doesRidged: Math.floor(this.randRange(0, 4))
});
}
setupPlane() {
this.maps = [];
this.textures = [];
this.textureCameras = [];
this.textureScenes = [];
this.planes = [];
this.geos = [];
for (let i = 0; i < 6; i++) {
let tempRes = 1000;
this.textures[i] = new THREE.WebGLRenderTarget(tempRes, tempRes, {minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat});
this.textureCameras[i] = new THREE.OrthographicCamera(-tempRes/2, tempRes/2, tempRes/2, -tempRes/2, -100, 100);
this.textureCameras[i].position.z = 10;
this.textureScenes[i] = new THREE.Scene();
this.geos[i] = new THREE.PlaneGeometry(1, 1);
this.planes[i] = new THREE.Mesh(this.geos[i], this.mats[i]);
this.planes[i].position.z = -10;
this.textureScenes[i].add(this.planes[i]);
//window.renderer.render(textureScene, textureCamera);
this.maps.push(this.textures[i].texture);
}
}
setup() {
this.mats = [];
for (let i = 0; i < 6; i++) {
this.mats[i] = new THREE.ShaderMaterial({
uniforms: {
index: {type: "i", value: i},
seed: {type: "f", value: 0},
resolution: {type: "f", value: 0},
res1: {type: "f", value: 0},
res2: {type: "f", value: 0},
resMix: {type: "f", value: 0},
mixScale: {type: "f", value: 0},
doesRidged: {type: "f", value: 0}
},
vertexShader: vertShader,
fragmentShader: fragShader,
transparent: true,
depthWrite: false
});
}
}
render(props) {
let resolution = props.resolution;
for (let i = 0; i < 6; i++) {
this.mats[i].uniforms.seed.value = props.seed;
this.mats[i].uniforms.resolution.value = props.resolution;
this.mats[i].uniforms.res1.value = props.res1;
this.mats[i].uniforms.res2.value = props.res2;
this.mats[i].uniforms.resMix.value = props.resMix;
this.mats[i].uniforms.mixScale.value = props.mixScale;
this.mats[i].uniforms.doesRidged.value = props.doesRidged;
this.mats[i].needsUpdat = true;
}
this.renderMaterial(props)
}
renderMaterial(props) {
let resolution = props.resolution;
console.log('map render')
for (let i = 0; i < 6; i++) {
this.textures[i].setSize(resolution, resolution);
this.textures[i].needsUpdate = true;
this.textureCameras[i].left = -resolution/2;
this.textureCameras[i].right = resolution/2;
this.textureCameras[i].top = resolution/2;
this.textureCameras[i].bottom = -resolution/2;
this.textureCameras[i].updateProjectionMatrix();
this.geos[i] = new THREE.PlaneGeometry(resolution, resolution);
this.planes[i].geometry = this.geos[i];
window.renderer.render(this.textureScenes[i], this.textureCameras[i]);
this.geos[i].dispose();
}
}
randRange(low, high) {
let range = high - low;
let n = window.rng() * range;
return low + n;
}
}
new NoiseMap();
Running the code gave me the error
three.module.js?3179:19503 WebGL: INVALID_OPERATION: useProgram: program not valid
useProgram # three.module.js?3179:19503
setProgram # three.module.js?3179:24390
WebGLRenderer.renderBufferDirect # three.module.js?3179:23631
WebGL: INVALID_OPERATION: drawElements: no valid shader program in use
three.module.js?3179:17081 THREE.WebGLProgram: shader error: 0 35715 false gl.getProgramInfoLog invalid shaders THREE.WebGLShader: gl.getShaderInfoLog() fragment
ERROR: 0:89: 'import' : syntax error
1: #version 300 es
2: #define varying in
3: out highp vec4 pc_fragColor;
4: #define gl_FragColor pc_fragColor
5: #define gl_FragDepthEXT gl_FragDepth
6: #define texture2D texture
7: #define textureCube texture
8: #define texture2DProj textureProj
9: #define texture2DLodEXT textureLod
10: #define texture2DProjLodEXT textureProjLod
11: #define textureCubeLodEXT textureLod
12: #define texture2DGradEXT textureGrad
13: #define texture2DProjGradEXT textureProjGrad
14: #define textureCubeGradEXT textureGrad
15: precision highp float;
16: precision highp int;
17: #define HIGH_PRECISION
18: #define SHADER_NAME ShaderMaterial
19: #define GAMMA_FACTOR 2
20: uniform mat4 viewMatrix;
21: uniform vec3 cameraPosition;
22: uniform bool isOrthographic;
23:
24: vec4 LinearToLinear( in vec4 value ) {
25: return value;
26: }
27: vec4 GammaToLinear( in vec4 value, in float gammaFactor ) {
28: return vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );
29: }
30: vec4 LinearToGamma( in vec4 value, in float gammaFactor ) {
31: return vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );
32: }
33: vec4 sRGBToLinear( in vec4 value ) {
34: return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );
35: }
36: vec4 LinearTosRGB( in vec4 value ) {
37: return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );
38: }
39: vec4 RGBEToLinear( in vec4 value ) {
40: return vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );
41: }
42: vec4 LinearToRGBE( in vec4 value ) {
43: float maxComponent = max( max( value.r, value.g ), value.b );
44: float fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );
45: return vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );
46: }
47: vec4 RGBMToLinear( in vec4 value, in float maxRange ) {
48: return vec4( value.rgb * value.a * maxRange, 1.0 );
49: }
50: vec4 LinearToRGBM( in vec4 value, in float maxRange ) {
51: float maxRGB = max( value.r, max( value.g, value.b ) );
52: float M = clamp( maxRGB / maxRange, 0.0, 1.0 );
53: M = ceil( M * 255.0 ) / 255.0;
54: return vec4( value.rgb / ( M * maxRange ), M );
55: }
56: vec4 RGBDToLinear( in vec4 value, in float maxRange ) {
57: return vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );
58: }
59: vec4 LinearToRGBD( in vec4 value, in float maxRange ) {
60: float maxRGB = max( value.r, max( value.g, value.b ) );
61: float D = max( maxRange / maxRGB, 1.0 );
62: D = clamp( floor( D ) / 255.0, 0.0, 1.0 );
63: return vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );
64: }
65: const mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );
66: vec4 LinearToLogLuv( in vec4 value ) {
67: vec3 Xp_Y_XYZp = cLogLuvM * value.rgb;
68: Xp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );
69: vec4 vResult;
70: vResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;
71: float Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;
72: vResult.w = fract( Le );
73: vResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;
74: return vResult;
75: }
76: const mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );
77: vec4 LogLuvToLinear( in vec4 value ) {
78: float Le = value.z * 255.0 + value.w;
79: vec3 Xp_Y_XYZp;
80: Xp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );
81: Xp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;
82: Xp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;
83: vec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb;
84: return vec4( max( vRGB, 0.0 ), 1.0 );
85: }
86: vec4 linearToOutputTexel( vec4 value ) { return LinearToLinear( value ); }
87:
88: #define GLSLIFY 1
89: import noise from 'glsl-noise/classic/3d'
90:
91: varying vec2 vUv;
92: uniform int index;
93: uniform float seed;
94: uniform float resolution;
95: uniform float res1;
96: uniform float res2;
97: uniform float resMix;
98: uniform float mixScale;
99: uniform float doesRidged;
100: const int octaves = 16;
101:
102: // #define M_PI 3.1415926535897932384626433832795;
103:
104: vec3 getSphericalCoord(int index, float x, float y, float width) {
105: width /= 2.0;
106: x -= width;
107: y -= width;
108: vec3 coord = vec3(0.0, 0.0, 0.0);
109:
110: if (index == 0) {coord.x=width; coord.y=-y; coord.z=-x;}
111: else if (index == 1) {coord.x=-width; coord.y=-y; coord.z=x;}
112: else if (index == 2) {coord.x=x; coord.y=width; coord.z=y;}
113: else if (index == 3) {coord.x=x; coord.y=-width; coord.z=-y;}
114: else if (index == 4) {coord.x=x; coord.y=-y; coord.z=width;}
115: else if (index == 5) {coord.x=-x; coord.y=-y; coord.z=-width;}
116:
117: return normalize(coord);
118: }
119: ..................
what is wrong with this shader code, as it is used to work in version 88
You have this line in your compiled shader:
import noise from 'glsl-noise/classic/3d';
This is no valid GLSL. It seems you are missing a step in you build that resolves the import and injects the code from glsl-noise/classic/3d into your shader.

Three.js ShaderMaterial Post Processing and Transparent Background

I'm trying to work with this shader, but I need a transparent background and it renders a black background.
I realized that this is done within the fragmentShader, but I haven't figured out how to change it, and I don't even know if it's possible.
Would anyone with experience in shaders know how to tell me?
var myEffect = {
uniforms: {
"tDiffuse": { value: null },
"distort": { value: 0 },
"resolution": { value: new THREE.Vector2(1., innerHeight / innerWidth) },
"uMouse": { value: new THREE.Vector2(-10, -10) },
"uVelo": { value: 0 },
"time": { value: 0 }
},
vertexShader: `uniform float time;
uniform float progress;
uniform vec2 resolution;
varying vec2 vUv;
uniform sampler2D texture1;
const float pi = 3.1415925;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );
}`,
fragmentShader: `uniform float time;
uniform float progress;
uniform sampler2D tDiffuse;
uniform vec2 resolution;
varying vec2 vUv;
uniform vec2 uMouse;
uniform float uVelo;
float circle(vec2 uv, vec2 disc_center, float disc_radius, float border_size) {
uv -= disc_center;
uv*=resolution;
float dist = sqrt(dot(uv, uv));
return smoothstep(disc_radius+border_size, disc_radius-border_size, dist);
}
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
float remap(float value, float inMin, float inMax, float outMin, float outMax) {
return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
}
float hash12(vec2 p) {
float h = dot(p,vec2(127.1,311.7));
return fract(sin(h)*43758.5453123);
}
// #define HASHSCALE3 vec3(.1031, .1030, .0973)
vec2 hash2d(vec2 p)
{
vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
p3 += dot(p3, p3.yzx+19.19);
return fract((p3.xx+p3.yz)*p3.zy);
}
void main() {
vec2 newUV = vUv;
vec4 color = vec4(1.,0.,0.,1.);
float c = circle(newUV, uMouse, 0.0, 0.2);
float r = texture2D(tDiffuse, newUV.xy += c * (uVelo * .5)).x;
float g = texture2D(tDiffuse, newUV.xy += c * (uVelo * .525)).y;
float b = texture2D(tDiffuse, newUV.xy += c * (uVelo * .55)).z;
color = vec4(r, g, b, 1.);
gl_FragColor = color;
}`
}
Well, assuming you set up three.js for transparency then my guess is
the last part
void main() {
vec2 newUV = vUv;
vec4 color = vec4(1.,0.,0.,1.);
float c = circle(newUV, uMouse, 0.0, 0.2);
float r = texture2D(tDiffuse, newUV.xy += c * (uVelo * .5)).x;
float g = texture2D(tDiffuse, newUV.xy += c * (uVelo * .525)).y;
float b = texture2D(tDiffuse, newUV.xy += c * (uVelo * .55)).z;
float a = texture2D(tDiffuse, newUV.xy += c * (uVelo * .525)).w; // added
color = vec4(r, g, b, a); // changed
gl_FragColor = color;
}`
This might also work better
vec4 c1 = texture2D(tDiffuse, newUV.xy += c * (0.1 * .5));
vec4 c2 = texture2D(tDiffuse, newUV.xy += c * (0.1 * .525));
vec4 c3 = texture2D(tDiffuse, newUV.xy += c * (0.1 * .55));
float a = min(min(c1.a, c2.a), c3.a);
vec4 color = vec4(c1.r, c2.g, c3.b, a);
gl_FragColor = color;
You maybe also need to premultiply the alpha
gl_FragColor = color;
gl_FragColor.rgb *= gl_FragColor.a;
Thanks #gman, you helped me understand the algorithm. I solved it as follows.
void main() {
vec2 newUV = vUv;
float c = circle(newUV, uMouse, 0.0, 0.2);
float a = texture2D(tDiffuse, newUV.xy+c*(uVelo)).w; //added
float r = texture2D(tDiffuse, newUV.xy += c * (uVelo * .5)).x;
float g = texture2D(tDiffuse, newUV.xy += c * (uVelo * .525)).y;
float b = texture2D(tDiffuse, newUV.xy += c * (uVelo * .55)).z;
vec4 color = vec4(r, g, b, r+g+b+a); //changed
gl_FragColor = color;
}

What is this called and how to achieve! Visuals in processing

Hey does anyone know how to achieve this effect using processing or what this is called?
I have been trying to use the wave gradient example in the processing library and implementing Perlin noise but I can not get close to the gif quality.
I know the artist used processing but can not figure out how!
Link to gif:
https://giphy.com/gifs/processing-jodeus-QInYLzY33wMwM
The effect is reminescent of Op Art (optical illusion art): I recommend reading/learning more about this fascinating genre and artists like:
Bridget Riley
(Bridget Riley, Intake, 1964)
(Bridget Riley, Hesistate, 1964,
Copyright: (c) Bridget Riley 2018. All rights reserved. / Photo (c) Tate)
Victor Vasarely
(Victor Vasarely, Zebra Couple)
(Victor Vasarely, VegaII)
Frank Stella
(Frank Stella, Untitled 1965, Image curtesy of Art Gallery NSW)
and more
You notice this waves are reminiscent/heavily inspired by Bridget Riley's work.
I also recommend checking out San Charoenchai;s album visualiser for Beach House - 7
As mentioned in my comment: you should post your attempt.
Waves and perlin noise could work for sure.
There are many ways to achieve a similar look.
Here's tweaked version of Daniel Shiffman's Noise Wave example:
int numWaves = 24;
float[] yoff = new float[numWaves]; // 2nd dimension of perlin noise
float[] yoffIncrements = new float[numWaves];
void setup() {
size(640, 360);
noStroke();
for(int i = 0 ; i < numWaves; i++){
yoffIncrements[i] = map(i, 0, numWaves - 1, 0.01, 0.03);
}
}
void draw() {
background(0);
float waveHeight = height / numWaves;
for(int i = 0 ; i < numWaves; i++){
float waveY = i * waveHeight;
fill(i % 2 == 0 ? color(255) : color(0));
// We are going to draw a polygon out of the wave points
beginShape();
float xoff = 0; // Option #1: 2D Noise
// float xoff = yoff; // Option #2: 1D Noise
// Iterate over horizontal pixels
for (float x = 0; x <= width + 30; x += 20) {
// Calculate a y value according to noise, map to
float y = map(noise(xoff, yoff[i]), 0, 1, waveY , waveY + (waveHeight * 3)); // Option #1: 2D Noise
// float y = map(noise(xoff), 0, 1, 200,300); // Option #2: 1D Noise
// Set the vertex
vertex(x, y);
// Increment x dimension for noise
xoff += 0.05;
}
// increment y dimension for noise
yoff[i] += yoffIncrements[i];
vertex(width, height);
vertex(0, height);
endShape(CLOSE);
}
}
Notice the quality of the noise wave in comparison to the image you're trying to emulate: there is a constant rhythm to it. To me that is a hint that it's using cycling sine waves changing phase and amplitude (potentially even adding waves together).
I've written an extensive answer on animating sine waves here
(Reuben Margolin's kinectic sculpture system demo)
From your question it sounds like you would be comfortable implementing a sine wave animation. It it helps, here's an example of adding two waves together:
void setup(){
size(600,600);
noStroke();
}
void draw(){
background(0);
// how many waves per sketch height
int heightDivisions = 30;
// split the sketch height into equal height sections
float heightDivisionSize = (float)height / heightDivisions;
// for each height division
for(int j = 0 ; j < heightDivisions; j++){
// use % 2 to alternate between black and white
// see https://processing.org/reference/modulo.html and
// https://processing.org/reference/conditional.html for more
fill(j % 2 == 0 ? color(255) : color(0));
// offset drawing on Y axis
translate(0,(j * heightDivisionSize));
// start a wave shape
beginShape();
// first vertex is at the top left corner
vertex(0,height);
// how many horizontal (per wave) divisions ?
int widthDivisions = 12;
// equally space the points on the wave horizontally
float widthDivsionSize = (float)width / widthDivisions;
// for each point on the wave
for(int i = 0; i <= widthDivisions; i++){
// calculate different phases
// play with arithmetic operators to make interesting wave additions
float phase1 = (frameCount * 0.01) + ((i * j) * 0.025);
float phase2 = (frameCount * 0.05) + ((i + j) * 0.25);
// calculate vertex x position
float x = widthDivsionSize * i;
// multiple sine waves
// (can use cos() and use other ratios too
// 150 in this case is the wave amplitude (e.g. from -150 to + 150)
float y = ((sin(phase1) * sin(phase2) * 150));
// draw calculated vertex
vertex(x,y);
}
// last vertex is at bottom right corner
vertex(width,height);
// finish the shape
endShape();
}
}
The result:
Minor note on performance: this could be implemented more efficiently using PShape, however I recommend playing with the maths/geometry to find the form you're after, then as a last step think of optimizing it.
My intention is not to show you how to create an exact replica, but to show there's more to Op Art than an effect and hopefully inspire you to explore other methods of achieving something similar in the hope that you will discover your own methods and outcomes: something new and of your own through fun happy accidents.
In terms of other techniques/avenues to explore:
displacement maps:
Using an alternating black/white straight bars texture on wavy 3D geometry
using shaders:
Shaders are a huge topic on their own, but it's worth noting:
There's a very good Processing Shader Tutorial
You might be able to explore frament shaders on shadertoy, tweak the code in browser then make slight changes so you can run them in Processing.
Here are a few quick examples:
https://www.shadertoy.com/view/Wts3DB
tweaked for black/white waves in Processing as shader-Wts3DB.frag
// https://www.shadertoy.com/view/Wts3DB
uniform vec2 iResolution;
uniform float iTime;
#define COUNT 6.
#define COL_BLACK vec3(23,32,38) / 255.0
#define SF 1./min(iResolution.x,iResolution.y)
#define SS(l,s) smoothstep(SF,-SF,l-s)
#define hue(h) clamp( abs( fract(h + vec4(3,2,1,0)/3.) * 6. - 3.) -1. , 0., 1.)
// Original noise code from https://www.shadertoy.com/view/4sc3z2
#define MOD3 vec3(.1031,.11369,.13787)
vec3 hash33(vec3 p3)
{
p3 = fract(p3 * MOD3);
p3 += dot(p3, p3.yxz+19.19);
return -1.0 + 2.0 * fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));
}
float simplex_noise(vec3 p)
{
const float K1 = 0.333333333;
const float K2 = 0.166666667;
vec3 i = floor(p + (p.x + p.y + p.z) * K1);
vec3 d0 = p - (i - (i.x + i.y + i.z) * K2);
vec3 e = step(vec3(0.0), d0 - d0.yzx);
vec3 i1 = e * (1.0 - e.zxy);
vec3 i2 = 1.0 - e.zxy * (1.0 - e);
vec3 d1 = d0 - (i1 - 1.0 * K2);
vec3 d2 = d0 - (i2 - 2.0 * K2);
vec3 d3 = d0 - (1.0 - 3.0 * K2);
vec4 h = max(0.6 - vec4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0);
vec4 n = h * h * h * h * vec4(dot(d0, hash33(i)), dot(d1, hash33(i + i1)), dot(d2, hash33(i + i2)), dot(d3, hash33(i + 1.0)));
return dot(vec4(31.316), n);
}
void mainImage( vec4 fragColor, vec2 fragCoord )
{
}
void main(void) {
//vec2 uv = vec2(gl_FragColor.x / iResolution.y, gl_FragColor.y / iResolution.y);
vec2 uv = gl_FragCoord.xy / iResolution.y;
float m = 0.;
float t = iTime *.5;
vec3 col;
for(float i=COUNT; i>=0.; i-=1.){
float edge = simplex_noise(vec3(uv * vec2(2., 0.) + vec2(0, t + i*.15), 3.))*.2 + (.95/COUNT)*i;
float mi = SS(edge, uv.y) - SS(edge + .095, uv.y);
m += mi;
if(mi > 0.){
col = vec3(1.0);
}
}
col = mix(COL_BLACK, col, m);
gl_FragColor = vec4(col,1.0);
// mainImage(gl_FragColor,gl_FragCoord);
}
loaded in Processing as:
PShader shader;
void setup(){
size(300,300,P2D);
noStroke();
shader = loadShader("shader-Wts3DB.frag");
shader.set("iResolution",(float)width, float(height));
}
void draw(){
background(0);
shader.set("iTime",frameCount * 0.05);
shader(shader);
rect(0,0,width,height);
}
https://www.shadertoy.com/view/MtsXzl
tweaked as shader-MtsXzl.frag
//https://www.shadertoy.com/view/MtsXzl
#define SHOW_GRID 1
const float c_scale = 0.5;
const float c_rate = 2.0;
#define FLT_MAX 3.402823466e+38
uniform vec3 iMouse;
uniform vec2 iResolution;
uniform float iTime;
//=======================================================================================
float CubicHermite (float A, float B, float C, float D, float t)
{
float t2 = t*t;
float t3 = t*t*t;
float a = -A/2.0 + (3.0*B)/2.0 - (3.0*C)/2.0 + D/2.0;
float b = A - (5.0*B)/2.0 + 2.0*C - D / 2.0;
float c = -A/2.0 + C/2.0;
float d = B;
return a*t3 + b*t2 + c*t + d;
}
//=======================================================================================
float hash(float n) {
return fract(sin(n) * 43758.5453123);
}
//=======================================================================================
float GetHeightAtTile(vec2 T)
{
float rate = hash(hash(T.x) * hash(T.y))*0.5+0.5;
return (sin(iTime*rate*c_rate) * 0.5 + 0.5) * c_scale;
}
//=======================================================================================
float HeightAtPos(vec2 P)
{
vec2 tile = floor(P);
P = fract(P);
float CP0X = CubicHermite(
GetHeightAtTile(tile + vec2(-1.0,-1.0)),
GetHeightAtTile(tile + vec2(-1.0, 0.0)),
GetHeightAtTile(tile + vec2(-1.0, 1.0)),
GetHeightAtTile(tile + vec2(-1.0, 2.0)),
P.y
);
float CP1X = CubicHermite(
GetHeightAtTile(tile + vec2( 0.0,-1.0)),
GetHeightAtTile(tile + vec2( 0.0, 0.0)),
GetHeightAtTile(tile + vec2( 0.0, 1.0)),
GetHeightAtTile(tile + vec2( 0.0, 2.0)),
P.y
);
float CP2X = CubicHermite(
GetHeightAtTile(tile + vec2( 1.0,-1.0)),
GetHeightAtTile(tile + vec2( 1.0, 0.0)),
GetHeightAtTile(tile + vec2( 1.0, 1.0)),
GetHeightAtTile(tile + vec2( 1.0, 2.0)),
P.y
);
float CP3X = CubicHermite(
GetHeightAtTile(tile + vec2( 2.0,-1.0)),
GetHeightAtTile(tile + vec2( 2.0, 0.0)),
GetHeightAtTile(tile + vec2( 2.0, 1.0)),
GetHeightAtTile(tile + vec2( 2.0, 2.0)),
P.y
);
return CubicHermite(CP0X, CP1X, CP2X, CP3X, P.x);
}
//=======================================================================================
vec3 NormalAtPos( vec2 p )
{
float eps = 0.01;
vec3 n = vec3( HeightAtPos(vec2(p.x-eps,p.y)) - HeightAtPos(vec2(p.x+eps,p.y)),
2.0*eps,
HeightAtPos(vec2(p.x,p.y-eps)) - HeightAtPos(vec2(p.x,p.y+eps)));
return normalize( n );
}
//=======================================================================================
float RayIntersectSphere (vec4 sphere, in vec3 rayPos, in vec3 rayDir)
{
//get the vector from the center of this circle to where the ray begins.
vec3 m = rayPos - sphere.xyz;
//get the dot product of the above vector and the ray's vector
float b = dot(m, rayDir);
float c = dot(m, m) - sphere.w * sphere.w;
//exit if r's origin outside s (c > 0) and r pointing away from s (b > 0)
if(c > 0.0 && b > 0.0)
return -1.0;
//calculate discriminant
float discr = b * b - c;
//a negative discriminant corresponds to ray missing sphere
if(discr < 0.0)
return -1.0;
//ray now found to intersect sphere, compute smallest t value of intersection
float collisionTime = -b - sqrt(discr);
//if t is negative, ray started inside sphere so clamp t to zero and remember that we hit from the inside
if(collisionTime < 0.0)
collisionTime = -b + sqrt(discr);
return collisionTime;
}
//=======================================================================================
vec3 DiffuseColor (in vec3 pos)
{
#if SHOW_GRID
pos = mod(floor(pos),2.0);
return vec3(mod(pos.x, 2.0) < 1.0 ? 1.0 : 0.0);
#else
return vec3(0.1, 0.8, 0.9);
#endif
}
//=======================================================================================
vec3 ShadePoint (in vec3 pos, in vec3 rayDir, float time, bool fromUnderneath)
{
vec3 diffuseColor = DiffuseColor(pos);
vec3 reverseLightDir = normalize(vec3(1.0,1.0,-1.0));
vec3 lightColor = vec3(1.0);
vec3 ambientColor = vec3(0.05);
vec3 normal = NormalAtPos(pos.xz);
normal *= fromUnderneath ? -1.0 : 1.0;
// diffuse
vec3 color = diffuseColor;
float dp = dot(normal, reverseLightDir);
if(dp > 0.0)
color += (diffuseColor * lightColor);
return color;
}
//=======================================================================================
vec3 HandleRay (in vec3 rayPos, in vec3 rayDir, in vec3 pixelColor, out float hitTime)
{
float time = 0.0;
float lastHeight = 0.0;
float lastY = 0.0;
float height;
bool hitFound = false;
hitTime = FLT_MAX;
bool fromUnderneath = false;
vec2 timeMinMax = vec2(0.0, 20.0);
time = timeMinMax.x;
const int c_numIters = 100;
float deltaT = (timeMinMax.y - timeMinMax.x) / float(c_numIters);
vec3 pos = rayPos + rayDir * time;
float firstSign = sign(pos.y - HeightAtPos(pos.xz));
for (int index = 0; index < c_numIters; ++index)
{
pos = rayPos + rayDir * time;
height = HeightAtPos(pos.xz);
if (sign(pos.y - height) * firstSign < 0.0)
{
fromUnderneath = firstSign < 0.0;
hitFound = true;
break;
}
time += deltaT;
lastHeight = height;
lastY = pos.y;
}
if (hitFound) {
time = time - deltaT + deltaT*(lastHeight-lastY)/(pos.y-lastY-height+lastHeight);
pos = rayPos + rayDir * time;
pixelColor = ShadePoint(pos, rayDir, time, fromUnderneath);
hitTime = time;
}
return pixelColor;
}
//=======================================================================================
void main()
{
// scrolling camera
vec3 cameraOffset = vec3(iTime, 0.5, iTime);
//----- camera
vec2 mouse = iMouse.xy / iResolution.xy;
vec3 cameraAt = vec3(0.5,0.5,0.5) + cameraOffset;
float angleX = iMouse.z > 0.0 ? 6.28 * mouse.x : 3.14 + iTime * 0.25;
float angleY = iMouse.z > 0.0 ? (mouse.y * 6.28) - 0.4 : 0.5;
vec3 cameraPos = (vec3(sin(angleX)*cos(angleY), sin(angleY), cos(angleX)*cos(angleY))) * 5.0;
// float angleX = 0.8;
// float angleY = 0.8;
// vec3 cameraPos = vec3(0.0,0.0,0.0);
cameraPos += vec3(0.5,0.5,0.5) + cameraOffset;
vec3 cameraFwd = normalize(cameraAt - cameraPos);
vec3 cameraLeft = normalize(cross(normalize(cameraAt - cameraPos), vec3(0.0,sign(cos(angleY)),0.0)));
vec3 cameraUp = normalize(cross(cameraLeft, cameraFwd));
float cameraViewWidth = 6.0;
float cameraViewHeight = cameraViewWidth * iResolution.y / iResolution.x;
float cameraDistance = 6.0; // intuitively backwards!
// Objects
vec2 rawPercent = (gl_FragCoord.xy / iResolution.xy);
vec2 percent = rawPercent - vec2(0.5,0.5);
vec3 rayTarget = (cameraFwd * vec3(cameraDistance,cameraDistance,cameraDistance))
- (cameraLeft * percent.x * cameraViewWidth)
+ (cameraUp * percent.y * cameraViewHeight);
vec3 rayDir = normalize(rayTarget);
float hitTime = FLT_MAX;
vec3 pixelColor = vec3(1.0, 1.0, 1.0);
pixelColor = HandleRay(cameraPos, rayDir, pixelColor, hitTime);
gl_FragColor = vec4(clamp(pixelColor,0.0,1.0), 1.0);
}
and the mouse interactive Processing sketch:
PShader shader;
void setup(){
size(300,300,P2D);
noStroke();
shader = loadShader("shader-MtsXzl.frag");
shader.set("iResolution",(float)width, float(height));
}
void draw(){
background(0);
shader.set("iTime",frameCount * 0.05);
shader.set("iMouse",(float)mouseX , (float)mouseY, mousePressed ? 1.0 : 0.0);
shader(shader);
rect(0,0,width,height);
}
Shadertoy is great way to play/learn: have fun !
Update
Here's a quick test tweaking Daniel Shiffman's 3D Terrain Generation example to add a stripped texture and basic sine waves instead of perlin noise:
// Daniel Shiffman
// http://codingtra.in
// http://patreon.com/codingtrain
// Code for: https://youtu.be/IKB1hWWedMk
int cols, rows;
int scl = 20;
int w = 2000;
int h = 1600;
float flying = 0;
float[][] terrain;
PImage texture;
void setup() {
size(600, 600, P3D);
textureMode(NORMAL);
noStroke();
cols = w / scl;
rows = h/ scl;
terrain = new float[cols][rows];
texture = getBarsTexture(512,512,96);
}
void draw() {
flying -= 0.1;
float yoff = flying;
for (int y = 0; y < rows; y++) {
float xoff = 0;
for (int x = 0; x < cols; x++) {
//terrain[x][y] = map(noise(xoff, yoff), 0, 1, -100, 100);
terrain[x][y] = map(sin(xoff) * sin(yoff), 0, 1, -60, 60);
xoff += 0.2;
}
yoff += 0.2;
}
background(0);
translate(width/2, height/2+50);
rotateX(PI/9);
translate(-w/2, -h/2);
for (int y = 0; y < rows-1; y++) {
beginShape(TRIANGLE_STRIP);
texture(texture);
for (int x = 0; x < cols; x++) {
float u0 = map(x,0,cols-1,0.0,1.0);
float u1 = map(x+1,0,cols-1,0.0,1.0);
float v0 = map(y,0,rows-1,0.0,1.0);
float v1 = map(y+1,0,rows-1,0.0,1.0);
vertex(x*scl, y*scl, terrain[x][y], u0, v0);
vertex(x*scl, (y+1)*scl, terrain[x][y+1], u1, v1);
}
endShape();
}
}
PGraphics getBarsTexture(int textureWidth, int textureHeight, int numBars){
PGraphics texture = createGraphics(textureWidth, textureHeight);
int moduleSide = textureWidth / numBars;
texture.beginDraw();
texture.background(0);
texture.noStroke();
for(int i = 0; i < numBars; i+= 2){
texture.rect(0, i * moduleSide, textureWidth, moduleSide);
}
texture.endDraw();
return texture;
}

Atmosphere Scattering for Earth from space and on the ground

Please provide prompt how to make the atmosphere of the Earth so that it is visible from space and from the ground (as shown in the image)
a model of the earth:
Earth = new THREE.Mesh(new THREE.SphereGeometry(6700,32,32),ShaderMaterialEarth);
model of the cosmos:
cosmos= new THREE.Mesh(new THREE.SphereGeometry(50000,32,32),ShaderMaterialCosmos);
and a light source:
sun = new THREE.DirectionalLight();
where to start, just I do not know. Perhaps this should do ShaderMaterialCosmos, where to pass position of the camera, and calculate how should be painted pixel. But how?
I tried using the following but get zero vectors at the entrance of the fragment shader
http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html
vertexShader:
#define M_PI 3.1415926535897932384626433832795
const float ESun=1.0;
const float Kr = 0.0025;
const float Km = 0.0015;
const int nSamples = 2;
const float fSamples = 1.0;
const float fScaleDepth = 0.25;
varying vec2 vUv;
varying vec3 wPosition;
varying vec4 c0;
varying vec4 c1;
varying vec3 t0;
uniform vec3 v3CameraPos; , // The camera's current position
uniform vec3 v3LightDir; // Direction vector to the light source
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for RGB
uniform float fCameraHeight; // The camera's current height
const float fOuterRadius=6500.0; // The outer (atmosphere) radius
const float fInnerRadius=6371.0; // The inner (planetary) radius
const float fKrESun=Kr*ESun; // Kr * ESun
const float fKmESun=Km*ESun; // Km * ESun
const float fKr4PI=Kr*4.0*M_PI; // Kr * 4 * PI
const float fKm4PI=Km*4.0*M_PI; // Km * 4 * PI
const float fScale=1.0/(fOuterRadius-fInnerRadius); // 1 / (fOuterRadius - fInnerRadius)
const float fScaleOverScaleDepth= fScale / fScaleDepth; // fScale / fScaleDepth
const float fInvScaleDepth=1.0/0.25;
float getNearIntersection(vec3 v3Pos, vec3 v3Ray, float fDistance2, float fRadius2)
{
float B = 2.0 * dot(v3Pos, v3Ray);
float C = fDistance2 - fRadius2;
float fDet = max(0.0, B*B - 4.0 * C);
return 0.5 * (-B - sqrt(fDet));
}
float scale(float fCos)
{
float x = 1.0 - fCos;
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
}
void main() {
// Get the ray from the camera to the vertex and its length (which
// is the far point of the ray passing through the atmosphere)
vec3 v3Pos = position.xyz;
vec3 v3Ray = v3Pos - v3CameraPos;
float fFar = length(v3Ray);
v3Ray /= fFar;
// Calculate the closest intersection of the ray with
// the outer atmosphere (point A in Figure 16-3)
float fNear = getNearIntersection(v3CameraPos, v3Ray, fCameraHeight*fCameraHeight, fOuterRadius*fOuterRadius);
// Calculate the ray's start and end positions in the atmosphere,
// then calculate its scattering offset
vec3 v3Start = v3CameraPos + v3Ray * fNear;
fFar -= fNear;
float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;
float fStartDepth = exp(-fInvScaleDepth);
float fStartOffset = fStartDepth * scale(fStartAngle);
// Initialize the scattering loop variables
float fSampleLength = fFar / fSamples;
float fScaledLength = fSampleLength * fScale;
vec3 v3SampleRay = v3Ray * fSampleLength;
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
// Now loop through the sample points
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
for(int i=0; i<nSamples; i++) {
float fHeight = length(v3SamplePoint);
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
float fLightAngle = dot(v3LightDir, v3SamplePoint) / fHeight;
float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;
float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) * scale(fCameraAngle)));
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
v3SamplePoint += v3SampleRay;
}
wPosition = (modelMatrix * vec4(position,1.0)).xyz;
c0.rgb = v3FrontColor * (v3InvWavelength * fKrESun);
c1.rgb = v3FrontColor * fKmESun;
t0 = v3CameraPos - v3Pos;
vUv = uv;
}
fragmentShader:
float getMiePhase(float fCos, float fCos2, float g, float g2){
return 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos2) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
}
// Rayleigh phase function
float getRayleighPhase(float fCos2){
//return 0.75 + 0.75 * fCos2;
return 0.75 * (2.0 + 0.5 * fCos2);
}
varying vec2 vUv;
varying vec3 wPosition;
varying vec4 c0;
varying vec4 c1;
varying vec3 t0;
uniform vec3 v3LightDir;
uniform float g;
uniform float g2;
void main() {
float fCos = dot(v3LightDir, t0) / length(t0);
float fCos2 = fCos * fCos;
gl_FragColor = getRayleighPhase(fCos2) * c0 + getMiePhase(fCos, fCos2, g, g2) * c1;
gl_FragColor = c1;
}
Chapter 16 of GPU Gem 2 has nice explanation and illustration for achieving your goal in real time.
Basically you need to perform ray casting through the atmosphere layer and evaluate the light scattering.

GLSL Shadows with Perlin Noise

So I've recently gotten into using WebGL and more specifically writing GLSL Shaders and I have run into a snag while writing the fragment shader for my "water" shader which is derived from this tutorial.
What I'm trying to achieve is a stepped shading (Toon shading, cell shading...) effect on waves generated by my vertex shader but the fragment shader seems to treat the waves as though they are still a flat plane and the entire mesh is drawn as one solid color.
What am I missing here? The sphere works perfectly but flat surfaces are all shaded uniformly. I have the same problem if I use a cube. Each face on the cube is shaded independently but the entire face is given a solid color.
The Scene
This is how I have my test scene set up. I have two meshes using the same material - a sphere and a plane and a light source.
The Problem
As you can see the shader is working as expected on the sphere.
I enabled wireframe for this shot to show that the vertex shader (perlin noise) is working beautifully on the plane.
But when I turn the wireframe off you can see that the fragment shader seems to be receiving the same level of light uniformly across the entire plane creating this...
Rotating the plane to face the light source will change the color of the material but again the color is applied uniformly over the entire surface of the plane.
The Fragment Shader
In all it's script kid glory lol.
uniform vec3 uMaterialColor;
uniform vec3 uDirLightPos;
uniform vec3 uDirLightColor;
uniform float uKd;
uniform float uBorder;
varying vec3 vNormal;
varying vec3 vViewPosition;
void main() {
vec4 color;
// compute direction to light
vec4 lDirection = viewMatrix * vec4( uDirLightPos, 0.0 );
vec3 lVector = normalize( lDirection.xyz );
// N * L. Normal must be normalized, since it's interpolated.
vec3 normal = normalize( vNormal );
// check the diffuse dot product against uBorder and adjust
// this diffuse value accordingly.
float diffuse = max( dot( normal, lVector ), 0.0);
if (diffuse > 0.95)
color = vec4(1.0,0.0,0.0,1.0);
else if (diffuse > 0.85)
color = vec4(0.9,0.0,0.0,1.0);
else if (diffuse > 0.75)
color = vec4(0.8,0.0,0.0,1.0);
else if (diffuse > 0.65)
color = vec4(0.7,0.0,0.0,1.0);
else if (diffuse > 0.55)
color = vec4(0.6,0.0,0.0,1.0);
else if (diffuse > 0.45)
color = vec4(0.5,0.0,0.0,1.0);
else if (diffuse > 0.35)
color = vec4(0.4,0.0,0.0,1.0);
else if (diffuse > 0.25)
color = vec4(0.3,0.0,0.0,1.0);
else if (diffuse > 0.15)
color = vec4(0.2,0.0,0.0,1.0);
else if (diffuse > 0.05)
color = vec4(0.1,0.0,0.0,1.0);
else
color = vec4(0.05,0.0,0.0,1.0);
gl_FragColor = color;
The Vertex Shader
vec3 mod289(vec3 x)
{
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x)
{
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x)
{
return mod289(((x*34.0)+1.0)*x);
}
vec4 taylorInvSqrt(vec4 r)
{
return 1.79284291400159 - 0.85373472095314 * r;
}
vec3 fade(vec3 t) {
return t*t*t*(t*(t*6.0-15.0)+10.0);
}
// Classic Perlin noise
float cnoise(vec3 P)
{
vec3 Pi0 = floor(P); // Integer part for indexing
vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1
Pi0 = mod289(Pi0);
Pi1 = mod289(Pi1);
vec3 Pf0 = fract(P); // Fractional part for interpolation
vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
vec4 iy = vec4(Pi0.yy, Pi1.yy);
vec4 iz0 = Pi0.zzzz;
vec4 iz1 = Pi1.zzzz;
vec4 ixy = permute(permute(ix) + iy);
vec4 ixy0 = permute(ixy + iz0);
vec4 ixy1 = permute(ixy + iz1);
vec4 gx0 = ixy0 * (1.0 / 7.0);
vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5;
gx0 = fract(gx0);
vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
vec4 sz0 = step(gz0, vec4(0.0));
gx0 -= sz0 * (step(0.0, gx0) - 0.5);
gy0 -= sz0 * (step(0.0, gy0) - 0.5);
vec4 gx1 = ixy1 * (1.0 / 7.0);
vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5;
gx1 = fract(gx1);
vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
vec4 sz1 = step(gz1, vec4(0.0));
gx1 -= sz1 * (step(0.0, gx1) - 0.5);
gy1 -= sz1 * (step(0.0, gy1) - 0.5);
vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);
vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
g000 *= norm0.x;
g010 *= norm0.y;
g100 *= norm0.z;
g110 *= norm0.w;
vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
g001 *= norm1.x;
g011 *= norm1.y;
g101 *= norm1.z;
g111 *= norm1.w;
float n000 = dot(g000, Pf0);
float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
float n111 = dot(g111, Pf1);
vec3 fade_xyz = fade(Pf0);
vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
return 2.2 * n_xyz;
}
// Classic Perlin noise, periodic variant
float pnoise(vec3 P, vec3 rep)
{
vec3 Pi0 = mod(floor(P), rep); // Integer part, modulo period
vec3 Pi1 = mod(Pi0 + vec3(1.0), rep); // Integer part + 1, mod period
Pi0 = mod289(Pi0);
Pi1 = mod289(Pi1);
vec3 Pf0 = fract(P); // Fractional part for interpolation
vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
vec4 iy = vec4(Pi0.yy, Pi1.yy);
vec4 iz0 = Pi0.zzzz;
vec4 iz1 = Pi1.zzzz;
vec4 ixy = permute(permute(ix) + iy);
vec4 ixy0 = permute(ixy + iz0);
vec4 ixy1 = permute(ixy + iz1);
vec4 gx0 = ixy0 * (1.0 / 7.0);
vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5;
gx0 = fract(gx0);
vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
vec4 sz0 = step(gz0, vec4(0.0));
gx0 -= sz0 * (step(0.0, gx0) - 0.5);
gy0 -= sz0 * (step(0.0, gy0) - 0.5);
vec4 gx1 = ixy1 * (1.0 / 7.0);
vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5;
gx1 = fract(gx1);
vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
vec4 sz1 = step(gz1, vec4(0.0));
gx1 -= sz1 * (step(0.0, gx1) - 0.5);
gy1 -= sz1 * (step(0.0, gy1) - 0.5);
vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);
vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
g000 *= norm0.x;
g010 *= norm0.y;
g100 *= norm0.z;
g110 *= norm0.w;
vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
g001 *= norm1.x;
g011 *= norm1.y;
g101 *= norm1.z;
g111 *= norm1.w;
float n000 = dot(g000, Pf0);
float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
float n111 = dot(g111, Pf1);
vec3 fade_xyz = fade(Pf0);
vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
return 2.2 * n_xyz;
}
varying vec2 vUv;
varying float noise;
uniform float time;
// for the cell shader
varying vec3 vNormal;
varying vec3 vViewPosition;
float turbulence( vec3 p ) {
float w = 100.0;
float t = -.5;
for (float f = 1.0 ; f <= 10.0 ; f++ ){
float power = pow( 2.0, f );
t += abs( pnoise( vec3( power * p ), vec3( 10.0, 10.0, 10.0 ) ) / power );
}
return t;
}
varying vec3 vertexWorldPos;
void main() {
vUv = uv;
// add time to the noise parameters so it's animated
noise = 10.0 * -.10 * turbulence( .5 * normal + time );
float b = 25.0 * pnoise( 0.05 * position + vec3( 2.0 * time ), vec3( 100.0 ) );
float displacement = - 10. - noise + b;
vec3 newPosition = position + normal * displacement;
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
// for the cell shader effect
vNormal = normalize( normalMatrix * normal );
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vViewPosition = -mvPosition.xyz;
}
Worth Mention
I am using the Three.js library
My light source is an instance of THREE.SpotLight
First of all, shadows are completely different. Your problem here is a lack of change in the per-vertex normal after displacement. Correcting this is not going to get you shadows, but your lighting will at least vary across your displaced geometry.
If you have access to partial derivatives, you can do this in the fragment shader. Otherwise, you are kind of out of luck in GL ES, due to a lack of vertex adjacency information. You could also compute per-face normals with a Geometry Shader, but that is not an option in WebGL.
This should be all of the necessary changes to implement this, note that it requires partial derivative support (optional extension in OpenGL ES 2.0).
Vertex Shader:
varying vec3 vertexViewPos; // NEW
void main() {
...
vec3 newPosition = position + normal * displacement;
vertexViewPos = (modelViewMatrix * vec4 (newPosition, 1.0)).xyz; // NEW
...
}
Fragment Shader:
#extension GL_OES_standard_derivatives : require
uniform vec3 uMaterialColor;
uniform vec3 uDirLightPos;
uniform vec3 uDirLightColor;
uniform float uKd;
uniform float uBorder;
varying vec3 vNormal;
varying vec3 vViewPosition;
varying vec3 vertexViewPos; // NEW
void main() {
vec4 color;
// compute direction to light
vec4 lDirection = viewMatrix * vec4( uDirLightPos, 0.0 );
vec3 lVector = normalize( lDirection.xyz );
// N * L. Normal must be normalized, since it's interpolated.
vec3 normal = normalize(cross (dFdx (vertexViewPos), dFdy (vertexViewPos))); // UPDATED
...
}
To enable partial derivative support in WebGL you need to check the extension like this:
var ext = gl.getExtension("OES_standard_derivatives");
if (!ext) {
alert("OES_standard_derivatives does not exist on this machine");
return;
}
// proceed with the shaders above.

Resources