I'm trying to create textual labels. I need to use shader material to better control the label during rendering.
I've noticed that the memory keeps increasing even though I clean up old labels.
I've created a jsfiddle example that is not unlike: https://threejs.org/examples/#webgl_test_memory
The following code uses a canvas object to generate a texture, which contains the text to be depicted as a label:
Please be careful, these computations are heavy and make the tab quite unresponsive.
var container;
var camera, scene, renderer;
var labels;
var canvas;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 200;
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
labels = new THREE.Object3D();
canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
// get text metrics
var fontface = 'Arial';
var fontSize = 60;
context.font = fontSize + "px " + fontface;
var width = context.measureText(text).width;
// add text
var text = 'abcdef';
canvas.width = width;
canvas.height = fontSize*1.3;
context.textAlign = "center";
context.font = fontSize + "px " + fontface;
context.fillStyle = "white";
context.fillText(text, canvas.width / 2, canvas.height / 2);
}
function createLabels() {
for(var i = 0; i < 10000 ; i++) {
createTextMesh();
}
scene.add( labels );
}
function createTextMesh() {
// canvas contents will be used for a texture
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
var uniforms = {
text: {
type: 't',
value: texture
}
};
var material = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: document.getElementById( 'vertex-shader' ).textContent,
fragmentShader: document.getElementById( 'fragment-shader' ).textContent
} );
var geometry = new THREE.PlaneBufferGeometry(15, 15);
var label = new THREE.Mesh( geometry, material );
labels.add(label);
}
function clearLabels() {
for(var i = 0; i < labels.children.length; i++) {
var label = labels.children[i];
if(label.material.uniforms) {
label.material.uniforms.text.value.dispose();
}
label.material.dispose();
label.geometry.dispose();
labels.remove(label);
}
scene.remove( labels );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
// build GL objects
createLabels();
renderer.render( scene, camera );
// clean up
clearLabels();
}
body {
margin:0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js"></script>
<script id="fragment-shader" type="x-shader/x-fragment">
uniform sampler2D text;
varying vec2 vUv;
void main() {
vec4 finalColor = texture2D(text, vUv);
gl_FragColor = finalColor;
}
</script>
<script id="vertex-shader" type="x-shader/x-fragment">
varying vec2 vUv;
void main() {
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<canvas></canvas>
You can use's chromes dev tools to evaluate the perceptual memory utilisation increase.
I'd recommend using something like Window's own task manager to see the memory increase.
You can decrease the label creation speed, although this will naturally mean that it will take longer for the tab do run out of memory.
Am I doing the resource clean-up wrongly?
Cheers
Hi try out following code
as I have added time gap in animate function which calls render function.
there is one variable fps currently 24, you can change it.
<!DOCTYPE html>
<html lang="en">
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>three.js - shader material memory leak</title>
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
background:#fff;
padding:0;
margin:0;
overflow:hidden;
}
</style>
</head>
<body>
<script src="https://threejs.org/build/three.js"></script>
<script id="fragment-shader" type="x-shader/x-fragment">
uniform sampler2D text;
varying vec2 vUv;
void main() {
vec4 finalColor = texture2D(text, vUv);
gl_FragColor = finalColor;
}
</script>
<script id="vertex-shader" type="x-shader/x-fragment">
varying vec2 vUv;
void main() {
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script>
var container,
camera, scene, renderer,
labels,
canvas,
lastTime, fps = 24;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 200;
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
labels = new THREE.Object3D();
canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
// get text metrics
var fontface = 'Arial';
var fontSize = 60;
context.font = fontSize + "px " + fontface;
var width = context.measureText(text).width;
// add text
var text = 'abcdef';
canvas.width = width;
canvas.height = fontSize*1.3;
context.textAlign = "center";
context.font = fontSize + "px " + fontface;
context.fillStyle = "white";
context.fillText(text, canvas.width / 2, canvas.height / 2);
}
function createLabels() {
for(var i = 0; i < 10000 ; i++) {
createTextMesh();
}
scene.add( labels );
}
function createTextMesh() {
// canvas contents will be used for a texture
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
var uniforms = {
text: {
type: 't',
value: texture
}
};
var material = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: document.getElementById( 'vertex-shader' ).textContent,
fragmentShader: document.getElementById( 'fragment-shader' ).textContent
} );
var geometry = new THREE.PlaneBufferGeometry(15, 15);
var label = new THREE.Mesh( geometry, material );
labels.add(label);
}
function clearLabels() {
for(var i = 0; i < labels.children.length; i++) {
var label = labels.children[i];
if(label.material.uniforms) {
label.material.uniforms.text.value.dispose();
}
label.material.dispose();
label.geometry.dispose();
labels.remove(label);
}
scene.remove( labels );
}
// Add time gap render will call with 24 fps. or you can slow down speed to check.
function animate() {
var curTime = new Date();
if(lastTime === undefined || (Math.round(curTime - lastTime)/1000) >= fps)
{
render();
lastTime = curTime;
}
requestAnimationFrame( animate );
}
function render() {
// build GL objects
createLabels();
renderer.render( scene, camera );
// clean up
clearLabels();
}
</script>
<div>
<canvas width="1920" height="974" style="width: 1920px; height: 974px;"></canvas>
</div>
</body>
</html>
Don't create a new mesh 1000 times every tick, pool them.
Don't create a 1000 geometries that are all the same plane. This is probably the biggest culprit here. Create just one, ever, and pass it to meshes.
Textures, im not so sure about that one. I think you're not supposed to create a new texture from the canvas context, create once and update canvas.
This will go away with the changes, but it's good to note that for performance you'd want to avoid creating that uniforms object in the loop as well.
EDIT
You do create a lot of stuff. Width of the label comes in as 263, and if three's console log is to be trusted, it's resized to 256x64. So you end up with 480mb of data, although, with the alpha channel it could be 600mb. I assume that your demo never even gets to the disposal part. It just crashed the browser on my end.
Three also complains about the textures being NPOT, so it attempts to write out ten thousand console logs.
Related
When looking for a plugin, I ended up across this website
I saw that there is a nice cloud animation.
So I started a search on google to find the source of the code and I found it here ... Preview
/JS
<script type="text/javascript" src="js/ThreeWebGL.js"></script>
<script type="text/javascript" src="js/ThreeExtras.js"></script>
<script type="text/javascript" src="js/Detector.js"></script>
<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>
/Html
<script id="vs" type="x-shader/x-vertex">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<script id="fs" type="x-shader/x-fragment">
uniform sampler2D map;
uniform vec3 fogColor;
uniform float fogNear;
uniform float fogFar;
varying vec2 vUv;
void main() {
float depth = gl_FragCoord.z / gl_FragCoord.w;
float fogFactor = smoothstep( fogNear, fogFar, depth );
gl_FragColor = texture2D( map, vUv );
gl_FragColor.w *= pow( gl_FragCoord.z, 20.0 );
gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );
}
</script>
<script type="text/javascript">
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
// Bg gradient
var canvas = document.createElement( 'canvas' );
canvas.width = 32;
canvas.height = window.innerHeight;
var context = canvas.getContext( '2d' );
var gradient = context.createLinearGradient( 0, 0, 0, canvas.height );
gradient.addColorStop(0, "#1e4877");
gradient.addColorStop(0.5, "#4584b4");
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
document.body.style.background = 'url(' + canvas.toDataURL('image/png') + ')';
// Clouds
var container;
var camera, scene, renderer, sky, mesh, geometry, material,
i, h, color, colors = [], sprite, size, x, y, z;
var mouseX = 0, mouseY = 0;
var start_time = new Date().getTime();
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.Camera( 30, window.innerWidth / window.innerHeight, 1, 3000 );
camera.position.z = 6000;
scene = new THREE.Scene();
geometry = new THREE.Geometry();
var texture = THREE.ImageUtils.loadTexture( 'cloud10.png' );
texture.magFilter = THREE.LinearMipMapLinearFilter;
texture.minFilter = THREE.LinearMipMapLinearFilter;
var fog = new THREE.Fog( 0x4584b4, - 100, 3000 );
material = new THREE.MeshShaderMaterial( {
uniforms: {
"map": { type: "t", value:2, texture: texture },
"fogColor" : { type: "c", value: fog.color },
"fogNear" : { type: "f", value: fog.near },
"fogFar" : { type: "f", value: fog.far },
},
vertexShader: document.getElementById( 'vs' ).textContent,
fragmentShader: document.getElementById( 'fs' ).textContent,
depthTest: false
} );
var plane = new THREE.Mesh( new THREE.Plane( 64, 64 ) );
for ( i = 0; i < 8000; i++ ) {
plane.position.x = Math.random() * 1000 - 500;
plane.position.y = - Math.random() * Math.random() * 200 - 15;
plane.position.z = i;
plane.rotation.z = Math.random() * Math.PI;
plane.scale.x = plane.scale.y = Math.random() * Math.random() * 1.5 + 0.5;
GeometryUtils.merge( geometry, plane );
}
mesh = new THREE.Mesh( geometry, material );
scene.addObject( mesh );
mesh = new THREE.Mesh( geometry, material );
mesh.position.z = - 8000;
scene.addObject( mesh );
renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
window.addEventListener( 'resize', onWindowResize, false );
}
function onDocumentMouseMove( event ) {
mouseX = ( event.clientX - windowHalfX ) * 0.25;
mouseY = ( event.clientY - windowHalfY ) * 0.15;
}
function onWindowResize( event ) {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
position = ( ( new Date().getTime() - start_time ) * 0.03 ) % 8000;
camera.position.x += ( mouseX - camera.target.position.x ) * 0.01;
camera.position.y += ( - mouseY - camera.target.position.y ) * 0.01;
camera.position.z = - position + 8000;
camera.target.position.x = camera.position.x;
camera.target.position.y = camera.position.y;
camera.target.position.z = camera.position.z - 1000;
renderer.render( scene, camera );
}
</script>
My question now :
I would like to set it up on my localhost site to test it on elementor.
I will call the script with an html widget.
The problem I know there is an wp_enqueue_script option in functions.php and the script goes there ..
but I can't understand the exact procedure. I failed for hours to set up the scripts ...
Can you show me how to integrate it ? I need a good example how use these scripts. to understand once and for all how to integrate scripts in wordpress child themes.
My setup :
A clean install of wordpress with an empty hello theme and it's child installed.
Update
let's develop the subject a bit
I did these manipulations in
functions.php
function my_scripts_method() {
wp_enqueue_script('custom-script',get_stylesheet_directory_uri() . '/js/ThreeWebGL.js',array( 'jquery' ));
wp_enqueue_script('custom-script',get_stylesheet_directory_uri() . '/js/ThreeExtras.js',array( 'jquery' ));
wp_enqueue_script('custom-script',get_stylesheet_directory_uri() . '/js/Detector.js',array( 'jquery' ));
wp_enqueue_script('custom-script',get_stylesheet_directory_uri() . '/js/RequestAnimationFrame.js',array( 'jquery' ));
}
add_action( 'wp_enqueue_scripts', 'my_scripts_method' );
It seems to work.. the scripts are loaded I hope.
I just have a message in the chrome console :
Uncaught ReferenceError: Detector is not defined at (index): 117
I guess because i haven't put html yet?
what do you think of a snippet?
I use it to create and add_shortcode
something like that.. do you think it's safe?
add_shortcode( 'amazing clouds', function () {
<script id="vs" type="x-shader/x-vertex">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<script id="fs" type="x-shader/x-fragment">
uniform sampler2D map;
uniform vec3 fogColor;
uniform float fogNear;
uniform float fogFar;
varying vec2 vUv;
void main() {
float depth = gl_FragCoord.z / gl_FragCoord.w;
float fogFactor = smoothstep( fogNear, fogFar, depth );
gl_FragColor = texture2D( map, vUv );
gl_FragColor.w *= pow( gl_FragCoord.z, 20.0 );
gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );
}
</script>
<script type="text/javascript">
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
// Bg gradient
var canvas = document.createElement( 'canvas' );
canvas.width = 32;
canvas.height = window.innerHeight;
var context = canvas.getContext( '2d' );
var gradient = context.createLinearGradient( 0, 0, 0, canvas.height );
gradient.addColorStop(0, "#1e4877");
gradient.addColorStop(0.5, "#4584b4");
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
document.body.style.background = 'url(' + canvas.toDataURL('image/png') + ')';
// Clouds
var container;
var camera, scene, renderer, sky, mesh, geometry, material,
i, h, color, colors = [], sprite, size, x, y, z;
var mouseX = 0, mouseY = 0;
var start_time = new Date().getTime();
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.Camera( 30, window.innerWidth / window.innerHeight, 1, 3000 );
camera.position.z = 6000;
scene = new THREE.Scene();
geometry = new THREE.Geometry();
var texture = THREE.ImageUtils.loadTexture( 'cloud10.png' );
texture.magFilter = THREE.LinearMipMapLinearFilter;
texture.minFilter = THREE.LinearMipMapLinearFilter;
var fog = new THREE.Fog( 0x4584b4, - 100, 3000 );
material = new THREE.MeshShaderMaterial( {
uniforms: {
"map": { type: "t", value:2, texture: texture },
"fogColor" : { type: "c", value: fog.color },
"fogNear" : { type: "f", value: fog.near },
"fogFar" : { type: "f", value: fog.far },
},
vertexShader: document.getElementById( 'vs' ).textContent,
fragmentShader: document.getElementById( 'fs' ).textContent,
depthTest: false
} );
var plane = new THREE.Mesh( new THREE.Plane( 64, 64 ) );
for ( i = 0; i < 8000; i++ ) {
plane.position.x = Math.random() * 1000 - 500;
plane.position.y = - Math.random() * Math.random() * 200 - 15;
plane.position.z = i;
plane.rotation.z = Math.random() * Math.PI;
plane.scale.x = plane.scale.y = Math.random() * Math.random() * 1.5 + 0.5;
GeometryUtils.merge( geometry, plane );
}
mesh = new THREE.Mesh( geometry, material );
scene.addObject( mesh );
mesh = new THREE.Mesh( geometry, material );
mesh.position.z = - 8000;
scene.addObject( mesh );
renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
window.addEventListener( 'resize', onWindowResize, false );
}
function onDocumentMouseMove( event ) {
mouseX = ( event.clientX - windowHalfX ) * 0.25;
mouseY = ( event.clientY - windowHalfY ) * 0.15;
}
function onWindowResize( event ) {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
position = ( ( new Date().getTime() - start_time ) * 0.03 ) % 8000;
camera.position.x += ( mouseX - camera.target.position.x ) * 0.01;
camera.position.y += ( - mouseY - camera.target.position.y ) * 0.01;
camera.position.z = - position + 8000;
camera.target.position.x = camera.position.x;
camera.target.position.y = camera.position.y;
camera.target.position.z = camera.position.z - 1000;
renderer.render( scene, camera );
}
</script>
} );
Things got very complicated very quickly.
I hope someone will come and show us how to integrate it into a wordpress page
(with elementor is bonus)
The HTML widget will strip out php tags for security reasons. But you have several options which will allow you to achieve your goal. Here are three:
Edit your child theme's functions.php file to allow php in the
widget. (Bad idea)
Write your own custom widget which enqueues the script you need.
(Better idea)
Don't use a widget at all. Just add the script to the pages you want it using the Advanced Custom Fields plugin. (Best idea IMHO)
And since you asked about loading JS, here's a good resource for you.
And here's another on the topic of wp_enqueue_scripts().
Edit: step by step instructions for ACF plugin:
Install Advanced Custom Fields plugin
Go to the Custom Fields settings and click Add New
Name the field group something like “Javascript Settings”
Create rules to restrict where the fields will appear and who will see them
Next to Style, choose Standard (WP metabox)
Click + Add Field
Name it “Header Script”
Change Field Type to “Text Area”
Change Formatting to “Convert HTML to tags”
Repeat from step 6, but this time call it “Footer Script”
Publish the Field Group
In header.php, right before the closing </head> tag, add: <?php the_field('header_script'); ?>
In footer.php, right before the closing </body> tag, add: <?php the_field(‘footer_script'); ?>
Place your javascript files in a folder on your server (preferably in a child theme).
Link your javascript in the new fields on your page using regular html <script> tags
Note: copy your header.php and footer.php files into your child theme and make the edits (steps 12 & 13) there to avoid losing these changes if your theme is updated.
I'm rendering a picking scene that contains sprites. As my cursor gets close to the sprite, it registers as a color and gets "picked". This invisible border gets larger closer you zoom into the sprites.
Open up your console to see the IDs printed in real time. Move your cursor closer and further away to large and small sprites. You'll see that sprites get selected on an invisible border. This behavior does not happen with regular geometry, just with sprites.
It's weird because I'm rendering out what renderer.readRenderTargetPixels actually sees.
How can I get rid of the invisible borders for more accurate picking?
var renderer, scene, camera, controls;
var particles, uniforms;
var PARTICLE_SIZE = 50;
var raycaster, intersects;
var mouse, INTERSECTED;
var pickingTexture;
var numOfVertices;
init();
animate();
function init() {
container = document.getElementById('container');
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 150;
//
var geometry1 = new THREE.BoxGeometry(200, 200, 200, 4, 4, 4);
var vertices = geometry1.vertices;
numOfVertices = vertices.length;
var positions = new Float32Array(vertices.length * 3);
var colors = new Float32Array(vertices.length * 3);
var sizes = new Float32Array(vertices.length);
var vertex;
var color = new THREE.Color();
for (var i = 0, l = vertices.length; i < l; i++) {
vertex = vertices[i];
vertex.toArray(positions, i * 3);
color.setHex(i + 1);
color.toArray(colors, i * 3);
sizes[i] = PARTICLE_SIZE * 0.5;
}
var geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.addAttribute('customColor', new THREE.BufferAttribute(colors, 3));
geometry.addAttribute('size', new THREE.BufferAttribute(sizes, 1));
//
var material = new THREE.ShaderMaterial({
uniforms: {
// texture: {type: "t", value: THREE.ImageUtils.loadTexture("../textures/circle.png")}
texture: {type: "t", value: THREE.ImageUtils.loadTexture("../textures/disc.png")}
},
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
depthTest: false,
transparent: false
// alphaTest: 0.9
});
//
particles = new THREE.Points(geometry, material);
scene.add(particles);
//
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff);
container.appendChild(renderer.domElement);
//
raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2();
//
//
window.addEventListener('resize', onWindowResize, false);
document.addEventListener('mousemove', onDocumentMouseMove, false);
// defaults are on the right (except minFilter)
var options = {
format: THREE.RGBAFormat, // THREE.RGBAFormat
type: THREE.UnsignedByteType, // THREE.UnsignedByteType
anisotropy: 1, // 1
magFilter: THREE.LinearFilter, // THREE.LinearFilter
minFilter: THREE.LinearFilter, // THREE.LinearFilter
depthBuffer: true, // true
stencilBuffer: true // true
};
pickingTexture = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, options);
pickingTexture.texture.generateMipmaps = false;
controls = new THREE.OrbitControls(camera, container);
controls.damping = 0.2;
controls.enableDamping = false;
}
function onDocumentMouseMove(e) {
// event.preventDefault();
mouse.x = e.clientX;
mouse.y = e.clientY;
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
render();
}
function render() {
pick();
renderer.render(scene, camera);
}
function pick() {
renderer.render(scene, camera, pickingTexture);
//create buffer for reading single pixel
var pixelBuffer = new Uint8Array(4);
//read the pixel under the mouse from the texture
renderer.readRenderTargetPixels(pickingTexture, mouse.x, pickingTexture.height - mouse.y, 1, 1, pixelBuffer);
//interpret the pixel as an ID
var id = ( pixelBuffer[0] << 16 ) | ( pixelBuffer[1] << 8 ) | ( pixelBuffer[2] );
if (id <= numOfVertices) console.log(id);
}
body {
color: #ffffff;
background-color: #000000;
margin: 0px;
overflow: hidden;
}
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform sampler2D texture;
varying vec3 vColor;
void main() {
// solid squares of color
gl_FragColor = vec4( vColor, 1.0 );
}
</script>
<script type="x-shader/x-vertex" id="vertexshader">
attribute float size;
attribute vec3 customColor;
varying vec3 vColor;
void main() {
vColor = customColor;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size * ( 300.0 / length( mvPosition.xyz ) );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<div id="container"></div>
The problem is you're on a device that has a devicePixelRatio != 1.0 and three.js lying about the size.
Because you called renderer.setPixelRatio now magic happens behind the scenes. Your canvas is not the size you requested it's some other size based on some formula hidden in the three.js code.
So, what happens. Your canvas is one size but your render target is a different size. Your shader uses gl_PointSize to draw its points. That size is in device pixels. Because your render target is a different size the size of the points are different in your render target than they are on screen.
Remove the call to render.setPixelRatio and it will start working.
IMO the correct way to fix this is to use devicePixelRatio yourself because that way everything that is happening is 100% visible to you. No magic happening behind the scenes.
So,
Get rid of the container and use a canvas directly
<canvas id="c"></canvas>
set the canvas to use 100vw for width, 100vh for height and made the body margin: 0;
canvas { width: 100vw; height: 100vh; display: block; }
body { margin: 0; }
This will make your canvas stretch automatically to fill the window.
Use the size the browser stretched the canvas to choose the size its drawingBuffer should be and multiply by devicePixelRatio. That assumes you actually want to support device pixel ratio. No need to do this twice so following D.R.Y. so just do it in onWindowResize.
canvas = document.getElementById("c");
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
canvas: canvas,
});
pickingTexture = new THREE.WebGLRenderTarget(1, 1, options);
onWindowResize();
...
function onWindowResize() {
var width = canvas.clientWidth * window.devicePixelRatio;
var height = canvas.clientHeight * window.devicePixelRatio;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height, false); // YOU MUST PASS FALSE HERE otherwise three.js will muck with the CSS
pickingTexture.setSize(width, height);
}
Convert the mouse coordinates into device coordinates
renderer.readRenderTargetPixels(
pickingTexture,
mouse.x * window.devicePixelRatio,
pickingTexture.height - mouse.y * window.devicePixelRatio,
1, 1, pixelBuffer);
Here's that solution
var renderer, scene, camera, controls;
var particles, uniforms;
var PARTICLE_SIZE = 50;
var raycaster, intersects;
var mouse, INTERSECTED;
var pickingTexture;
var numOfVertices;
var info = document.querySelector('#info');
init();
animate();
function init() {
canvas = document.getElementById('c');
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, 1, 1, 10000);
camera.position.z = 150;
//
var geometry1 = new THREE.BoxGeometry(200, 200, 200, 4, 4, 4);
var vertices = geometry1.vertices;
numOfVertices = vertices.length;
var positions = new Float32Array(vertices.length * 3);
var colors = new Float32Array(vertices.length * 3);
var sizes = new Float32Array(vertices.length);
var vertex;
var color = new THREE.Color();
for (var i = 0, l = vertices.length; i < l; i++) {
vertex = vertices[i];
vertex.toArray(positions, i * 3);
color.setHex(i + 1);
color.toArray(colors, i * 3);
sizes[i] = PARTICLE_SIZE * 0.5;
}
var geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.setAttribute('customColor', new THREE.BufferAttribute(colors, 3));
geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));
//
var loader = new THREE.TextureLoader();
var material = new THREE.ShaderMaterial({
uniforms: {
// texture: {type: "t", value: THREE.ImageUtils.loadTexture("../textures/circle.png")}
texture: {value: loader.load("https://i.imgur.com/iXT97XR.png")}
},
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
depthTest: false,
transparent: false
// alphaTest: 0.9
});
//
particles = new THREE.Points(geometry, material);
scene.add(particles);
//
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
canvas: canvas,
});
renderer.setClearColor(0xffffff);
//
raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2();
//
//
window.addEventListener('resize', onWindowResize, false);
document.addEventListener('mousemove', onDocumentMouseMove, false);
// defaults are on the right (except minFilter)
var options = {
format: THREE.RGBAFormat, // THREE.RGBAFormat
type: THREE.UnsignedByteType, // THREE.UnsignedByteType
anisotropy: 1, // 1
magFilter: THREE.LinearFilter, // THREE.LinearFilter
minFilter: THREE.LinearFilter, // THREE.LinearFilter
depthBuffer: true, // true
stencilBuffer: true // true
};
pickingTexture = new THREE.WebGLRenderTarget(1, 1, options);
pickingTexture.texture.generateMipmaps = false;
controls = new THREE.OrbitControls(camera, canvas);
controls.damping = 0.2;
controls.enableDamping = false;
onWindowResize();
}
function onDocumentMouseMove(e) {
// event.preventDefault();
mouse.x = e.clientX;
mouse.y = e.clientY;
}
function onWindowResize() {
var width = canvas.clientWidth * window.devicePixelRatio;
var height = canvas.clientHeight * window.devicePixelRatio;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height, false); // YOU MUST PASS FALSE HERE!
pickingTexture.setSize(width, height);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
render();
}
function render() {
pick();
renderer.render(scene, camera);
}
function pick() {
renderer.setRenderTarget(pickingTexture);
renderer.setClearColor(0);
renderer.render(scene, camera);
renderer.setClearColor(0xFFFFFF);
renderer.setRenderTarget(null)
//create buffer for reading single pixel
var pixelBuffer = new Uint8Array(4);
//read the pixel under the mouse from the texture
renderer.readRenderTargetPixels(pickingTexture, mouse.x * window.devicePixelRatio, pickingTexture.height - mouse.y * window.devicePixelRatio, 1, 1, pixelBuffer);
//interpret the pixel as an ID
var id = ( pixelBuffer[0] << 16 ) | ( pixelBuffer[1] << 8 ) | ( pixelBuffer[2] );
//if (id > 0) console.log(id);
info.textContent = id;
}
body {
color: #ffffff;
background-color: #000000;
margin: 0;
}
canvas { width: 100vw; height: 100vh; display: block; }
#info { position: absolute; left: 0; top: 0; color: red; background: black; padding: 0.5em; font-family: monospace; }
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform sampler2D texture;
varying vec3 vColor;
void main() {
// solid squares of color
gl_FragColor = vec4( vColor, 1.0 );
}
</script>
<script type="x-shader/x-vertex" id="vertexshader">
attribute float size;
attribute vec3 customColor;
varying vec3 vColor;
void main() {
vColor = customColor;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size * ( 300.0 / length( mvPosition.xyz ) );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<canvas id="c"></canvas>
<div id="info"></div>
Note a few other things.
I'd guess you really want to clear the picking texture to zero instead of white. That way 0 = nothing there, anything else = something there.
renderer.setClearColor(0);
renderer.render(scene, camera, pickingTexture);
renderer.setClearColor(0xFFFFFF);
No idea what the id <= numOfVertices means
So given that it's clearing to zero now the code is just
if (id) console.log(id);
I don't set the renderer size, the pickingTexture size nor the camera aspect at init time.
Why repeat myself. onWindowResize already sets it
You need to resize the pickingTexture render target when the canvas is resizes so it matches in size.
I removed most references to window.innerWidth and window.innerHeight
I would have removed all of them but I didn't want to change even more code for this example. Using window.innerWidth ties the code to the window. If you ever want to use the code in something that's not the fullsize of the window, for example lets say you make an editor. You'll have to change the code.
It's not any harder to write the code in a way that works in more situations so why make more work for yourself later.
Other solutions I didn't chose
You could call render.setPixelRatio and then set the pickingTexture render target's size with window.devicePixelRatio
I didn't pick this solution because you have to guess what three.js is doing behind the scenes. Your guess might be correct today but wrong tomorrow. It seems better if you tell three.js make something width by height it should just make it width by height and not make it something else. Similarly you'd have to guess when three.js is going to apply pixelRatio and when it's not. As you noticed above it doesn't apply it to the size of the render target and it can't because it doesn't know what your purpose is. Are you making a render target for picking? For a fullscreen effect? For capture? for a non-fullscreen effect? Since it can't know it can't apply the pixelRatio for you. This happens all over the three.js code. Some places it applies pixelRatio, other places it doesn't. You're left guessing. If you never set pixelRatio that problem disappears.
You could pass in devicePixelRatio into your shader
<script type="x-shader/x-vertex" id="vertexshader">
attribute float size;
attribute vec3 customColor;
varying vec3 vColor;
uniform float devicePixelRatio; // added
void main() {
vColor = customColor;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size * ( 300.0 / length( mvPosition.xyz ) ) * devicePixelRatio;
gl_Position = projectionMatrix * mvPosition;
}
</script>
and of course you'd need to set devicePixelRatio in your uniforms.
I might pick this solution. The minor problem is if the pickingTexture is not the same resolution as the canvas's backbuffer you can get off by 1 errors. In this case if the canvas was 2x the pickingTexture then 3 of every 4 pixels in the canvas don't exist in the pickingTexture. Depending on your application that might be ok though. You can't pick 1/2 pixels, at least not with the mouse.
Another other reason I would probably not pick this solution is it just leaves the issue to pop up other places. lineWidth is one, gl_FragCoord is another. So are the viewport and scissor settings. It seems better to make the render target size match that canvas so that everything is the same rather than make more and more workarounds and have to remember where to use one size vs another. Tomorrow I start using the PointsMaterial. It also has issues with devicePixelRatio. By not calling renderer.setPixelRatio those problems go away.
I am currently loading textures from URLs but since my back-end code is generating planets I need them to be displayed using Base64.
(I'm playing around with procedural generation so I'd prefer not to save the image and then load it via URL)
Here's the code;
<!DOCTYPE html><html class=''>
<head>
<style>body {
background: black;
text-align: center;
}
</style></head><body>
<script id="vertexShader" type="x-shader/x-vertex">
uniform vec3 viewVector;
uniform float c;
uniform float p;
varying float intensity;
void main({
vec3 vNormal = normalize( normalMatrix * normal );
vec3 vNormel = normalize( normalMatrix * viewVector );
intensity = pow( c - dot(vNormal, vNormel), p );
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec3 glowColor;
varying float intensity;
void main() {
vec3 glow = glowColor * intensity;
gl_FragColor = vec4( glow, 1.0 );
}
</script>
<script src='http://cdnjs.cloudflare.com/ajax/libs/three.js/r63/three.min.js'></script><script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/orbitcontrols.js'></script>
<script>var container, controls, camera, renderer, scene, light,
rotationSpeed = 0.02,
clock = new THREE.Clock(),
WIDTH = window.innerWidth - 30,
HEIGHT = window.innerHeight - 30;
//cam vars
var angle = 45,
aspect = WIDTH / HEIGHT,
near = 0.1,
far = 10000;
//mesh vars
var earthMesh, Atmos, AtmosMat;
container = document.createElement('div');
document.body.appendChild(container);
//cam
camera = new THREE.PerspectiveCamera(angle, aspect, near, far);
camera.position.set(1380, -17, 394);
//scene
scene = new THREE.Scene();
camera.lookAt(scene.position);
//light
light = new THREE.SpotLight(0xFFFFFF, 1, 0, Math.PI / 2, 1);
light.position.set(4000, 4000, 1500);
light.target.position.set (1000, 3800, 1000);
light.castShadow = true;
//light.shadowCameraNear = 1;
//light.shadowCameraFar = 10000;
//light.shadowCameraFov = 50;
scene.add(light);
//EARTH
var earthGeo = new THREE.SphereGeometry (200, 400, 400),
earthMat = new THREE.MeshPhongMaterial();
earthMesh = new THREE.Mesh(earthGeo, earthMat);
earthMesh.position.set(-100, 0, 0);
earthMesh.rotation.y=5;
scene.add(earthMesh);
//diffuse
earthMat.map = THREE.ImageUtils.loadTexture('https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/earthmap.jpg');
//bump
earthMat.bumpMap = THREE.ImageUtils.loadTexture('https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/bump-map.jpg');
earthMat.bumpScale = 8;
//specular
earthMat.specularMap = THREE.ImageUtils.loadTexture('https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/earthspec1k.jpg');
earthMat.specular = new THREE.Color('#2e2e2e');
earthMesh.castShadow = true;
earthMesh.receiveShadow = true;
//Atmosphere
AtmosMat = new THREE.ShaderMaterial({
uniforms:{
"c": { type: "f", value: 0.3 },
"p": { type: "f", value: 5.2},
glowColor: { type: "c", value: new THREE.Color(0x00dbdb)},
viewVector: { type: "v3", value: camera.position}
},
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent,
side: THREE.BackSide,
blending: THREE.AdditiveBlending,
transparent: true
});
Atmos = new THREE.Mesh(earthGeo, AtmosMat);
Atmos.position = earthMesh.position;
Atmos.scale.multiplyScalar(1.2);
scene.add(Atmos);
//STARS
var starGeo = new THREE.SphereGeometry (3000, 10, 100),
starMat = new THREE.MeshBasicMaterial();
starMat.map = THREE.ImageUtils.loadTexture('https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/star-field.png');
starMat.side = THREE.BackSide;
var starMesh = new THREE.Mesh(starGeo, starMat);
scene.add(starMesh);
//renderer
renderer = new THREE.WebGLRenderer({antialiasing : true});
renderer.setSize(WIDTH, HEIGHT);
container.appendChild(renderer.domElement);
//controls
controls = new THREE.OrbitControls( camera, renderer.domElement);
controls.addEventListener( 'change', render );
function animate(){
requestAnimationFrame(animate);
controls.update();
render();
}
function render(){
var delta = clock.getDelta();
earthMesh.rotation.y += rotationSpeed * delta;
renderer.clear();
renderer.render(scene, camera);
}
animate();
//# sourceURL=pen.js
</script>
</body></html>
I have tried;
image = document.createElement( 'img' );
document.body.appendChild( image );
earthMat.map = new THREE.Texture( image );
image.addEventListener( 'load', function ( event ) { texture.needsUpdate = true; } );
image.src = 'data:image/png;base64,<?php echo $image_data_base64 ?>';
But it doesn't seem to be working correctly.
Any help would be greatly appreciated, thanks.
Turns out I had to do;
earthMat.map = THREE.ImageUtils.loadTexture( image.src );
Instead of;
earthMat.map = new THREE.Texture( image );
new event listener;
image.addEventListener( 'load', function ( event ) {
earthMat.map = THREE.ImageUtils.loadTexture( image.src );
earthMat.needsUpdate = true;
});
Perhaps this does not meet the needs of the original question with the base64 string coming from a PHP script, but in our case the solution was much simpler (THREE.js r130):
const manager = new THREE.LoadingManager()
const texture = new THREE.TextureLoader(manager).load('data:image/png;base64,...')
I'm working with three.js and trying to write a shader to render many spheres with all of the same attributes except their radii. The radii are varying in real time and I'm not sure what the most efficient way to change the radii of the individual spheres.
Here is what I have so far to test. It seems that my uniform variable radius doesn't actually affect the radius of the sphere at all.
<!DOCTYPE html>
<html>
<title>Test Sphere</title>
<head>
</head>
<body>
<div id="test"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>
<script type="x-shader/x-vertex" id="vertexShader">
/**
* Multiply each vertex by the
* model-view matrix and the
* projection matrix (both provided
* by Three.js) to get a final
* vertex position
*/
uniform float radius;
void main() {
gl_Position = radius * projectionMatrix *
modelViewMatrix *
vec4(position,1.0);
}
</script>
<script type="x-shader/x-vertex" id="fragmentShader">
/**
* Set the colour to a lovely pink.
* Note that the color is a 4D Float
* Vector, R,G,B and A and each part
* runs from 0.0 to 1.0
*/
void main() {
gl_FragColor = vec4(1.0, // R
0.0, // G
1.0, // B
1.0); // A
}
</script>
<script>
var light;
var material;
var scene, camera;
var puthere = document.getElementById("test");
container = document.createElement( 'div' );
puthere.appendChild( container );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 300;
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight )
container.appendChild( renderer.domElement );
var uniforms = {
radius: { type: "f", value: 10.0 }
};
material = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );
var geometry = new THREE.SphereGeometry( 1, 32, 32 );
sphere = new THREE.Mesh( geometry, material );
// material.needsUpdate = true;
scene.add( sphere );
scene.add( camera );
renderer.render( scene, camera );
setInterval( function() {
console.log( "here" );
sphere.material.uniforms.radius.value += 10;
renderer.render( scene, camera );
}, 100);
</script>
</body>
</html>
I wrote a program with Three.js. I try to use shaders but, unfortunately, the app does not work. I tried to customized a application from threejs.org. This is the code:
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="ecma/three.js"></script>
<script type="text/javascript" src="ecma/jquery-1.9.0.js"></script>
<script type="text/javascript" src="ecma/OrbitControls.js"></script>
<style>
body{ margin: 0; overflow: hidden; }
</style>
</head>
<body>
<div id="WebGL-output">
</div>
<script id="vertexShader" type="x-shader/x-vertex">
varying vec2 vUv;
void main()
{
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script id="fragment_shader1" type="x-shader/x-fragment">
uniform vec2 resolution;
uniform float time;
varying vec2 vUv;
void main(void)
{
vec2 p = -1.0 + 2.0 * vUv;
float a = time*100.0;
float d,e,f,g=1.0/40.0,h,i,r,q;
e=400.0*(p.x*0.5+0.5);
f=400.0*(p.y*0.5+0.5);
i=200.0+sin(e*g+a/150.0)*20.0;
d=200.0+cos(f*g/2.0)*18.0+cos(e*g)*7.0;
r=sqrt(pow(i-e,2.0)+pow(d-f,2.0));
q=f/r;
e=(r*cos(q))-a/2.0;f=(r*sin(q))-cos(a/2.0);
d=sin(e*g)*176.0+sin(e*g)*164.0+r;
h=((f+d)+a/2.0)*g;
i=cos(h+r*p.x/1.3)*(e+e+a)+cos(q*g*6.0)*(r+h/3.0);
h=sin(f*g)*144.0-sin(e*g)*212.0*p.x;
h=(h+(f-e)*q+sin(r-(a+h)/7.0)*10.0+i/4.0)*g;
i+=cos(h*2.3*sin(a/350.0-q))*184.0*sin(q-(r*4.3+a/12.0)*g)+tan(r*g+h)*184.0*cos(r*g+h);
i=mod(i/5.6,256.0)/64.0;
if(i<0.0) i+=4.0;
if(i>=2.0) i=4.0-i;
d=r/350.0;
d+=sin(d*d*8.0)*0.52;
f=(sin(a*g)+1.0)/2.0;
gl_FragColor=vec4(vec3(f*i/1.6,i/2.0+d/13.0,i)*d*p.x+vec3(i/1.3+d/8.0,i/2.0+d/18.0,i)*d*(1.0-p.x),0.0);
}
</script>
<script type="text/javascript">
$(function () {
var W = window.innerWidth, H = window.innerHeight;
var plane, planeGeom, planeMat;
var sphere, sphereGeom, shadedMat;
var scene, camera, renderer;
var clock;
var orbitControls;
var uniforms1;
init();
makeLights();
makeFloor();
makeSphere();
render();
function init(){
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, W / H, 0.1, 1000);
camera.position.set(-40, 30, 0);
camera.lookAt(new THREE.Vector3(0,0,0));
renderer = new THREE.WebGLRenderer();
renderer.setClearColorHex(0xEEEEEE);
renderer.setSize(W, H);
renderer.shadowMapEnabled = true;
orbitControls = new THREE.OrbitControls(camera);
orbitControls.autoRotate = false;
clock = new THREE.Clock();
}
function makeLights(){
makeAmbientLight();
makeSpotLight();
}
function makeAmbientLight(){
ambiColor = 0x141414;
ambientLight = new THREE.AmbientLight(ambiColor);
scene.add(ambientLight);
}
function makeSpotLight(){
var spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( -40, 60, -10 );
spotLight.castShadow = true;
scene.add( spotLight );
}
function makeFloor(){
planeGeom = new THREE.PlaneGeometry(100,100);
planeMat = new THREE.MeshLambertMaterial();
var planeTex = THREE.ImageUtils.loadTexture("picim/checkerboard.jpg");
planeTex.wrapS = planeTex.wrapT = THREE.RepeatWrapping;
planeTex.repeat.set(50, 50);
planeMat.map = planeTex;
planeMat.side = THREE.DoubleSide;
plane = new THREE.Mesh(planeGeom, planeMat);
plane.rotation.x=-0.5*Math.PI;
plane.position.set(15, 0, 0);
plane.receiveShadow = true;
scene.add(plane);
}
function makeSphere(){
sphereGeom = new THREE.SphereGeometry(5,20,20);
uniforms1 = {
time: { type: "f", value: 1.0 },
resolution: { type: "v2", value: new THREE.Vector2() }
};
shadedMat = new THREE.ShaderMaterial({uniforms: uniforms1,
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragment_shader1').textContent,
});
sphere = new THREE.Mesh(sphereGeom, shadedMat);
sphere.position.set(0, 10, 0);
sphere.castShadow = true;
scene.add(sphere);
}
function render(){
var delta = clock.getDelta();
orbitControls.update(delta);
sphere.rotation.y += 0.02;
requestAnimationFrame(render);
renderer.render(scene, camera);
}
$("#WebGL-output").append(renderer.domElement);
});
</script>
</body>
</html>
The app must display the floor and a sphere, on which the shaders are used. But the app shows a bright white sphere. Could you help me to find the error ?
Thanks,
Ee
If you are seeing a white sphere with these crazy shader, then it means that the shader works no?
If you are asking why is that... shader (and it's quite a shader) rendering white, instead of all that math, it's doubtful that anyone can help you with the presented code.
you can add something like gl_FragColor.xyz=cos(gl_FragColor.xyz)*.5+.5; and you'll see if that white actually has a bigger meaning.