Fragment Shader not showing in ThreeJS - javascript

I am new to threejs and implementing shaders in it. I brought a fun shader in but I am having issues with displaying it. I believe it is related to the variable "len" in the code but I am not sure. Here is the link to the codepen https://codepen.io/Yerbs/pen/eYWgevO. Any Help would be appreciated
This is the frag shader
fragmentShader: `
uniform vec2 resolution;
uniform float time;
const int AMOUNT = 12;
void main() {
vec2 coord = 20.0 * (gl_FragCoord.xy - resolution / 2.0) / min(resolution.y, resolution.x);
float len;
for (int i = 0; i < AMOUNT; i++){
len = length(vec2(coord.x, coord.y));
coord.x = coord.x - cos(coord.y + sin(len)) + cos(time / 9.0);
coord.y = coord.y + sin(coord.x + cos(len)) + sin(time / 12.0);
}
gl_FragColor = vec4(cos(len * 2.0), cos(len * 3.0), cos(len * 1.0), 1.0);
}
`
});
I have tested out previous code so I know it is related to the fragment itself.

You need to set the values of the uniforms variables time and resolution (see ShaderMaterial). e.g:
const material = new THREE.ShaderMaterial({
uniforms: {
time: { type: "f", value: 0.0 },
resolution: { type: "v2", value: new THREE.Vector2() },
},
// [...]
function animate(timestamp) {
requestAnimationFrame(animate);
material.uniforms.time.value = timestamp / 1000;
material.uniforms.resolution.value.x = renderer.domElement.width;
material.uniforms.resolution.value.y = renderer.domElement.height;
renderer.render(scene, camera);
}
Complete example:
const renderer = new THREE.WebGLRenderer({
antialias: false
});
renderer.setSize(window.innerWidth, window.innerHeight, 2);
document.body.appendChild(renderer.domElement);
window.addEventListener( 'resize', function(e) {
renderer.setSize(window.innerWidth, window.innerHeight, 2);
});
const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
const material = new THREE.ShaderMaterial({
uniforms: {
time: { type: "f", value: 0.0 },
resolution: { type: "v2", value: new THREE.Vector2() },
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4( position, 1.0 );
}
`,
fragmentShader: `
uniform vec2 resolution;
uniform float time;
const int AMOUNT = 12;
void main() {
vec2 coord = 20.0 * (gl_FragCoord.xy - resolution / 2.0) / min(resolution.y, resolution.x);
float len;
for (int i = 0; i < AMOUNT; i++){
len = length(vec2(coord.x, coord.y));
coord.x = coord.x - cos(coord.y + sin(len)) + cos(time / 9.0);
coord.y = coord.y + sin(coord.x + cos(len)) + sin(time / 12.0);
}
gl_FragColor = vec4(1.0, cos(len * 3.0), cos(len * 1.0), 1.0);
}
`
});
const quad = new THREE.Mesh(new THREE.PlaneBufferGeometry( 2, 2, 1, 1 ), material);
scene.add(quad);
function animate(timestamp) {
requestAnimationFrame(animate);
material.uniforms.time.value = timestamp / 1000;
material.uniforms.resolution.value.x = renderer.domElement.width;
material.uniforms.resolution.value.y = renderer.domElement.height;
renderer.render(scene, camera);
}
animate();
<script src="https://cdn.jsdelivr.net/npm/three#0.137/build/three.js"></script>

Related

Improve UV line quality of threejs/shader geometry

I'm using the uv output of threejs's torus to create moving lines across the torus. It works, but doesn't look crisp.
How can I improve the line quality?
I've tried making the material two-sided, and increasing the width of the lines, but the quality isn't improving much.
I haven't tried completely reproducing the torus outside of threejs, but that's out of my comfort zone.
I'm hoping there's way to change the logic of the fragment shader to produce clearer lines. I'd be greatful for any suggestions.
Codepen
/* Scene Initialization */
var startTime = Date.now();
var scene = new THREE.Scene();
var width = window.innerWidth;
var height = window.innerHeight;
var canvas = document.getElementById('canvas');
var camera = new THREE.PerspectiveCamera(75, 1, 1, 1200);
// var camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 1200 );
camera.position.set(0, -420, 600);
camera.lookAt(new THREE.Vector3(0, 0, 0));
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth * .2, window.innerWidth * .2);
renderer.setClearColor( 0xffffff, 1);
canvas.appendChild(renderer.domElement);
var geometry = new THREE.TorusGeometry(200, 200, 260, 260);
material = new THREE.ShaderMaterial( {
uniforms: {time: { type: "f", value: Date.now() - startTime}, },
vertexShader: `attribute vec3 center;
varying vec3 vCenter;
varying vec2 vUv;
void main() {
vCenter = center;
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`,
fragmentShader: `varying vec3 vCenter;
varying vec2 vUv;
uniform float time;
uniform sampler2D tDiffuse;
void main() {
float sh = 0.005;
float PI = 3.1415926535897932384626433832795;
// float linesX = mod(time + vUv.x, 0.03);
float linesX = sin((time + vUv.x) * PI * 30.)/30.;
// float linesY = mod(time + vUv.y, 0.05);
float linesY = sin((time + vUv.y) * PI * 20.)/20.;
float smoothX =
smoothstep( 0.0 - sh, 0.0, linesX) -
smoothstep( 0.0, 0.0 + sh, linesX);
float smoothY =
smoothstep( 0.0 - sh, 0.0, linesY) -
smoothstep( 0.0, 0.0 + sh, linesY);
float uvOutput = smoothX + smoothY;
gl_FragColor.rgb = vec3(1.0, 0, 0);
gl_FragColor.a = uvOutput;
// gl_FragColor = vec4(1.,0,0,1.)
}`
} );
//material.extensions.derivatives = true;
material.side = THREE.DoubleSide;
material.transparent = true;
//material.blending = THREE.Add;
material.depthTest = false;
var torus = new THREE.Mesh(geometry, material);
var geom = torus.geometry;
geometry.sortFacesByMaterialIndex();
torus.position.x = 0;
scene.add(torus);
/* Request Animation Frame */
function animation() {
camera.lookAt(new THREE.Vector3(0, 0, 0));
renderer.render(scene, camera);
material.uniforms.time.value = (Date.now() - startTime)/20000;
requestAnimationFrame(animation);
}
animation();
setupDraggableEvents();
function setupDraggableEvents() {
var hammer = new Hammer(document.getElementsByTagName('canvas')[0]);
hammer.on('pan', function(event) {
torus.rotation.y += event.velocityX / 10;
torus.rotation.x += event.velocityY / 10;
});
}
I recommend to define the number of lines for both directions and to calculate the distance to a line in terms of UV coordinates:
float t = time;
vec2 noLines = vec2(30.0, 20.0);
vec2 floorUV = floor((t + vUv) * noLines);
vec2 distUV = t + vUv - (floorUV+0.5) / noLines;
Smoothly interpolate between the thickness and the half thickness of a line (smoothstep), to calculate the "saturation". This causes that the line always has the full "strength" in the middle (of course you can experiment with this e.g. sh*0.66, sh*0.33):
float sh = 0.005;
vec2 lineUV = smoothstep(sh, sh*0.5, abs(distUV));
The alpha channel is the maximum "saturation" value of both directions:
float uvOutput = max(lineUV.x, lineUV.y);
gl_FragColor = vec4(1.0, 0.0, 0.0, uvOutput);
See the example, where I applied the suggested changes to your original code:
/* Scene Initialization */
var startTime = Date.now();
var scene = new THREE.Scene();
var width = window.innerWidth;
var height = window.innerHeight;
var canvas = document.getElementById('canvas');
var camera = new THREE.PerspectiveCamera(75, 1, 1, 1200);
camera.position.set(0, -420, 600);
camera.lookAt(new THREE.Vector3(0, 0, 0));
orbitControls = new THREE.OrbitControls(camera);
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth * .2, window.innerWidth * .2);
renderer.setClearColor( 0xffffff, 1);
canvas.appendChild(renderer.domElement);
var geometry = new THREE.TorusGeometry(200, 200, 260, 260);
material = new THREE.ShaderMaterial( {
uniforms: {time: { type: "f", value: Date.now() - startTime}, },
vertexShader: `attribute vec3 center;
varying vec3 vCenter;
varying vec2 vUv;
void main() {
vCenter = center;
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`,
fragmentShader: `varying vec3 vCenter;
varying vec2 vUv;
uniform float time;
uniform sampler2D tDiffuse;
void main() {
float t = time;
vec2 noLines = vec2(30.0, 20.0);
vec2 floorUV = floor((t + vUv) * noLines);
vec2 distUV = t + vUv - (floorUV+0.5) / noLines;
float sh = 0.005;
vec2 lineUV = smoothstep(sh, sh*0.5, abs(distUV));
float uvOutput = max(lineUV.x, lineUV.y);
gl_FragColor = vec4(1.0, 0.0, 0.0, uvOutput);
}`,
transparent: true
} );
//material.extensions.derivatives = true;
material.side = THREE.DoubleSide;
material.transparent = true;
//material.blending = THREE.Add;
material.depthTest = false;
var torus = new THREE.Mesh(geometry, material);
var geom = torus.geometry;
geometry.sortFacesByMaterialIndex();
torus.position.x = 0;
scene.add(torus);
/* Request Animation Frame */
function animation() {
camera.lookAt(new THREE.Vector3(0, 0, 0));
renderer.render(scene, camera);
material.uniforms.time.value = (Date.now() - startTime)/20000;
requestAnimationFrame(animation);
}
resize();
window.onresize = resize;
animation();
setupDraggableEvents();
function setupDraggableEvents() {
var hammer = new Hammer(document.getElementsByTagName('canvas')[0]);
hammer.on('pan', function(event) {
torus.rotation.y += event.velocityX / 10;
torus.rotation.x += event.velocityY / 10;
});
}
function resize() {
var aspect = window.innerWidth / window.innerHeight;
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = aspect;
camera.updateProjectionMatrix();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/100/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div id="canvas"></div>

Three.js: Custom sizes for each quad using InstancedBufferGeometry + ShaderMaterial

I am trying to create a scene full of points, each with unique width and heights. However, I can't figure out how to get into the vertex shader to move the vertices to create the custom sizes. Here's the scene:
// generate a scene object
var scene = new THREE.Scene();
scene.background = new THREE.Color(0xaaaaaa);
// generate a camera
var aspectRatio = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 10000);
camera.position.set(0, 1, -10);
// generate a renderer
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio); // <3 retina
renderer.setSize(window.innerWidth, window.innerHeight); // canvas size
document.body.appendChild(renderer.domElement);
// generate controls
var controls = new THREE.TrackballControls(camera, renderer.domElement);
// generate some lights
var ambientLight = new THREE.AmbientLight(0xeeeeee);
scene.add(ambientLight);
/**
* Add the points
**/
var BA = THREE.BufferAttribute;
var IBA = THREE.InstancedBufferAttribute;
var geometry = new THREE.InstancedBufferGeometry();
var n = 10000, // number of observations
rootN = n**(1/2),
cellSize = 20,
translations = new Float32Array(n * 3),
widths = new Float32Array(n),
heights = new Float32Array(n),
translationIterator = 0,
widthIterator = 0,
heightIterator = 0;
for (var i=0; i<n*3; i++) {
translations[translationIterator++] = (Math.random() * n) - (Math.random() * n);
translations[translationIterator++] = (Math.random() * n) - (Math.random() * n);
translations[translationIterator++] = (Math.random() * n) - (Math.random() * n);
widths[widthIterator++] = Math.random() * 20;
heights[heightIterator++] = Math.random() * 20;
}
// coordinates for template box
var size = 10,
verts = [
0, 0, 0, // lower left
size, 0, 0, // lower right
size, size, 0, // upper right
0, size, 0, // upper left
]
var positionAttr = new BA(new Float32Array(verts), 3),
translationAttr = new IBA(translations, 3, true, 1),
widthAttr = new IBA(widths, 1, true, 1),
heightAttr = new IBA(heights, 1, true, 1);
// we make two triangles but only use 4 distinct vertices in the object
// the second argument to THREE.BufferAttribute is the number of elements
// in the first argument per vertex
geometry.setIndex([0,1,2, 2,3,0])
geometry.addAttribute('position', positionAttr);
geometry.addAttribute('translation', translationAttr);
geometry.addAttribute('width', widthAttr);
geometry.addAttribute('height', heightAttr);
var material = new THREE.RawShaderMaterial({
vertexShader: document.getElementById('vertex-shader').textContent,
fragmentShader: document.getElementById('fragment-shader').textContent,
});
material.side = THREE.DoubleSide;
var mesh = new THREE.Mesh(geometry, material);
mesh.frustumCulled = false; // prevent the mesh from being clipped on drag
scene.add(mesh);
// render loop
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
controls.update();
};
// draw some geometries
var geometry = new THREE.TorusGeometry(10, 3, 16, 100);
var material = new THREE.MeshNormalMaterial({ color: 0xffff00 });
render();
html, body { width: 100vw; height: 100vh; background: #000; }
body { margin: 0; overflow: hidden; }
canvas { width: 100vw; height: 100vh; }
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js'></script>
<script src='https://threejs.org/examples/js/controls/TrackballControls.js'></script>
<script type='x-shader/x-vertex' id='vertex-shader'>
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform vec3 cameraPosition;
attribute vec3 position; // sets the blueprint's vertex positions
attribute vec3 translation; // x y translation offsets for an instance
attribute float width;
attribute float height;
void main() {
// set point position
vec3 pos = position + translation;
vec4 projected = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
gl_Position = projected;
}
</script>
<script type='x-shader/x-fragment' id='fragment-shader'>
precision highp float;
void main() {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
</script>
My question is: how can I use the width and height attributes to make each point have the given (relative) proportions specified by its width and height values? Can I query the index of the vertex being drawn within its given instance? Any suggestions would be very helpful!
Ah, it seems one can do the following in the vertex shader:
void main() {
// set point position
vec3 pos = position + translation;
pos.x = pos.x * width;
pos.y = pos.y * height;
vec4 projected = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
gl_Position = projected;
}
Full snippet:
// generate a scene object
var scene = new THREE.Scene();
scene.background = new THREE.Color(0xaaaaaa);
// generate a camera
var aspectRatio = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 10000);
camera.position.set(0, 1, -10);
// generate a renderer
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio); // <3 retina
renderer.setSize(window.innerWidth, window.innerHeight); // canvas size
document.body.appendChild(renderer.domElement);
// generate controls
var controls = new THREE.TrackballControls(camera, renderer.domElement);
// generate some lights
var ambientLight = new THREE.AmbientLight(0xeeeeee);
scene.add(ambientLight);
/**
* Add the points
**/
var BA = THREE.BufferAttribute;
var IBA = THREE.InstancedBufferAttribute;
var geometry = new THREE.InstancedBufferGeometry();
var n = 10000, // number of observations
rootN = n**(1/2),
cellSize = 20,
translations = new Float32Array(n * 3),
widths = new Float32Array(n),
heights = new Float32Array(n),
translationIterator = 0,
widthIterator = 0,
heightIterator = 0;
for (var i=0; i<n*3; i++) {
translations[translationIterator++] = (Math.random() * n) - (Math.random() * n);
translations[translationIterator++] = (Math.random() * n) - (Math.random() * n);
translations[translationIterator++] = (Math.random() * n) - (Math.random() * n);
widths[widthIterator++] = Math.random() * 20;
heights[heightIterator++] = Math.random() * 20;
}
// coordinates for template box
var size = 10,
verts = [
0, 0, 0, // lower left
size, 0, 0, // lower right
size, size, 0, // upper right
0, size, 0, // upper left
]
var positionAttr = new BA(new Float32Array(verts), 3),
translationAttr = new IBA(translations, 3, true, 1),
widthAttr = new IBA(widths, 1, true, 1),
heightAttr = new IBA(heights, 1, true, 1);
// we make two triangles but only use 4 distinct vertices in the object
// the second argument to THREE.BufferAttribute is the number of elements
// in the first argument per vertex
geometry.setIndex([0,1,2, 2,3,0])
geometry.addAttribute('position', positionAttr);
geometry.addAttribute('translation', translationAttr);
geometry.addAttribute('width', widthAttr);
geometry.addAttribute('height', heightAttr);
var material = new THREE.RawShaderMaterial({
vertexShader: document.getElementById('vertex-shader').textContent,
fragmentShader: document.getElementById('fragment-shader').textContent,
});
material.side = THREE.DoubleSide;
var mesh = new THREE.Mesh(geometry, material);
mesh.frustumCulled = false; // prevent the mesh from being clipped on drag
scene.add(mesh);
// render loop
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
controls.update();
};
// draw some geometries
var geometry = new THREE.TorusGeometry(10, 3, 16, 100);
var material = new THREE.MeshNormalMaterial({ color: 0xffff00 });
render();
html, body { width: 100vw; height: 100vh; background: #000; }
body { margin: 0; overflow: hidden; }
canvas { width: 100vw; height: 100vh; }
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js'></script>
<script src='https://threejs.org/examples/js/controls/TrackballControls.js'></script>
<script type='x-shader/x-vertex' id='vertex-shader'>
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform vec3 cameraPosition;
attribute vec3 position; // sets the blueprint's vertex positions
attribute vec3 translation; // x y translation offsets for an instance
attribute float width;
attribute float height;
void main() {
// set point position
vec3 pos = position + translation;
vec4 projected = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
gl_Position = projected;
}
</script>
<script type='x-shader/x-fragment' id='fragment-shader'>
precision highp float;
void main() {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
</script>

Generate particle with 3 shades of the same color Three

Hello I have searched the internet but I have not found anything on, I am trying to make 1 globe in the form of particles with the mix of 3 colors pink, dark pink and white equal to that image down
I need the colors to look like this picture, normal pink, dark pink and whit
the problem is that my Globe is left with 1 single color instead of varios like the image, all help is grateful, thank you all at once
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth /
window.innerHeight, 1, 1000);
camera.position.z = 10;
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor(0x2675AD);
renderer.setSize(window.innerWidth, window.innerHeight);
var globe = document.getElementById('globe')
globe.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var geom = new THREE.SphereBufferGeometry(5, 320, 160);
var colors = [];
var color = new THREE.Color();
var q = 0xC83C84;
for (let i = 0; i < geom.attributes.position.count; i++) {
color.set(Math.random() * q);
color.toArray(colors, i * 3);
}
geom.addAttribute('color', new THREE.BufferAttribute(new
Float32Array(colors), 3));
var loader = new THREE.TextureLoader();
loader.setCrossOrigin('');
var texture = loader.load('../img/equirectangle_projection.png');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(1, 1);
var disk = loader.load('../img/circleround.png');
var points = new THREE.Points(geom, new THREE.ShaderMaterial({
vertexColors: THREE.VertexColors,
uniforms: {
visibility: {
value: texture
},
shift: {
value: 0
},
shape: {
value: disk
},
size: {
value: 0.125
},
scale: {
value: window.innerHeight / 2
}
},
vertexShader: `
uniform float scale;
uniform float size;
varying vec2 vUv;
varying vec3 vColor;
void main() {
vUv = uv;
vColor = color;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size * ( scale / length( mvPosition.xyz ) );
gl_Position = projectionMatrix * mvPosition;
}
`,
fragmentShader: `
uniform sampler2D visibility;
uniform float shift;
uniform sampler2D shape;
varying vec2 vUv;
varying vec3 vColor;
void main() {
vec2 uv = vUv;
uv.x += shift;
vec4 v = texture2D(visibility, uv);
if (length(v.rgb) > 1.0) discard;
gl_FragColor = vec4( vColor, 1.0 );
vec4 shapeData = texture2D( shape, gl_PointCoord );
if (shapeData.a < 0.5) discard;
gl_FragColor = gl_FragColor * shapeData;
}
`,
transparent: true
}));
scene.add(points);
var blackGlobe = new THREE.Mesh(geom, new
THREE.MeshBasicMaterial({
color: 0x2675AD
}));
blackGlobe.scale.setScalar(0.99);
points.add(blackGlobe);
var clock = new THREE.Clock();
var time = 0;
render();
function render() {
requestAnimationFrame(render);
time += clock.getDelta();
points.rotation.y += 0.0009
renderer.render(scene, camera);
}
You can use an array of colour values and pick those values randomly:
var q = ["white", "pink", 0xb2497d, "gray"];
for (let i = 0; i < geom.attributes.position.count; i++) {
color.set(q[THREE.Math.randInt(0,3)]);
color.toArray(colors, i * 3);
}
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(1.25, 7, 7);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor(0x080808);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var geom = new THREE.SphereBufferGeometry(5, 120, 60);
var colors = [];
var color = new THREE.Color();
var q = ["white", "pink", 0xb2497d, "gray"];
for (let i = 0; i < geom.attributes.position.count; i++) {
color.set(q[THREE.Math.randInt(0,3)]);
color.toArray(colors, i * 3);
}
geom.addAttribute('color', new THREE.BufferAttribute(new Float32Array(colors), 3));
var loader = new THREE.TextureLoader();
loader.setCrossOrigin('');
var texture = loader.load('http://learningthreejs.com/data/2013-09-16-how-to-make-the-earth-in-webgl/demo/bower_components/threex.planets/images/earthspec1k.jpg');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(1, 1);
var disk = loader.load('https://threejs.org/examples/textures/sprites/circle.png');
var points = new THREE.Points(geom, new THREE.ShaderMaterial({
vertexColors: THREE.VertexColors,
uniforms: {
visibility: {
value: texture
},
shift: {
value: 0
},
shape: {
value: disk
},
size: {
value: 0.125
},
scale: {
value: window.innerHeight / 2
}
},
vertexShader: `
uniform float scale;
uniform float size;
varying vec2 vUv;
varying vec3 vColor;
void main() {
vUv = uv;
vColor = color;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size * ( scale / length( mvPosition.xyz ) );
gl_Position = projectionMatrix * mvPosition;
}
`,
fragmentShader: `
uniform sampler2D visibility;
uniform float shift;
uniform sampler2D shape;
varying vec2 vUv;
varying vec3 vColor;
void main() {
vec2 uv = vUv;
uv.x += shift;
vec4 v = texture2D(visibility, uv);
if (length(v.rgb) > 1.0) discard;
gl_FragColor = vec4( vColor, 1.0 );
vec4 shapeData = texture2D( shape, gl_PointCoord );
if (shapeData.a < 0.5) discard;
gl_FragColor = gl_FragColor * shapeData;
}
`,
transparent: true
}));
scene.add(points);
var blackGlobe = new THREE.Mesh(geom, new THREE.MeshBasicMaterial({
color: 0x000000
}));
blackGlobe.scale.setScalar(0.99);
points.add(blackGlobe);
var clock = new THREE.Clock();
var time = 0;
render();
function render() {
requestAnimationFrame(render);
time += clock.getDelta();
points.material.uniforms.shift.value = time * 0.1;
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Three.js envmaps and vertex animation

I am making my first steps coding with JavaScript and playing with Three.js.
I am learning how to use Shaders and I have a week stuck with a vertex animation that doesn't work.
This one is my Vertex Shader:
uniform float fresnelBias;
uniform float amplitude;
uniform float fresnelScale;
uniform float fresnelPower;
attribute float displacement;
varying float vReflectionFactor;
varying vec3 vReflect;
void main() {
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
vec3 worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );
vec3 I = worldPosition.xyz - cameraPosition;
vReflect = reflect( I, worldNormal );
vReflectionFactor = fresnelBias + fresnelScale * pow( 1.0 + dot( normalize( I ), worldNormal ), fresnelPower );
gl_Position = projectionMatrix * mvPosition;
}
and this one is Fragment Shader:
uniform vec3 color;
uniform samplerCube envMap;
varying vec3 vReflect;
varying float vReflectionFactor;
void main() {
vec4 envColor = textureCube( envMap, vec3( -vReflect.x, vReflect.yz ) );
gl_FragColor = vec4(mix(color, envColor.xyz, vec3(clamp( vReflectionFactor, 0.0, 1.0 ))), 1.0);
}
Then I declared a variable to my attributes and another to my uniforms to assign it to a geometry but when I load the site I don't see anything. The JavaScript console tells that in this line uniforms.amplitude.value = Math.sin(frame); uniforms is not defined.
Do you have some recomendation? Do you know something that I can do?
I let here my complete code I hope it could help:
<script id="vertexShader" type="x-shader/x-vertex">
uniform float fresnelBias;
uniform float amplitude;
uniform float fresnelScale;
uniform float fresnelPower;
attribute float displacement;
varying float vReflectionFactor;
varying vec3 vReflect;
void main() {
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
vec3 worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );
vec3 I = worldPosition.xyz - cameraPosition;
vReflect = reflect( I, worldNormal );
vReflectionFactor = fresnelBias + fresnelScale * pow( 1.0 + dot( normalize( I ), worldNormal ), fresnelPower );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec3 color;
uniform samplerCube envMap;
varying vec3 vReflect;
varying float vReflectionFactor;
void main() {
vec4 envColor = textureCube( envMap, vec3( -vReflect.x, vReflect.yz ) );
gl_FragColor = vec4(mix(color, envColor.xyz, vec3(clamp( vReflectionFactor, 0.0, 1.0 ))), 1.0);
}
</script>
<script>
var camera, scene, renderer;
var mesh, material, controls, sky;
init();
animate();
function init(){
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setClearColor(0xfffff, 0);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.z = 400;
//controls = new THREE.TrackballControls( camera );
scene = new THREE.Scene();
var numberOfImages = 46, images = [];
for (var i = 1; i <= numberOfImages; i++) {
images.push('sources/instagram2/image' + i + ".jpg");
}
var urls = images.sort(function(){return .6 - Math.random()}).slice(0,6);
var textureCube = THREE.ImageUtils.loadTextureCube( urls );
// Skybox
var skyshader = THREE.ShaderLib[ "cube" ];
skyshader.uniforms[ "tCube" ].value = textureCube;
var skymaterial = new THREE.ShaderMaterial( {
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
uniforms: skyshader.uniforms,
depthWrite: false,
side: THREE.BackSide
} );
sky = new THREE.Mesh( new THREE.BoxGeometry( 1500, 1500, 1500 ), skymaterial );
sky.visible = false;
scene.add( sky );
var attributes = {
displacement: {
type: 'f', // a float
value: [] // an empty array
}
};
var uniforms = {
color: {
type: "c",
value: new THREE.Color(0x000000),
},
envMap: {
type: "t",
value: textureCube
},
fresnelBias: {
type: "f",
value: 0.1
},
fresnelScale: {
type: "f",
value: 1.0
},
fresnelPower: {
type: 'f',
value: 2.0
},
amplitude: {
type: 'f',
value: 0
}
};
var vertexShader = document.getElementById('vertexShader').text;
var fragmentShader = document.getElementById('fragmentShader').text;
material = new THREE.ShaderMaterial(
{
uniforms : uniforms,
vertexShader : vertexShader,
fragmentShader : fragmentShader,
});
var loader = new THREE.BinaryLoader();
loader.load( "sources/obj/mmlogo/mm_logo.js", function ( geometry ) {
mesh = new THREE.Mesh(geometry, material);
mesh.scale.set( 300, 300, 300 );
var vertices = mesh.geometry.vertices;
var values = attributes.displacement.value
for(var v = 0; v < vertices.length; v++) {
values.push(Math.random() * 10);
}
scene.add(mesh);
} );
var light = new THREE.AmbientLight( 0x404040 ); // soft white light
scene.add( light );
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
var frame = 0;
function animate() {
uniforms.amplitude.value = Math.sin(frame);
frame += 0.01;
requestAnimationFrame(animate);
//controls.update();
//mesh.rotation.x += 0.005;
//mesh.rotation.y += 0.005;
renderer.render(scene, camera);
stats.update();
}
Update:
I Added the uniforms variable to the global scope and now the console doesn't show me any problem but I can't see the vertex animation:
<script id="vertexShader" type="x-shader/x-vertex">
uniform float fresnelBias;
uniform float amplitude;
uniform float fresnelScale;
uniform float fresnelPower;
attribute float displacement;
varying float vReflectionFactor;
varying vec3 vReflect;
void main() {
vec3 newPosition = position + normal * vec3(displacement * amplitude);
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
vec3 worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );
vec3 I = worldPosition.xyz - cameraPosition;
vReflect = reflect( I, worldNormal );
vReflectionFactor = fresnelBias + fresnelScale * pow( 1.0 + dot( normalize( I ), worldNormal ), fresnelPower );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec3 color;
uniform samplerCube envMap;
varying vec3 vReflect;
varying float vReflectionFactor;
void main() {
vec4 envColor = textureCube( envMap, vec3( -vReflect.x, vReflect.yz ) );
gl_FragColor = vec4(mix(color, envColor.xyz, vec3(clamp( vReflectionFactor, 0.0, 1.0 ))), 1.0);
}
</script>
<script>
var camera, scene, renderer;
var mesh, material, controls, sky;
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setClearColor(0xfffff, 0);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.z = 400;
scene = new THREE.Scene();
var numberOfImages = 46, images = [];
for (var i = 1; i <= numberOfImages; i++) {
images.push('sources/instagram2/image' + i + ".jpg");
}
var urls = images.sort(function(){return .6 - Math.random()}).slice(0,6);
var textureCube = THREE.ImageUtils.loadTextureCube( urls );
var skyshader = THREE.ShaderLib[ "cube" ];
skyshader.uniforms[ "tCube" ].value = textureCube;
var skymaterial = new THREE.ShaderMaterial( {
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
uniforms: skyshader.uniforms,
depthWrite: false,
side: THREE.BackSide
} );
sky = new THREE.Mesh( new THREE.BoxGeometry( 1500, 1500, 1500 ), skymaterial );
sky.visible = false;
scene.add( sky );
var attributes = {
displacement: {
type: 'f',
value: []
}
};
var uniforms = {
color: {
type: "c",
value: new THREE.Color(0x000000),
},
envMap: {
type: "t",
value: textureCube
},
fresnelBias: {
type: "f",
value: 0.1
},
fresnelScale: {
type: "f",
value: 1.0
},
fresnelPower: {
type: 'f',
value: 2.0
},
amplitude: {
type: 'f',
value: 0
}
};
var vertexShader = document.getElementById('vertexShader').text;
var fragmentShader = document.getElementById('fragmentShader').text;
material = new THREE.ShaderMaterial(
{
uniforms : uniforms,
vertexShader : vertexShader,
fragmentShader : fragmentShader,
});
var loader = new THREE.BinaryLoader();
loader.load( "sources/obj/mmlogo/mm_logo.js", function ( geometry ) {
mesh = new THREE.Mesh(geometry, material);
mesh.scale.set( 100, 100, 100 );
var vertices = mesh.geometry.vertices;
var values = attributes.displacement.value
for(var v = 0; v < vertices.length; v++) {
values.push(Math.random() * 30);
}
scene.add(mesh);
} );
var light = new THREE.AmbientLight( 0x404040 );
scene.add( light );
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
var frame = 0;
function animate() {
uniforms.amplitude.value = Math.sin(frame);
frame += 0.1;
requestAnimationFrame(animate);
//controls.update();
//mesh.rotation.x += 0.005;
//mesh.rotation.y += 0.005;
renderer.render(scene, camera);
}
animate();
</script>
Do you have some conseil to make it?
You have defined the uniforms variable in the init() function so it's scope is within that function and can not be accessed in the animate() function.
Add the uniforms variable to the global scope and you should be fine.

No output in canvas when integrating Shadertoy

I stumbled upon this SO post describing a way to port shadertoy examples into threejs.
I tried following along and ended up with this plunk. The fragment shader looks like this
#ifdef GL_ES
precision highp float;
#endif
uniform float iGlobalTime;
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
varying vec2 vUv;
void main(void)
{
vec2 p = -1.0 + 2.0 *vUv;
vec2 q = p - vec2(0.5, 0.5);
q.x += sin(iGlobalTime* 0.6) * 0.2;
q.y += cos(iGlobalTime* 0.4) * 0.3;
float len = length(q);
float a = atan(q.y, q.x) + iGlobalTime * 0.3;
float b = atan(q.y, q.x) + iGlobalTime * 0.3;
float r1 = 0.3 / len + iGlobalTime * 0.5;
float r2 = 0.2 / len + iGlobalTime * 0.5;
float m = (1.0 + sin(iGlobalTime * 0.5)) / 2.0;
vec4 tex1 = texture2D(iChannel0, vec2(a + 0.1 / len, r1 ));
vec4 tex2 = texture2D(iChannel1, vec2(b + 0.1 / len, r2 ));
vec3 col = vec3(mix(tex1, tex2, m));
gl_FragColor = vec4(col * len * 1.5, 1.0);
}
and the threejs code like this
window.addEventListener("load", function () {
// Camera variables.
var width = window.innerWidth;
var height = window.innerHeight;
var aspect = width/height;
var fov = 65;
var clipPlaneNear = 0.1;
var clipPlaneFar = 1000;
var clearColor = 0x221f26;
var clearAlpha = 1.0;
// main container.
var $container = $('#container');
// Clock
var clock = new THREE.Clock();
// Set up uniform.
var tuniform = {
iGlobalTime: { type: 'f', value: 0.1 },
iChannel0: { type: 't', value: THREE.ImageUtils.loadTexture( 'images/tex07.jpg') },
iChannel1: { type: 't', value: THREE.ImageUtils.loadTexture( 'images/tex03.jpg' ) },
};
tuniform.iChannel0.value.wrapS = tuniform.iChannel0.value.wrapT = THREE.RepeatWrapping;
tuniform.iChannel1.value.wrapS = tuniform.iChannel1.value.wrapT = THREE.RepeatWrapping;
// Set up our scene.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(fov, aspect, clipPlaneNear, clipPlaneFar);
//camera.position.z = 10;
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(width, height);
renderer.setClearColor(new THREE.Color(clearColor, clearAlpha));
$container.append(renderer.domElement);
var mat = new THREE.ShaderMaterial( {
uniforms: tuniform,
vertexShader: $('#vertexshader').text(),
fragmentShader: $('#fragmentshader').text(),
side:THREE.DoubleSide
} );
tuniform.iGlobalTime.value += clock.getDelta();
var tobject = new THREE.Mesh( new THREE.PlaneGeometry(700, 394,1,1), mat);
//var tobject = new THREE.Mesh( new THREE.PlaneBufferGeometry (700, 394,1,1), mat);
scene.add(tobject);
// Keep updating our scene.
var loop = function loop() {
renderer.render(scene, camera);
};
loop();
}, false);
As you can see from the plunk, there is no output in the page. What have I done wrong in this case, and how can I successfully implement the shader in threejs?
Your camera should be at camera.position.z = 1000; and
Your loop code should be:
var loop = function loop() {
requestAnimationFrame(loop);
tuniform.iGlobalTime.value += clock.getDelta();
renderer.render(scene, camera);
};
loop();
Updated plunker:

Categories

Resources