Three.js same shader with multiple objects different parameters - javascript

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>

Related

How to apply HemisphereLight to ShaderMaterial?

I want to add HemisphereLight to light an object which is built with ShaderMaterial. But when I simply add the light to the screen, the object doesn't seem to be affected. In fact, I've tried with all the other lights and no one light is affecting the object. What do I have to set to make the object affected by the lights?
<script src="https://threejs.org/build/three.js"></script>
<script type="module">
var clock = new THREE.Clock()
function main() {
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 200, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var vShader = `
precision mediump float;
uniform float uTime;
void main() {
float z = 0.1*cos(uTime) * cos(position.y*40. - uTime) * position.y*sin(log(position.y))*0.5 + 0.5;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position.x, position.y, z, 1.0);
}
`
var fShader = `
precision mediump float;
uniform vec2 uRes;
void main() {
vec2 uv = 1.5*gl_FragCoord.xy/uRes;
gl_FragColor = vec4(uv.x, uv.y, 0.0, 1.0);
}
// `
var planeG = new THREE.PlaneGeometry(25, 60, 20, 20);
var planeM = new THREE.ShaderMaterial({
uniforms: {
//ambientLightColor: 0xffffff,
uTime: {
type:"f",
value:0.0,
},
uRes: {
type:"f",
value:new THREE.Vector2(window.innerWidth, window.innerHeight),
}
},
// wireframe:true,
//lights:true,
vertexShader:vShader,
fragmentShader:fShader,
side:THREE.DoubleSide,
});
var plane = new THREE.Mesh( planeG, planeM );
var light = new THREE.HemisphereLight(0xffffff, 0x000000, 2);
//var light = new THREE.AmbientLight(0xFFFFFF, 1.0)
scene.add(light);
scene.add(plane);
plane.rotateZ(Math.PI/2)
camera.position.z = 4;
scene.background = new THREE.Color(0xfffffff);
var render = function (time) {
requestAnimationFrame( render );
plane.material.uniforms.uTime.value = time/100;
renderer.render(scene, camera);
};
render();
};
main()
</script>
ShaderMaterial does not respond to lights because you're manually telling the shader what color to output when you assign values to gl_FragColor in the fragment shader. You're overriding the default behavior of materials, so all things like, position, rotation, color are up to you to control.
If you want a hemisphere light to affect your shader, then you'd have to manually write those calculations in GLSL, which is a pretty complex process. You'd have to feed the colors of the light as uniforms, then you'll have to figure out which triangles are facing up and down so they "reflect" those light colors accordingly.
Three.js has all its material shaders broken down throughout several files in "ShaderChunks", so it's pretty difficult to track down exactly where each step takes place.

How do you render to an R8UI, RedIntegerFormat, UnsignedByteType WebGLRenderTarget?

I'm trying to render to a single component 8 bit render target in three.js but I'm getting a number of errors I'm not sure how to solve and searching doesn't seem to come up with a lot of other hits. The WebGLRenderTarget is created with the following parameters:
format: THREE.RedIntegerFormat,
type: THREE.UnsignedByteType,
internalFormat: 'R8UI',
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
When rendering to the render target and then trying to copy it to the screen I get the following WebGL errors:
GL_INVALID_OPERATION: No defined conversion between clear value and attachment format.
GL_INVALID_OPERATION: Fragment shader output type does not match the bound framebuffer attachment type.
GL_INVALID_OPERATION: Mismatch between texture format and sampler type (signed/unsigned/float/shadow).
Here's a repro case for the issue I'm seeing:
<script type="module">
import * as THREE from 'https://cdn.skypack.dev/three'
import { FullScreenQuad } from 'https://cdn.skypack.dev/three/examples/jsm/postprocessing/Pass.js'
let camera, scene, renderer;
let geometry, material, mesh;
let renderTarget, fsQuad;
class FinalMaterial extends THREE.ShaderMaterial {
constructor() {
super( {
uniforms: {
map: { value: null }
},
vertexShader: /* glsl */`
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`,
fragmentShader: /* glsl */`
uniform sampler2D map;
varying vec2 vUv;
void main() {
vec4 texel = texture2D( map, vUv );
gl_FragColor = texel;
}`
} );
}
}
init();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.z = 1;
scene = new THREE.Scene();
geometry = new THREE.BoxGeometry( 0.2, 0.2, 0.2 );
material = new THREE.MeshNormalMaterial();
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animation );
document.body.appendChild( renderer.domElement );
renderTarget = new THREE.WebGLRenderTarget(
window.innerWidth,
window.innerHeight,
{
format: THREE.RedIntegerFormat,
type: THREE.UnsignedByteType,
internalFormat: 'R8UI',
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
}
);
renderTarget.texture.internalFormat = 'R8UI';
fsQuad = new FullScreenQuad( new FinalMaterial() );
fsQuad.material.uniforms.map.value = renderTarget.texture;
}
function animation( time ) {
mesh.rotation.x = time / 2000;
mesh.rotation.y = time / 1000;
renderer.setRenderTarget( renderTarget );
renderer.render( scene, camera );
renderer.setRenderTarget( null );
fsQuad.render( renderer );
}
</script>

Particular Wp Enqueue script in wordpress

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.

Book of shaders exercises

I am spending this winter holidays trying to learn something about shaders, I am stuck with this couple exercise:
y = sin(x);
Try the following exercises and notice what happens:
Add time (u_time) to x before computing the sin. Internalize that motion along
x.
how do I implement it?
You'll need 2 uniform variables, the resolution of the viewport (u_resolution) and the time (u_time) in seconds:
uniform vec2 u_resolution;
uniform float u_time;
x can be get by the x coordinate of the fragment. Map the x coordinate to the range [0, 2*PI]:
vec2 st = gl_FragCoord.xy/u_resolution.xy;
float x = st.x * 2.0 * 3.141529;
Calculate y. sin is the Sine function:
float y = sin(x + u_time);
Set the color channels of the fragment by y. y has to be mapped from the range [-1, 1], to [0, 1]:
gl_FragColor = vec4(vec3(y*0.5+0.5), 1.0);
The result is a sine gradient, moving from the right to the left:
var container, camera, scene, renderer, uniforms;
init();
animate();
function init() {
container = document.getElementById( 'container' );
camera = new THREE.Camera();
camera.position.z = 1;
scene = new THREE.Scene();
var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
uniforms = {
u_time: { type: "f", value: 1.0 },
u_resolution: { type: "v2", value: new THREE.Vector2() }
};
var material = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
container.appendChild( renderer.domElement );
(window.onresize = function() {
renderer.setSize( window.innerWidth, window.innerHeight );
uniforms.u_resolution.value.x = renderer.domElement.width;
uniforms.u_resolution.value.y = renderer.domElement.height;
})();
}
function animate(delta_ms) {
requestAnimationFrame( animate );
uniforms.u_time.value = delta_ms / 1000.0;
renderer.render( scene, camera );
}
<script id="vertexShader" type="x-shader/x-vertex">
void main() {
gl_Position = vec4( position, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec2 u_resolution;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
float x = st.x * 2.0 * 3.141529;
float y = sin(x + u_time);
gl_FragColor = vec4(vec3(y*0.5+0.5), 1.0);
}
</script>
<div id="container"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>
I believe it would be something like this:
y = sin(u_time + x);
You should see the sin wave moving along the x axis.
Explanation:
u_time is the time in seconds since the shader started. Using this variable, we can add it to the x value before calculating sin, which will give the effect of the wave moving along the x axis.
To implement it, you can change the text just under the graph.

Background plane with shader overlaps everything in three.js

I'm trying to get a plane with a shader as background of my scene and a box with a lambert material over it. It's really simple but when I try to do it I get always the plane and the box don't appear. Any clue? What I don't understand?
Here is the jsfiddle:
http://jsfiddle.net/5zTz3/
Index.html
<html>
<head>
<title>The Cube</title>
<style>
canvas { width: 100%; height: 100%; }
body{margin: 0px;}
</style>
</head>
<body>
<script id="vertexShader" type="x-shader/x-vertex">
void main() {
gl_Position = vec4( position,1);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec2 resolution;
void main() {
vec2 coord = gl_FragCoord.xy;
float xmid = resolution.x/2.0;
float ymid = resolution.y/2.0;
float x = (coord.x - xmid)/resolution.x;
float y = (coord.y-ymid)/resolution.y;
float r = sqrt(x*x + y*y)+0.5;
vec4 color = vec4(1.0-vec2(r),1.3-r,1.0);
gl_FragColor = color;
}
</script>
<script src="https://rawgithub.com/mrdoob/three.js/master/build/three.js"></script>
<script src="scene.js">
</script>
</body>
</html>
scene.js
//Define scene
var scene = new THREE.Scene();
function render() {
requestAnimationFrame(render);
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
//Define camera
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
//Plane material
var uniforms = {
resolution: { type: "v2", value: new THREE.Vector2(window.innerWidth,window.innerHeight) }
};
var planeMaterial = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent
} );
//Create plane
var geometry = new THREE.PlaneGeometry(1800*2, 1600,1,1);
var plane = new THREE.Mesh(geometry, planeMaterial);
plane.position.z = - 500;
scene.add(plane);
//Create cube
var geometry = new THREE.CubeGeometry(1,1,1);
var cubeMaterial = new THREE.MeshLambertMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, cubeMaterial );
scene.add( cube );
//Define Render
var renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize( window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
//Define light
var light = new THREE.PointLight(0xffffff);
light.position.set(0,200,100);
scene.add(light);
//render
render();
If I change the plane geometry by another CubeGeometry ( new THREE.CubeGeometry(2,2,2); ) do what I want but I don't get why the plane don't work
In the vertex shader you need to multiply modelViewMatrix and projectionMatrix to the vertex position.
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
http://jsfiddle.net/5zTz3/2/
I'd really recommend you take a look at the book "Learning three.js". Its an excellent starting resource.
The example code from the book is available here: https://github.com/josdirksen/learning-threejs
The example Ch01.03 does what I think you are asking:
<!DOCTYPE html>
<html>
<head>
<title>Example 01.03 - Materials and light</title>
<script type="text/javascript" src="../libs/three.js"></script>
<script type="text/javascript" src="../libs/jquery-1.9.0.js"></script>
<style>
body{
/* set margin to 0 and overflow to hidden, to go fullscreen */
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>
<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
// once everything is loaded, we run our Three.js stuff.
$(function () {
// create a scene, that will hold all our elements such as objects, cameras and lights.
var scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// create a render and set the size
var renderer = new THREE.WebGLRenderer();
renderer.setClearColorHex(0xEEEEEE, 1.0);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true;
// create the ground plane
var planeGeometry = new THREE.PlaneGeometry(60,20);
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
var plane = new THREE.Mesh(planeGeometry,planeMaterial);
plane.receiveShadow = true;
// rotate and position the plane
plane.rotation.x=-0.5*Math.PI;
plane.position.x=15
plane.position.y=0
plane.position.z=0
// add the plane to the scene
scene.add(plane);
// create a cube
var cubeGeometry = new THREE.CubeGeometry(4,4,4);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.castShadow = true;
// position the cube
cube.position.x=-4;
cube.position.y=3;
cube.position.z=0;
// add the cube to the scene
scene.add(cube);
var sphereGeometry = new THREE.SphereGeometry(4,20,20);
var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
var sphere = new THREE.Mesh(sphereGeometry,sphereMaterial);
// position the sphere
sphere.position.x=20;
sphere.position.y=4;
sphere.position.z=2;
sphere.castShadow=true;
// add the sphere to the scene
scene.add(sphere);
// position and point the camera to the center of the scene
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
// add spotlight for the shadows
var spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( -40, 60, -10 );
spotLight.castShadow = true;
scene.add( spotLight );
// add the output of the renderer to the html element
$("#WebGL-output").append(renderer.domElement);
// call the render function
renderer.render(scene, camera);
});
</script>
</body>
</html>

Categories

Resources