Blur HTML5 canvas issue - javascript

The canvas does not allow me to use other domain URLs and show a cross-domain error.
I have to use this demo https://tympanus.net/Development/FlowmapDeformation/index3.html but I face some issues on the frontend.
At the front end of the demo, it shows blurs SVG image in the canvas.
Demo use below Vertex and fragment:
const vertex = `
attribute vec2 uv;
attribute vec2 position;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 0, 1);
}
`;
const fragment = `
precision highp float;
precision highp int;
uniform sampler2D tWater;
uniform sampler2D tFlow;
uniform float uTime;
varying vec2 vUv;
uniform vec4 res;
void main() {
// R and G values are velocity in the x and y direction
// B value is the velocity length
vec3 flow = texture2D(tFlow, vUv).rgb;
vec2 uv = .5 * gl_FragCoord.xy / res.xy ;
vec2 myUV = (uv - vec2(0.5))*res.zw + vec2(0.5);
myUV -= flow.xy * (0.15 * 0.5);
vec3 tex = texture2D(tWater, myUV).rgb;
gl_FragColor.rgb = vec3(tex.r, tex.g, tex.b);
gl_FragColor.a = tex.r;
}
`;
SVG image code:
let imgSize = [1600, 1200];
const img = new Image();
img.onload = () => (texture.image = img);
img.crossOrigin = "Anonymous";
img.src = "img/Alienation.svg";
const program = new Program(gl, {
vertex,
fragment,
uniforms: {
uTime: { value: 0 },
tWater: { value: texture },
res: {
value: new ogl.Vec4(window.innerWidth, window.innerHeight)
},
img: { value: new ogl.Vec2(imgSize[0], imgSize[1]) },
tFlow: flowmap.uniform
}
});
See the original SVG image - https://tympanus.net/Development/FlowmapDeformation/img/Alienation.svg
Check the attached screenshot for more information.

Related

How to change javascript event listener?

I just switched to a new shopify theme. I've run into some issues with code that works fine on my other themes, but not on this new one, due to how their theme is structured.
Their documentation says to use the following event listener instead of document.onload and $(document).ready():
document.addEventListener('page:loaded', function() {
console.log('page:loaded');
});
I'm not skilled in javascript and I'm having trouble getting it to work with the following 2 scripts. Can anyone assist?
<script type="text/javascript">
jQuery(document).ready(function($) {
$('a[data-rel^=lightcase]').lightcase();
});
</script>
<script>
window.addEventListener("load", function () {
var curtains = new Curtains({
container: "planes-canvas"
});
var planeEls = document.getElementsByClassName("planes");
var vs = `#ifdef GL_ES
precision mediump float;
#endif
// default mandatory attributes
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
// those projection and model view matrices are generated by the library
// it will position and size our plane based on its HTML element CSS values
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
// texture coord varying that will be passed to our fragment shader
varying vec2 vTextureCoord;
void main() {
// apply our vertex position based on the projection and model view matrices
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
// varying
// use texture matrix and original texture coords to generate accurate texture coords
vTextureCoord = aTextureCoord;
}`;
var fs = `
#ifdef GL_ES
precision mediump float;
#endif
// get our varyings
varying vec3 vVertexPosition;
varying vec2 vTextureCoord;
// the uniform we declared inside our javascript
uniform float uTime;
// our texture sampler (default name, to use a different name please refer to the documentation)
uniform sampler2D planeTexture;
vec3 hueRotate(vec3 col, float hue) {
vec3 k = vec3(0.57735, 0.57735, 0.57735);
float cosAngle = cos(hue);
return col * cosAngle + cross(k, col) * sin(hue) + k * dot(k, col) * (1.0 - cosAngle);
}
vec3 saturate(vec3 rgb, float adjustment) {
vec3 W = vec3(0.2125, 0.7154, 0.0721);
vec3 intensity = vec3(dot(rgb, W));
return mix(intensity, rgb, adjustment);
}
void main() {
// get our texture coords
vec2 textureCoord = vTextureCoord;
// displace our pixels along both axis based on our time uniform and texture UVs
// this will create a kind of water surface effect
// try to comment a line or change the constants to see how it changes the effect
// reminder : textures coords are ranging from 0.0 to 1.0 on both axis
const float PI = 3.141592;
textureCoord.x += (
sin(textureCoord.x * 12.0 + ((uTime * (PI / 15.0)) * 0.031))
+ sin(textureCoord.y * 12.0 + ((uTime * (PI / 12.489)) * 0.047))
) * 0.0050;
textureCoord.y += (
sin(textureCoord.y * 8.0 + ((uTime * (PI / 12.023)) * 0.023))
+ sin(textureCoord.x * 8.0 + ((uTime * (PI / 15.1254)) * 0.067))
) * 0.0100;
vec4 color = texture2D(planeTexture, textureCoord);
// hue rotation from 0 to PI in 10 seconds
float hueRotation = cos(uTime / 600.0) * PI;
color.rgb = hueRotate(color.rgb, hueRotation);
// saturate
color.rgb = saturate(color.rgb, 2.0);
gl_FragColor = color;
}
`;
var planes = [];
function handlePlane(index) {
var plane = planes[index];
plane
.onReady(function () {
// our texture has been loaded, resize our plane!
plane.planeResize();
})
.onRender(function () {
plane.uniforms.time.value++;
});
}
for (var i = 0; i < planeEls.length; i++) {
var params = {
vertexShader: vs,
fragmentShader: fs,
uniforms: {
time: {
name: "uTime",
type: "1f",
value: 0
}
}
};
var plane = curtains.addPlane(planeEls[i], params);
if (plane) {
planes.push(plane);
handlePlane(i);
}
}
});
</script>
For this code to work with the new theme, you need to listen to the custom event page:loaded specific to this new theme, instead of the standard events window.onload or $(document).ready().
Below you will find your old code snippets adapted to the new event:
First script tag :
<script type="text/javascript">
document.addEventListener('page:loaded', function() {
$('a[data-rel^=lightcase]').lightcase();
});
</script>
Second one :
<script>
document.addEventListener('page:loaded', function() {
var curtains = new Curtains({
container: "planes-canvas"
});
var planeEls = document.getElementsByClassName("planes");
var vs = `#ifdef GL_ES
precision mediump float;
#endif
// default mandatory attributes
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
// those projection and model view matrices are generated by the library
// it will position and size our plane based on its HTML element CSS values
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
// texture coord varying that will be passed to our fragment shader
varying vec2 vTextureCoord;
void main() {
// apply our vertex position based on the projection and model view matrices
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
// varying
// use texture matrix and original texture coords to generate accurate texture coords
vTextureCoord = aTextureCoord;
}`;
var fs = `
#ifdef GL_ES
precision mediump float;
#endif
// get our varyings
varying vec3 vVertexPosition;
varying vec2 vTextureCoord;
// the uniform we declared inside our javascript
uniform float uTime;
// our texture sampler (default name, to use a different name please refer to the documentation)
uniform sampler2D planeTexture;
vec3 hueRotate(vec3 col, float hue) {
vec3 k = vec3(0.57735, 0.57735, 0.57735);
float cosAngle = cos(hue);
return col * cosAngle + cross(k, col) * sin(hue) + k * dot(k, col) * (1.0 - cosAngle);
}
vec3 saturate(vec3 rgb, float adjustment) {
vec3 W = vec3(0.2125, 0.7154, 0.0721);
vec3 intensity = vec3(dot(rgb, W));
return mix(intensity, rgb, adjustment);
}
void main() {
// get our texture coords
vec2 textureCoord = vTextureCoord;
// displace our pixels along both axis based on our time uniform and texture UVs
// this will create a kind of water surface effect
// try to comment a line or change the constants to see how it changes the effect
// reminder : textures coords are ranging from 0.0 to 1.0 on both axis
const float PI = 3.141592;
textureCoord.x += (
sin(textureCoord.x * 12.0 + ((uTime * (PI / 15.0)) * 0.031))
+ sin(textureCoord.y * 12.0 + ((uTime * (PI / 12.489)) * 0.047))
) * 0.0050;
textureCoord.y += (
sin(textureCoord.y * 8.0 + ((uTime * (PI / 12.023)) * 0.023))
+ sin(textureCoord.x * 8.0 + ((uTime * (PI / 15.1254)) * 0.067))
) * 0.0100;
vec4 color = texture2D(planeTexture, textureCoord);
// hue rotation from 0 to PI in 10 seconds
float hueRotation = cos(uTime / 600.0) * PI;
color.rgb = hueRotate(color.rgb, hueRotation);
// saturate
color.rgb = saturate(color.rgb, 2.0);
gl_FragColor = color;
}
`;
var planes = [];
function handlePlane(index) {
var plane = planes[index];
plane
.onReady(function () {
// our texture has been loaded, resize our plane!
plane.planeResize();
})
.onRender(function () {
plane.uniforms.time.value++;
});
}
for (var i = 0; i < planeEls.length; i++) {
var params = {
vertexShader: vs,
fragmentShader: fs,
uniforms: {
time: {
name: "uTime",
type: "1f",
value: 0
}
}
};
var plane = curtains.addPlane(planeEls[i], params);
if (plane) {
planes.push(plane);
handlePlane(i);
}
}
});
</script>

How to pass and use a lookup table in a shader with three.js

I have written a simple three.js of using a height map. This is the relevant code that creates the shader material:
function loadHeightMap() {
// fake a lookup table
var lut = [];
for ( var n=0; n<256; n++ ) {
lut.push(new THREE.Vector3(0.5, 0.4, 0.3));
}
var loader = new THREE.TextureLoader();
var zScale = 10;
var mapLoc = "https://s22.postimg.org/8n93ehmep/Terrain128.png";
loader.load(mapLoc, function ( texture ) {
// use "this." to create global object
this.customUniforms = {
zTexture: { type: "t", value: texture },
zScale: { type: "f", value: zScale },
zLut: { type: "v3v", value: lut }
};
var customMaterial = new THREE.ShaderMaterial({
uniforms: customUniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
side: THREE.DoubleSide
});
var planeGeo = new THREE.PlaneGeometry( 20, 20, 129, 129 );
var plane = new THREE.Mesh( planeGeo, customMaterial );
plane.rotation.x = -Math.PI / 2;
plane.position.y = 0;
scene.add(plane);
});
}
And here are the shaders:
<script id="vertexShader" type="x-shader/x-vertex">
uniform sampler2D zTexture;
uniform float zScale;
uniform vec3 zLut[ 256 ];
varying float vAmount;
void main() {
vec4 heightData = texture2D( zTexture, uv );
vAmount = heightData.r;
// move the position along the normal
vec3 newPosition = position + normal * zScale * vAmount;
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-vertex">
uniform vec3 zLut[ 256 ];
varying float vAmount;
void main() {
int index = int(vAmount) * 255;
vec3 vColor = vec3(vAmount, vAmount, vAmount);
//gl_FragColor = vec4(zLut[index], 1.0);
gl_FragColor = vec4(vColor, 1.0);
}
The shaders and the height map part works fine. But I want to pass the lookup table (zLut). The above code works fine if I don't try to use the lookup table. A working example is here. I created a fiddle as well here but it fails because of CORS issues.
Any suggestions are welcome.
OK, solved this (mostly). The trick was to fetch the lookup color in the vertex shader, where one CAN index into an array with a non-const value. The pass the resulting color to the fragmentShader as a varying. So the two shaders end up being:
<script id="vertexShader" type="x-shader/x-vertex">
uniform sampler2D vTexture;
uniform float vScale;
uniform vec3 vLut[ 256 ];
varying vec3 vColor;
void main() {
vec4 heightData = texture2D( vTexture, uv );
// assuming map is grayscale it doesn't matter if you use r, g, or b.
float vAmount = heightData.r;
// fetch the color from the lookup table so it gets passed to the fragshader
int index = int(heightData.r * 255.0);
vColor = vLut[index];
// move the position along the normal
vec3 newPosition = position + normal * vScale * vAmount;
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-vertex">
varying vec3 vColor;
void main() {
gl_FragColor = vec4(vColor, 1.0);
}
</script>
The remaining problem I have is that when rendered the colors are all flat. I tried forcing an update on the vertices in the animate function but didn't work. Still researching but the question here is solved (AFAIK).
You can see the result here

Error when adding a new object into existing javascript code

I am trying to resolve an issue of the cannot read property of undefined error when I try to add a new object I created into my javascript file.
Previously, I was able to successfully get 3 objects (a cow, plane, and teapot) in a scene on html and interact with them. When I went to replace the plane with my own object (in my case it is called willis), I received the error.
The error spicifically states:
prog4.js:131 Uncaught TypeError: Cannot read property 'positions' of undefined(…)
init
# prog4.js:131
onload
# prog4.html:12
I have changed nothing about the code, other than renaming 'plane' to 'willis' and making sure the files were in the correct locations.
Any help very much appreciated! My goal is to get 3 different objects in the scene from the original 3 and I was hoping to do it one at a time to see the progress.
<html>
<head>
<script type="text/javascript" src="webgl-utils.js"></script>
<script type="text/javascript" src="webgl-debug.js"></script>
<script type="text/javascript" src="cuon-utils.js"></script>
<script type="text/javascript" src="cuon-matrix.js"></script>
<script type="text/javascript" src="teapot.js"></script>
<script type="text/javascript" src="willis.js"></script>
<script type="text/javascript" src="cow.js"></script>
<script type="text/javascript" src="prog4.js"></script>
</head>
<body onload="init()">
<script id="vertexShader" type="x-shader/x-vertex">
precision mediump float;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform vec4 lightPosition;
attribute vec4 vertexPosition;
attribute vec3 vertexNormal;
varying vec3 fragmentNormal;
varying vec3 fragmentLight;
varying vec3 fragmentView;
varying vec4 fragmentPosition;
void main() {
mat4 modelViewMatrix = viewMatrix * modelMatrix;
vec4 p = vec4 (modelViewMatrix * vertexPosition);
vec4 q = vec4 (viewMatrix * lightPosition);
fragmentNormal = normalize(mat3(modelViewMatrix) * vertexNormal);
fragmentLight = normalize(vec3(q - p));
fragmentView = normalize(vec3(-p));
fragmentPosition = vertexPosition;
gl_Position = projectionMatrix * modelViewMatrix * vertexPosition;
}
</script>
<script id="lightingFragmentShader" type="x-shader/x-fragment">
precision mediump float;
varying vec3 fragmentNormal;
varying vec3 fragmentLight;
varying vec3 fragmentView;
uniform vec3 modelColor;
uniform vec3 lightColor;
void main() {
vec3 n = normalize(fragmentNormal);
vec3 l = normalize(fragmentLight);
vec3 v = normalize(fragmentView);
vec3 h = normalize(l+v);
float d = max(dot(l,n),0.0);
float s = pow(max(dot(h,n),0.0), 10.0);
vec3 fragmentColor = modelColor * lightColor * d + lightColor * s;
gl_FragColor = vec4(fragmentColor, 1.0);
}
</script>
<script id="rainbowFragmentShader" type="x-shader/x-fragment">
precision mediump float;
varying vec3 fragmentNormal;
varying vec3 fragmentLight;
varying vec3 fragmentView;
varying vec4 fragmentPosition;
uniform vec3 lightColor;
void main() {
vec3 modelColor;
if(fragmentPosition.y > 0.5) {
modelColor = vec3(1.0,0.0,0.0);
}
else if (fragmentPosition.y > 0.3) {
modelColor = vec3(0.0,0.0,1.0);
}
else if (fragmentPosition.y > 0.1) {
modelColor = vec3(0.0,1.0,0.1);
}
else {
modelColor = vec3(0.0,1.0,1.0);
}
vec3 fragmentColor = modelColor;
gl_FragColor = vec4(fragmentColor, 1.0);
}
</script>
<script id="goochFragmentShader" type="x-shader/x-fragment">
precision mediump float;
varying vec3 fragmentNormal;
varying vec3 fragmentLight;
varying vec3 fragmentView;
uniform vec3 modelColor;
uniform vec3 lightColor;
void main() {
vec3 n = normalize(fragmentNormal);
vec3 l = normalize(fragmentLight);
vec3 v = normalize(fragmentView);
vec3 h = normalize(l+v);
float kg = max(dot(n,v), 0.0);
vec3 fragmentColor = mix(vec3(0.0,0.0,1.0), vec3(1.0,1.0,0.0), kg);
gl_FragColor = vec4(fragmentColor, 1.0);
}
</script>
<canvas id="webgl" width="500px" height="500px" >
This content requires WebGL.
</canvas>
</body>
var canvas
var gl
var willis
var teapot
var cow
// Interaction
var modelRotationX =0;
var modelRotationY =0;
var dragging = false;
var lastClientX = 0;
var lastClientY = 0;
// Mouse commands
function onmousedown(event) {
dragging = true;
lastClientX = event.clientX;
lastClientY = event.clientY;
}
function onmouseup(event) {
dragging = false;
}
function onmousemove(event) {
if (dragging) {
dX = event.clientX - lastClientX;
dY = event.clientY - lastClientY;
modelRotationY = modelRotationY + dX;
modelRotationX = modelRotationX + dY;
if (modelRotationX > 90.0) {
modelRotationX = 90.0;
}
if (modelRotationX < -90.0) {
modelRotationX = -90.0;
}
requestAnimationFrame(draw);
}
lastClientX = event.clientX;
lastClientY = event.clientY;
}
// FLatten
function flatten(a) {
return a.reduce(function (b, v) { b.push.apply(b, v); return b }, [])
}
// Create shaders for objects
function Shader (vertexId, fragmentId) {
this.program = createProgram(gl, document.getElementById(vertexId).text,
document.getElementById(fragmentId).text);
this.projectionMatrixLocation = gl.getUniformLocation(this.program, "projectionMatrix");
this.viewMatrixLocation = gl.getUniformLocation(this.program, "viewMatrix");
this.modelMatrixLocation = gl.getUniformLocation(this.program, "modelMatrix");
this.lightPositionLocation = gl.getUniformLocation(this.program, "lightPosition");
this.modelColorLocation = gl.getUniformLocation(this.program, "modelColor");
this.lightColorLocation = gl.getUniformLocation(this.program, "lightColor");
this.vertexPositionLocation = gl.getAttribLocation(this.program, 'vertexPosition');
this.vertexNormalLocation = gl.getAttribLocation(this.program, 'vertexNormal');
gl.enableVertexAttribArray(this.vertexPositionLocation);
gl.enableVertexAttribArray(this.vertexNormalLocation);
}
// Execution for shaders
Shader.prototype.use = function(projectionMatrix, viewMatrix, modelMatrix) {
gl.useProgram(this.program);
gl.uniformMatrix4fv(this.projectionMatrixLocation, false, projectionMatrix.elements);
gl.uniformMatrix4fv(this.viewMatrixLocation, false, viewMatrix.elements);
gl.uniformMatrix4fv(this.modelMatrixLocation, false, modelMatrix.elements);
gl.uniform4f(this.lightPositionLocation,0,8,8,1);
gl.uniform3f(this.modelColorLocation,1,1,1);
gl.uniform3f(this.lightColorLocation,0.6,0.4,0.2);
}
// Create models
function Model (positions, normals, triangles) {
this.positionArray = new Float32Array(flatten(positions));
this.normalArray = new Float32Array(flatten(normals));
this.triangleArray = new Uint16Array(flatten(triangles));
this.normalBuffer = gl.createBuffer();
this.positionBuffer = gl.createBuffer();
this.triangleBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, this.normalArray, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, this.positionArray, gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.triangleBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.triangleArray, gl.STATIC_DRAW);
}
// Draw shaders on objects
Model.prototype.draw = function (shader_entry) {
gl.bindBuffer(gl.ARRAY_BUFFER, this.normalBuffer);
gl.vertexAttribPointer(shader_entry.vertexNormalLocation, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
gl.vertexAttribPointer(shader_entry.vertexPositionLocation, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.triangleBuffer);
gl.drawElements(gl.TRIANGLES, this.triangleArray.length, gl.UNSIGNED_SHORT, 0);
}
// Initialization
function init() {
// Initialize the GL context
canvas = document.getElementById('webgl');
gl = getWebGLContext(canvas, false);
lightingShader = new Shader('vertexShader', 'lightingFragmentShader');
rainbowShader = new Shader('vertexShader', 'rainbowFragmentShader');
goochShader = new Shader('vertexShader', 'goochFragmentShader');
teapotModel = new Model(teapot.positions, teapot.normals, teapot.triangles);
willisModel = new Model(willis.positions, willis.normals, willis.triangles);
cowModel = new Model(cow.positions, cow.normals, cow.triangles);
// Make mouse functions "properties of the canvas entity."
canvas.onmousedown = onmousedown;
canvas.onmouseup = onmouseup;
canvas.onmousemove = onmousemove;
// Depth test
gl.enable(gl.DEPTH_TEST);
// Request animation frame
requestAnimationFrame(draw);
}
// Draw
function draw() {
// Create colored background
gl.clearColor(0.2, 0.1, 0.0, 0.3);
gl.clear(gl.COLOR_BUFFER_BIT);
// Declaration of variables
var modelMatrix = new Matrix4();
var viewMatrix = new Matrix4();
var projectionMatrix = new Matrix4();
// Cow and rotation
var modelMatrix = new Matrix4();
modelMatrix.rotate(modelRotationX,1,0,0);
modelMatrix.rotate(modelRotationY,0,1,0);
viewMatrix.translate(0,0,-5)
projectionMatrix.perspective(60,1,1,10);
gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
// Cow shader
lightingShader.use(projectionMatrix, viewMatrix, modelMatrix);
cowModel.draw(lightingShader);
// willis
var modelMatrix = new Matrix4();
modelMatrix.rotate(modelRotationX,1,0,0);
modelMatrix.rotate(modelRotationY,0,1,0);
viewMatrix.translate(2,0,-1)
// willis shader
goochShader.use(projectionMatrix, viewMatrix, modelMatrix);
willisModel.draw(goochShader);
//Teapot
var modelMatrix = new Matrix4();
modelMatrix.rotate(modelRotationX,1,0,0);
modelMatrix.rotate(modelRotationY,0,1,0);
viewMatrix.translate(-5,0,-2)
// Teapot shader
rainbowShader.use(projectionMatrix, viewMatrix, modelMatrix);
teapotModel.draw(rainbowShader);
}

Export from Shadertoy to Three.js

I am making my first steps coding. I made some courses on internet, then I played with some three.js experiments, and now I would like to continue learning experimenting with Shaders.
I found Shadertoy.com and it's really amazing! There are a lot of difference experiments with incredible effects. I am trying to use one of these shaders in Three.js but is not so easy.
The Shaders are already written, it's true. But I don't know what to do with that, I don't know how I can use it.
Because it's not only copy and paste the code. There is a relation that I have to write to can apply some of these amazing effects to a Three.js geometry. I have to use uniforms, and I don't know how I can make to know which uniforms I can use, and how can I use them.
I started see the tutorials in Shadertoy and some articles on Internet and it looks like something really abstract. I think that I should study a lot of maths before start understanding that language.
Do you have some recommendation to start?
Maybe is something simpler than I think and I can just copy, paste, and experiment with the code on my HTML document?
Shadertoy is a relatively complex program. It's got audio input into shaders, video input into shaders, audio data generation from shaders, various kinds of textures including both 2d and cubemaps. Supporting all those features is not a small amount of work.
That said a basic shader can be used pretty easily, see example below. But shadertoy shaders are not really designed to be used as materials on meshes in three.js.
If you want to understand why and how WebGL works see http://webglfundamentals.org
const vs = `
attribute vec4 position;
void main() {
gl_Position = position;
}
`;
const userShader = `
// FROM: https://www.shadertoy.com/view/4sdXDl
//spikey
#define SHAPE length(z.yz)
//normal
//#define SHAPE length(z.xyz)
//bizarro
//#define SHAPE length(z.yz-z.xx)
//etc...
#define HIGH_QUAL
#ifdef HIGH_QUAL
#define MARCH_STEPS 199
#else
#define MARCH_STEPS 99
#endif
float k=7.0+3.0*sin(iGlobalTime*0.15);
vec3 mcol=vec3(0.0);
void AbsBox(inout vec4 z){//abs box by kali
z.xyz=abs(z.xyz+1.0)-1.0;
z*=1.5/clamp(dot(z.xyz,z.xyz),0.25,1.0);
}
void Bulb(inout vec4 z, in vec4 c){//mandelBulb by twinbee
float r = length(z.xyz);
float zo = asin(z.z / r) * k + iGlobalTime*0.15;
float zi = atan(z.y, z.x) * 7.0;
z=pow(r, k-1.0)*vec4(r*vec3(cos(zo)*vec2(cos(zi),sin(zi)),sin(zo)),z.w*k)+c;
}
float DE(vec3 p){
vec4 c = vec4(p,1.0),z = c;
Bulb(z,c);
float r0=(length(z.xyz)-1.15)/z.w;
z.xyz-=1.0;
for(int i=0;i<7;i++)AbsBox(z);
float r=SHAPE;
mcol.rgb=vec3(1.0,0.5,0.2)+abs(sin(0.2*r+100.0*z.yxz/z.w));
return 0.5 * max((r-1.0) / z.w,-r0);
}
vec3 sky(vec3 rd, vec3 L){//modified bananaft's & public_int_i's code
float d=0.4*dot(rd,L)+0.6;
//return vec3(d);
rd.y+=sin(sqrt(clamp(-rd.y,0.0,0.9))*90.0)*0.45*max(-0.1,rd.y);
rd=abs(rd);
float y=max(0.,L.y),sun=max(1.-(1.+10.*y+rd.y)*length(rd-L),0.)
+.3*pow(1.-rd.y,12.)*(1.6-y);
return d*mix(vec3(0.3984,0.5117,0.7305),vec3(0.7031,0.4687,0.1055),sun)
*((.5+pow(y,.4))*(1.5-abs(L.y))+pow(sun,5.2)*y*(5.+15.0*y));
}
float rnd;
void randomize(in vec2 p){rnd=fract(float(iFrame)+sin(dot(p,vec2(13.3145,117.7391)))*42317.7654321);}
float ShadAO(in vec3 ro, in vec3 rd){
float t=0.0,s=1.0,d,mn=0.01;
for(int i=0;i<12;i++){
d=max(DE(ro+rd*t)*1.5,mn);
s=min(s,d/t+t*0.5);
t+=d;
}
return s;
}
vec3 scene(vec3 ro, vec3 rd){
vec3 L=normalize(vec3(0.4,0.025,0.5));
vec3 bcol=sky(rd,L);
vec4 col=vec4(0.0);//color accumulator
float t=DE(ro)*rnd,d,od=1.0,px=1.0/iResolution.x;
for(int i=0;i<MARCH_STEPS;i++){
d=DE(ro);
if(d<px*t){
float dif=clamp(1.0-d/od,0.2,1.0);
vec3 scol=mcol*dif*(1.3-0.3*t);
#ifdef HIGH_QUAL
vec2 s=vec2(DE(ro+d*4.0*L),DE(ro+d*16.0*L));
scol*=clamp(0.5*s.x/d+(s.y/d)/8.0,0.0,1.0);
#endif
float alpha=(1.0-col.w)*clamp(1.0-d/(px*t),0.0,1.0);
col+=vec4(clamp(scol,0.0,1.0),1.0)*alpha;
if(col.w>0.9)break;
}
t+=d;ro+=rd*d;od=d;
if(t>6.0)break;
}
col.rgb+=bcol*(1.0-clamp(col.w,0.0,1.0));
return col.rgb;
}
mat3 lookat(vec3 fw){
fw=normalize(fw);vec3 rt=normalize(cross(fw,vec3(0.0,1.0,0.0)));return mat3(rt,cross(rt,fw),fw);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
randomize(fragCoord);
float tim=iGlobalTime*0.3,r=2.0+cos(tim*0.7);
vec2 uv=(fragCoord-0.5*iResolution.xy)/iResolution.x;
vec3 ro=vec3(sin(tim)*r,sin(tim*0.4),cos(tim)*r);
vec3 rd=lookat(-ro)*normalize(vec3(uv,1.0));
//rd+=2.0*cross(qrt.xyz,cross(qrt.xyz,rd)+qrt.w*rd);
fragColor=vec4(scene(ro,rd)*2.0,1.0);
}
`;
// FROM shadertoy.com
const shadertoyBoilerplate = `
#extension GL_OES_standard_derivatives : enable
//#extension GL_EXT_shader_texture_lod : enable
#ifdef GL_ES
precision highp float;
#endif
uniform vec3 iResolution;
uniform float iGlobalTime;
uniform float iChannelTime[4];
uniform vec4 iMouse;
uniform vec4 iDate;
uniform float iSampleRate;
uniform vec3 iChannelResolution[4];
uniform int iFrame;
uniform float iTimeDelta;
uniform float iFrameRate;
struct Channel
{
vec3 resolution;
float time;
};
uniform Channel iChannel[4];
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
uniform sampler2D iChannel2;
uniform sampler2D iChannel3;
void mainImage( out vec4 c, in vec2 f );
${userShader}
void main( void ){
vec4 color = vec4(0.0,0.0,0.0,1.0);
mainImage( color, gl_FragCoord.xy );
color.w = 1.0;
gl_FragColor = color;
}
`;
const $ = document.querySelector.bind(document);
const camera = new THREE.Camera();
camera.position.z = 1;
const scene = new THREE.Scene();
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
-1, -1,
1, -1,
-1, 1,
-1, 1,
1, -1,
1, 1,
]);
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 2 ) );
const uniforms = {
iGlobalTime: { type: "f", value: 1.0 },
iResolution: { type: "v3", value: new THREE.Vector3() },
};
const material = new THREE.RawShaderMaterial({
uniforms: uniforms,
vertexShader: vs,
fragmentShader: shadertoyBoilerplate,
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
var renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);
resize(true);
render(0);
function resize(force) {
var canvas = renderer.domElement;
var dpr = 1; //window.devicePixelRatio; // make 1 or less if too slow
var width = canvas.clientWidth * dpr;
var height = canvas.clientHeight * dpr;
if (force || width != canvas.width || height != canvas.height) {
renderer.setSize( width, height, false );
uniforms.iResolution.value.x = renderer.domElement.width;
uniforms.iResolution.value.y = renderer.domElement.height;
}
}
function render(time) {
resize();
uniforms.iGlobalTime.value = time * 0.001;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
canvas {
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r74/three.min.js"></script>
The code above from shadertoy passes gl_FragCoord as input to the user's shader which is the pixel coordinate of the pixel being drawn in the canvas.
For a model we can pass in UV coordinates instead, we just have to choose a resolution to multiply them by since UV coordinates usually go from 0 to 1 and the shadertoy shaders are expecting 0 to canvas.width and 0 to canvas.height
Example:
const vs = `
varying vec2 vUv;
void main()
{
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
`;
const userShader = `
// FROM: https://www.shadertoy.com/view/4sdXDl
//spikey
#define SHAPE length(z.yz)
//normal
//#define SHAPE length(z.xyz)
//bizarro
//#define SHAPE length(z.yz-z.xx)
//etc...
#define HIGH_QUAL
#ifdef HIGH_QUAL
#define MARCH_STEPS 199
#else
#define MARCH_STEPS 99
#endif
float k=7.0+3.0*sin(iGlobalTime*0.15);
vec3 mcol=vec3(0.0);
void AbsBox(inout vec4 z){//abs box by kali
z.xyz=abs(z.xyz+1.0)-1.0;
z*=1.5/clamp(dot(z.xyz,z.xyz),0.25,1.0);
}
void Bulb(inout vec4 z, in vec4 c){//mandelBulb by twinbee
float r = length(z.xyz);
float zo = asin(z.z / r) * k + iGlobalTime*0.15;
float zi = atan(z.y, z.x) * 7.0;
z=pow(r, k-1.0)*vec4(r*vec3(cos(zo)*vec2(cos(zi),sin(zi)),sin(zo)),z.w*k)+c;
}
float DE(vec3 p){
vec4 c = vec4(p,1.0),z = c;
Bulb(z,c);
float r0=(length(z.xyz)-1.15)/z.w;
z.xyz-=1.0;
for(int i=0;i<7;i++)AbsBox(z);
float r=SHAPE;
mcol.rgb=vec3(1.0,0.5,0.2)+abs(sin(0.2*r+100.0*z.yxz/z.w));
return 0.5 * max((r-1.0) / z.w,-r0);
}
vec3 sky(vec3 rd, vec3 L){//modified bananaft's & public_int_i's code
float d=0.4*dot(rd,L)+0.6;
//return vec3(d);
rd.y+=sin(sqrt(clamp(-rd.y,0.0,0.9))*90.0)*0.45*max(-0.1,rd.y);
rd=abs(rd);
float y=max(0.,L.y),sun=max(1.-(1.+10.*y+rd.y)*length(rd-L),0.)
+.3*pow(1.-rd.y,12.)*(1.6-y);
return d*mix(vec3(0.3984,0.5117,0.7305),vec3(0.7031,0.4687,0.1055),sun)
*((.5+pow(y,.4))*(1.5-abs(L.y))+pow(sun,5.2)*y*(5.+15.0*y));
}
float rnd;
void randomize(in vec2 p){rnd=fract(float(iFrame)+sin(dot(p,vec2(13.3145,117.7391)))*42317.7654321);}
float ShadAO(in vec3 ro, in vec3 rd){
float t=0.0,s=1.0,d,mn=0.01;
for(int i=0;i<12;i++){
d=max(DE(ro+rd*t)*1.5,mn);
s=min(s,d/t+t*0.5);
t+=d;
}
return s;
}
vec3 scene(vec3 ro, vec3 rd){
vec3 L=normalize(vec3(0.4,0.025,0.5));
vec3 bcol=sky(rd,L);
vec4 col=vec4(0.0);//color accumulator
float t=DE(ro)*rnd,d,od=1.0,px=1.0/iResolution.x;
for(int i=0;i<MARCH_STEPS;i++){
d=DE(ro);
if(d<px*t){
float dif=clamp(1.0-d/od,0.2,1.0);
vec3 scol=mcol*dif*(1.3-0.3*t);
#ifdef HIGH_QUAL
vec2 s=vec2(DE(ro+d*4.0*L),DE(ro+d*16.0*L));
scol*=clamp(0.5*s.x/d+(s.y/d)/8.0,0.0,1.0);
#endif
float alpha=(1.0-col.w)*clamp(1.0-d/(px*t),0.0,1.0);
col+=vec4(clamp(scol,0.0,1.0),1.0)*alpha;
if(col.w>0.9)break;
}
t+=d;ro+=rd*d;od=d;
if(t>6.0)break;
}
col.rgb+=bcol*(1.0-clamp(col.w,0.0,1.0));
return col.rgb;
}
mat3 lookat(vec3 fw){
fw=normalize(fw);vec3 rt=normalize(cross(fw,vec3(0.0,1.0,0.0)));return mat3(rt,cross(rt,fw),fw);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
randomize(fragCoord);
float tim=iGlobalTime*0.3,r=2.0+cos(tim*0.7);
vec2 uv=(fragCoord-0.5*iResolution.xy)/iResolution.x;
vec3 ro=vec3(sin(tim)*r,sin(tim*0.4),cos(tim)*r);
vec3 rd=lookat(-ro)*normalize(vec3(uv,1.0));
//rd+=2.0*cross(qrt.xyz,cross(qrt.xyz,rd)+qrt.w*rd);
fragColor=vec4(scene(ro,rd)*2.0,1.0);
}
`;
// FROM shadertoy.com
const shadertoyBoilerplate = `
#extension GL_OES_standard_derivatives : enable
//#extension GL_EXT_shader_texture_lod : enable
#ifdef GL_ES
precision highp float;
#endif
uniform vec3 iResolution;
uniform float iGlobalTime;
uniform float iChannelTime[4];
uniform vec4 iMouse;
uniform vec4 iDate;
uniform float iSampleRate;
uniform vec3 iChannelResolution[4];
uniform int iFrame;
uniform float iTimeDelta;
uniform float iFrameRate;
struct Channel
{
vec3 resolution;
float time;
};
uniform Channel iChannel[4];
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
uniform sampler2D iChannel2;
uniform sampler2D iChannel3;
varying vec2 vUv;
void mainImage( out vec4 c, in vec2 f );
${userShader}
void main( void ){
vec4 color = vec4(0.0,0.0,0.0,1.0);
mainImage( color, vUv * iResolution.xy );
color.w = 1.0;
gl_FragColor = color;
}
`;
const $ = document.querySelector.bind(document);
const fieldOfView = 45;
const zNear = .1;
const zFar = 100;
const camera = new THREE.PerspectiveCamera(fieldOfView, 1, zNear, zFar);
camera.position.z = 3;
const scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(1, 1, 1);
const uniforms = {
iGlobalTime: { type: "f", value: 1.0 },
iResolution: { type: "v3", value: new THREE.Vector3() },
};
// choose a resolution to pass to the shader
uniforms.iResolution.value.x = 100;
uniforms.iResolution.value.y = 100;
const material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vs,
fragmentShader: shadertoyBoilerplate,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
var renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);
resize(true);
render(0);
function resize(force) {
const canvas = renderer.domElement;
const dpr = 1; //window.devicePixelRatio; // make 1 or less if too slow
const width = canvas.clientWidth * dpr;
const height = canvas.clientHeight * dpr;
if (force || width != canvas.width || height != canvas.height) {
renderer.setSize( width, height, false );
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
}
function render(time) {
time *= 0.001; // seconds
resize();
uniforms.iGlobalTime.value = time;
mesh.rotation.x = time * 0.5;
mesh.rotation.y = time * 0.6;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.min.js"></script>
Note that shadertoy shaders are generally not designed to be used as materials. They are not efficient, rather they are more like a fun activity of "how cool an image can I make using only time and pixel location as input". Because of that while the results can be amazing they are often 10x or 100x or even 1000x slower than traditional techniques for materials (using textures)
Compare for example this amazing shader which draws an entire city but at least on my machine it runs at 10-18fps in a small window and 1fps when fullscreen. VS for example Grand Theft Auto 5 which also shows an entire city yet manages to run at 30-60fps when fullscreen on the same machine.
There is a lot of fun to be had and lots of interesting techniques to learn on shadertoy.com that might be useful in your shaders but don't mistake what's there for "production" techniques. It's called shaderTOY for a reason 😉

THREE.js Color texture by shader

i've added simple box to my scene, and I want to create shader that will add a texture to it and add color to this texture.
This is my vertex shader(nothing special about it):
<script id="vertexShader" type="x-shader/x-vertex">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
</script>
And this is my fragment shader:
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec2 resolution;
uniform float time;
uniform sampler2D texture;
varying vec2 vUv;
uniform vec3 color;
varying vec3 vColor;
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord.xy / vec2(1920.0, 1920.0);
fragColor = vec4(uv, 0.5 + 0.5 * cos(time) * sin(time) ,1.0);
}
void main( void ) {
vec4 color = vec4(0.0,0.0,0.0,1.0);
mainImage( color, gl_FragCoord.xy );
color.w = 1.0;
gl_FragColor = texture2D(texture, vUv);
gl_FragColor = color;
}
</script>
As You can see, in two last lines i've sets gl_FragColor with texture and color.
When last line is gl_FragColor = color; The result is:
When i change order and last line is gl_FragColor = texture2D(texture, vUv); The result is:
This is the code that use shader and add a box to a scene:
var geometry = new THREE.BoxGeometry(.5, 1, .5);
uniforms = {
time: { type: "f", value: 1.0 },
resolution: { type: "v2", value: new THREE.Vector2() },
texture: { type: "t", value: THREE.ImageUtils.loadTexture("../img/disc.png") }
};
var material = new THREE.ShaderMaterial({
transparent: true,
uniforms: uniforms,
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
Is there a possibility to color my texture(mix color and texture in object) by this shader in the same way like in the picture?
Just like any other variable setting it twice just makes it the 2nd result;
var foo;
foo = 123;
foo = 456;
foo now equals 456
If you want to combine the results you need to something yourself to combine them
gl_FragColor = texture2D(texture, vUv);
gl_FragColor = color;
Just means gl_FragColor equals color;
I'm guessing you want something like
gl_FragColor = texture2D(texture, vUv) * color;
But of course what math you use is up to you depending on what you're trying to achieve.
Given your example texture and color above multiplying the texture by the color you'll get a circle with a gradient color. It's not clear if that's the result you wanted.

Categories