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>
Related
So this is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
<style>
body {
overflow: hidden;
margin: 0;
}
</style>
</head>
<body>
<script src="three.js"></script>
<script src="pointerlockcontrols.js"></script>
<script>
var camera, scene, renderer, controls;
var cube;
var previous_time = performance.now();
var color = new THREE.Color();
camera = new THREE.PerspectiveCamera(99, window.innerWidth / window.innerHeight, 1, 100);
camera.position.y = 10;
scene = new THREE.Scene();
scene.background = new THREE.Color(0x0000ff);
scene.fog = new THREE.Fog(0xffffff, 0, 750);
var light = new THREE.HemisphereLight(0xeeeeff, 0x777788, 0.75);
light.position.set(0.5, 1, 0.75);
scene.add(light);
controls = new THREE.PointerLockControls(camera);
document.body.addEventListener("click", function() { controls.lock(); });
scene.add(controls.getObject());
var geometry = new THREE.BoxBufferGeometry(0.8*5, 1.5*5, 0.4*5);
var material = new THREE.MeshPhongMaterial({ color: 0xffffff });
cube = new THREE.Mesh(geometry, material);
scene.add(cube);
raycaster = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3(0, - 1, 0), 0, 10);
var floorGeometry = new THREE.PlaneBufferGeometry(2000, 2000, 100, 100);
floorGeometry.rotateX(- Math.PI / 2);
floorGeometry = floorGeometry.toNonIndexed(); // ensure each face has unique vertices
position = floorGeometry.attributes.position;
var colors = [];
for (var i = 0, l = position.count; i < l; i ++) {
color.setHSL(Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75);
colors.push(color.r, color.g, color.b);
}
floorGeometry.addAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
var floorMaterial = new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors });
var floor = new THREE.Mesh(floorGeometry, floorMaterial);
scene.add(floor);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', on_window_resize, false);
function on_window_resize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function loop() {
requestAnimationFrame(loop);
if (controls.isLocked === true) {
raycaster.ray.origin.copy(controls.getObject().position);
var vector = new THREE.Vector3();
controls.getObject().getWorldDirection(vector);
cube.rotation.y = Math.atan2(vector.x, vector.z);
cube.position.x = controls.getObject().position.x;
cube.position.z = controls.getObject().position.z+1;
}
renderer.render(scene, camera);
}
loop();
</script>
</body>
</html>
The important part here is:
// This makes the cube always look in the direction of the camera.
var vector = new THREE.Vector3();
controls.getObject().getWorldDirection(vector);
cube.rotation.y = Math.atan2(vector.x, vector.z);
// This makes the cube always be on the position of the camera (for later when there's movement)
cube.position.x = controls.getObject().position.x;
cube.position.z = controls.getObject().position.z+1;
And that works all pretty well, however because of the +1 (I want the cube to be a bit behind the camera) at the end, the cube is doing circular movements when rotating the camera.
I tried
cube.rotation.y = Math.atan2(vector.x, vector.z+1);
However that makes the cube not rotate at all.
How do I avoid the circular movements? I just want to place the cube on my position, a bit behind me, while it also faces the direction I look at.
I have to include the STLLoader.js of three.js into my web application but can't find some good clean code examples on how to start.
On the https://threejs.org website there is only the example demonstration for the STLLoader (https://threejs.org/examples/#webgl_loader_stl) but I can't find some clean sample code for the STLLoader (except for this one: https://github.com/mrdoob/three.js/blob/master/examples/webgl_loader_stl.html which is still quite difficult to understand for beginners), like there is for some other Loaders e.g. the OBJLoader (https://threejs.org/docs/index.html#examples/en/loaders/OBJLoader)...
Please help me out with this:)
That is what i came up with at the end...
For all those who had problems figuring it out too:)
HTML:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>STLLoader Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script src="three.js-master/build/three.js"></script>
<script src="three.js-master/examples/jsm/controls/OrbitControls.js"></script>
<script src="three.js-master/examples/jsm/loaders/STLLoader.js"></script>
<script src="js/custom.js"></script>
</body>
</html>
JS (custom.js):
// Necessary for camera/plane rotation
var degree = Math.PI/180;
// Setup
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Resize after viewport-size-change
window.addEventListener("resize", function () {
var height = window.innerHeight;
var width = window.innerWidth;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
});
// Adding controls
controls = new THREE.OrbitControls(camera, renderer.domElement);
// Ground (comment out line: "scene.add( plane );" if Ground is not needed...)
var plane = new THREE.Mesh(
new THREE.PlaneBufferGeometry(500, 500 ),
new THREE.MeshPhongMaterial( { color: 0x999999, specular: 0x101010 } )
);
plane.rotation.x = -90 * degree;
plane.position.y = 0;
scene.add( plane );
plane.receiveShadow = true;
// ASCII file - STL Import
var loader = new THREE.STLLoader();
loader.load( './stl/1.stl', function ( geometry ) {
var material = new THREE.MeshLambertMaterial( { color: 0xFFFFFF, specular: 0x111111, shininess: 200 } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 0, 0, 0);
scene.add( mesh );
} );
// Binary files - STL Import
loader.load( './stl/2.stl', function ( geometry ) {
var material = new THREE.MeshLambertMaterial( { color: 0xFFFFFF, specular: 0x111111, shininess: 200 } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 0, 20, 0);
scene.add( mesh );
} );
// Camera positioning
camera.position.z = 100;
camera.position.y = 100;
camera.rotation.x = -45 * degree;
// Ambient light (necessary for Phong/Lambert-materials, not for Basic)
var ambientLight = new THREE.AmbientLight(0xffffff, 1);
scene.add(ambientLight);
// Draw scene
var render = function () {
renderer.render(scene, camera);
};
// Run game loop (render,repeat)
var GameLoop = function () {
requestAnimationFrame(GameLoop);
render();
};
GameLoop();
And of course you need to download the three.js project and include it into your project root.
Leon
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>
First time trying out three js...my cube is black...I set the colour to red, is there a reason why?
<!DOCTYPE html>
<html>
<head>
<title>Some shapes</title>
<script type="text/javascript" src="../lib/threejs/build/three.js"></script>
<script type="text/javascript" src="../lib/jquery-2.1.3.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="output">
</div>
<script type="text/javascript">
$(function() {
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xEEEEEE);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true;
var cubeGeometry = new THREE.CubeGeometry(8,8,8);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 0x990000});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.x = -4;
cube.position.y = 3;
cube.position.z = 0;
scene.add(cube);
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
$("#output").append(renderer.domElement);
renderer.render(scene, camera);
});
</script>
</body>
</html>
I set the colour in the mesh lambert material...but I don't think I need to do anymore than this? In the browser it comes out black...does it have anything to do with setClearColour perhaps?
This was my original comment:
I changed MeshLambertMaterial to MeshBasicMaterial and it worked, I am guessing that because the lambert material colour is probably determined by some sort of light source on the object, since there is no light, the colour is coming out black...
I reworked my first try to this:
$(function() {
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xEEEEEE);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true;
var cubeGeometry = new THREE.CubeGeometry(8,8,8);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 0x990000});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.x = -4;
cube.position.y = 3;
cube.position.z = 0;
scene.add(cube);
//add some lighting
var ambientLight = new THREE.AmbientLight(0x0c0c0c);
scene.add(ambientLight);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true;
scene.add(spotLight);
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
$("#output").append(renderer.domElement);
renderer.render(scene, camera);
});
my guess was correct, when using Lambert or Phong materials, you need some lighting, otherwise in the dark, you won't be able to see the colours since the materials react to some lighting.
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.