Drawing a square in a website using three.js - three.js

Why does the following code not draw a complete square?
var square = new THREE.Geometry();
square.vertices.push(new THREE.Vector3(0, 0, 0));
square.vertices.push(new THREE.Vector3(0, 100, 0));
square.vertices.push(new THREE.Vector3(100, 100, 0));
square.vertices.push(new THREE.Vector3(100, 0, 0));
square.faces.push(new THREE.Face3(0, 1, 2));
square.faces.push(new THREE.Face3(0, 3, 2));
var line = new THREE.Line(square, new THREE.LineBasicMaterial({ color: 0xffffff, opacity: 0.5 }));
scene.add(line);
i get the following result:

square.vertices.push(new THREE.Vector3(0, 0, 0));
square.vertices.push(new THREE.Vector3(0, 100, 0));
square.vertices.push(new THREE.Vector3(100, 100, 0));
square.vertices.push(new THREE.Vector3(100, 0, 0));
square.vertices.push(new THREE.Vector3(0, 0, 0));
square.faces.push(new THREE.Face3(0, 1, 2));
square.faces.push(new THREE.Face3(0, 3, 2));
var line = new THREE.Line(square, new THREE.LineBasicMaterial({ color: 0xffffff, opacity: 0.5 }));
scene.add(line);

Related

How may i use three.js to create a fatline

Currently, I'm working on a three.js project where i must use a lot of points to drow a fat line ;I had use the lineWidth property of THREE.LineBasicMaterial,but it is not work; My big question now is how to to do it?
this is the code
createLine_old() {
const material = new THREE.LineBasicMaterial({
color: 0x0000ff,
linewidth: 10
});
const points = [];
points.push(new THREE.Vector3(-10, 0, 0));
points.push(new THREE.Vector3(0, 10, 0));
points.push(new THREE.Vector3(10, 0, 0));
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const line = new THREE.Line(geometry, material);
scene.add(line);
}
At last, any help would be appreciated;

Why cubes do not always animate with three.js

In the code below, cubes sometimes move with animation and sometimes without. How can I fix it ?
Also, how should I set rotation speed ?
new Vue({
el: '#app',
data () {
return {
camera: null,
scene: null,
renderer: null,
cube: null,
angle: null
}
},
methods: {
init: function () {
this.camera = new THREE.PerspectiveCamera(1, 1);
this.camera.position.z = 200;
// Make a scene
this.scene = new THREE.Scene();
this.clock = new THREE.Clock();
//
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
let container = document.getElementById('container')
this.renderer.setSize(container.offsetWidth, container.offsetHeight);
container.appendChild(this.renderer.domElement);
let cube2 = this.createCube()
cube2.name = "cube2"
// cube2.position = new THREE.Vector3(1, 0)
this.scene.add(cube2);
},
createCube: function () {
// GEOMETRY
// 1. Start with empty geometry
let geometry = new THREE.Geometry();
// 2. Add vertices to geometry
geometry.vertices.push(
// verts [0-3] are in in +z
new THREE.Vector3(-1, 1, 1),
new THREE.Vector3(-1, -1, 1),
new THREE.Vector3(1, -1, 1),
new THREE.Vector3(1, 1, 1),
// verts [4-7] in -z
new THREE.Vector3(-1, 1, -1),
new THREE.Vector3(-1, -1, -1),
new THREE.Vector3(1, -1, -1),
new THREE.Vector3(1, 1, -1),
);
// 3. Connect vertices in desired order to make faces
let b = 0x1db0ec
let y = 0xffef3a
let r = 0xea353d
let w = 0xffffff
// Set half faces
geometry.faces.push(new THREE.Face3(0, 1, 2)); // blue
geometry.faces.push(new THREE.Face3(0, 2, 3)); // yellow
geometry.faces.push(new THREE.Face3(5, 4, 6)); // white
geometry.faces.push(new THREE.Face3(6, 4, 7)); // red
// Set whole faces
geometry.faces.push(new THREE.Face3(1, 0, 5)); // blue
geometry.faces.push(new THREE.Face3(5, 0, 4));
geometry.faces.push(new THREE.Face3(1, 5, 2)); // white
geometry.faces.push(new THREE.Face3(5, 6, 2));
geometry.faces.push(new THREE.Face3(2, 6, 3)); // red
geometry.faces.push(new THREE.Face3(3, 6, 7));
geometry.faces.push(new THREE.Face3(0, 3, 4)); // yellow
geometry.faces.push(new THREE.Face3(3, 7, 4));
// Set faces colors
geometry.faces[0].color.setHex(b); // Half face
geometry.faces[1].color.setHex(y);
geometry.faces[2].color.setHex(w);
geometry.faces[3].color.setHex(r);
geometry.faces[4].color.setHex(b); // Whole face
geometry.faces[5].color.setHex(b);
geometry.faces[6].color.setHex(w);
geometry.faces[7].color.setHex(w);
geometry.faces[8].color.setHex(r);
geometry.faces[9].color.setHex(r);
geometry.faces[10].color.setHex(y);
geometry.faces[11].color.setHex(y);
// MATERIAL
// Make a material
let material = new THREE.MeshBasicMaterial({
// color: 0x00FF00,
vertexColors: THREE.FaceColors,
wireframe: false,
});
// MESH
let cube = new THREE.Mesh(geometry, material);
return cube
},
rotateTo: function (face) {
if (face == 'yellow')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI / 2, Math.PI / 2));
else if (face == 'red')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, Math.PI / 2));
else if (face == 'blue')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, - Math.PI / 2));
else if (face == 'white')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(- Math.PI / 2, Math.PI / 2, 0));
else if (face == 'yb')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
else if (face == 'rw')
this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI, 0, 0));
this.animate()
},
animate: function () {
let id = requestAnimationFrame(this.animate);
let delta = this.clock.getDelta();
this.scene.children[0].quaternion.rotateTowards(this.angle, Math.PI * delta);
this.renderer.render(this.scene, this.camera);
if (this.scene.children[0].quaternion.equals(this.angle)) {
cancelAnimationFrame(id)
}
}
},
mounted () {
this.init();
this.renderer.render(this.scene, this.camera);
}
})
#container {
background-color: #aaa;
width: 20em;
height: 20em;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://threejs.org/build/three.min.js"></script>
<div id="app">
<div>
<button v-on:click="rotateTo('yellow')">yellow</button>
<button v-on:click="rotateTo('red')">red</button>
<button v-on:click="rotateTo('blue')">blue</button>
<button v-on:click="rotateTo('white')">white</button>
<button v-on:click="rotateTo('yb')">yellow/blue</button>
<button v-on:click="rotateTo('rw')">red/white</button>
</div>
<div id="container"></div>
</div>
UPDATE
Code isolated to only the threejs portion.
var camera = null;
var scene = null;
var renderer = null;
var cube = null;
var angle = null;
init();
renderer.render(scene, camera);
function init() {
camera = new THREE.PerspectiveCamera(1, 1);
camera.position.z = 200;
// Make a scene
scene = new THREE.Scene();
clock = new THREE.Clock();
//
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
let container = document.getElementById('container');
renderer.setSize(container.offsetWidth, container.offsetHeight);
container.appendChild(renderer.domElement);
let cube2 = createCube();
cube2.name = "cube2";
// cube2.position = new THREE.Vector3(1, 0)
scene.add(cube2);
}
function createCube() {
// GEOMETRY
// 1. Start with empty geometry
let geometry = new THREE.Geometry();
// 2. Add vertices to geometry
geometry.vertices.push(
// verts [0-3] are in in +z
new THREE.Vector3(-1, 1, 1),
new THREE.Vector3(-1, -1, 1),
new THREE.Vector3(1, -1, 1),
new THREE.Vector3(1, 1, 1),
// verts [4-7] in -z
new THREE.Vector3(-1, 1, -1),
new THREE.Vector3(-1, -1, -1),
new THREE.Vector3(1, -1, -1),
new THREE.Vector3(1, 1, -1),
);
// 3. Connect vertices in desired order to make faces
let b = 0x1db0ec;
let y = 0xffef3a;
let r = 0xea353d;
let w = 0xffffff;
// Set half faces
geometry.faces.push(new THREE.Face3(0, 1, 2)); // blue
geometry.faces.push(new THREE.Face3(0, 2, 3)); // yellow
geometry.faces.push(new THREE.Face3(5, 4, 6)); // white
geometry.faces.push(new THREE.Face3(6, 4, 7)); // red
// Set whole faces
geometry.faces.push(new THREE.Face3(1, 0, 5)); // blue
geometry.faces.push(new THREE.Face3(5, 0, 4));
geometry.faces.push(new THREE.Face3(1, 5, 2)); // white
geometry.faces.push(new THREE.Face3(5, 6, 2));
geometry.faces.push(new THREE.Face3(2, 6, 3)); // red
geometry.faces.push(new THREE.Face3(3, 6, 7));
geometry.faces.push(new THREE.Face3(0, 3, 4)); // yellow
geometry.faces.push(new THREE.Face3(3, 7, 4));
// Set faces colors
geometry.faces[0].color.setHex(b); // Half face
geometry.faces[1].color.setHex(y);
geometry.faces[2].color.setHex(w);
geometry.faces[3].color.setHex(r);
geometry.faces[4].color.setHex(b); // Whole face
geometry.faces[5].color.setHex(b);
geometry.faces[6].color.setHex(w);
geometry.faces[7].color.setHex(w);
geometry.faces[8].color.setHex(r);
geometry.faces[9].color.setHex(r);
geometry.faces[10].color.setHex(y);
geometry.faces[11].color.setHex(y);
// MATERIAL
// Make a material
let material = new THREE.MeshBasicMaterial({
// color: 0x00FF00,
vertexColors: THREE.FaceColors,
wireframe: false,
});
// MESH
let cube = new THREE.Mesh(geometry, material);
return cube;
}
function rotateTo(face) {
if (face == 'yellow')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI / 2, Math.PI / 2));
else if (face == 'red')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, Math.PI / 2));
else if (face == 'blue')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, -Math.PI / 2));
else if (face == 'white')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(-Math.PI / 2, Math.PI / 2, 0));
else if (face == 'yb')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
else if (face == 'rw')
angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI, 0, 0));
animate();
}
function animate() {
let id = requestAnimationFrame(animate);
let delta = clock.getDelta();
scene.children[0].quaternion.rotateTowards(angle, Math.PI * delta);
renderer.render(scene, camera);
if (scene.children[0].quaternion.equals(angle)) {
cancelAnimationFrame(id);
}
}
#container {
background-color: #aaa;
width: 20em;
height: 20em;
}
<script src="https://threejs.org/build/three.min.js"></script>
<div>
<button onclick="rotateTo('yellow')">yellow</button>
<button onclick="rotateTo('red')">red</button>
<button onclick="rotateTo('blue')">blue</button>
<button onclick="rotateTo('white')">white</button>
<button onclick="rotateTo('yb')">yellow/blue</button>
<button onclick="rotateTo('rw')">red/white</button>
</div>
<div id="container"></div>
The reason for the animation not playing is because when you cancelAnimationFrame the clock is still running, so the next time you call rotateTo the delta is so high that the animation ends immediately.
you can avoid this by stopping the clock with cancelAnimationFrame, and start it again when calling rotateTo as follows:
function rotateTo(face) {
clock.start()
...
}
function animate() {
...
if (scene.children[0].quaternion.equals(angle)) {
cancelAnimationFrame(id);
clock.stop()
}
}
as for rotation speed, the 2nd arg of rotateTowards is step, which determines how fast will it get there. So if you add a modifier var to it, you can control the speed.
let rotSpeedMotifier = 0.2 // the higher the faster
scene.children[0].quaternion.rotateTowards(angle, Math.PI * delta * rotSpeedMotifier );

Why do I see only half of crate?

I don't understand why I only see half of crate. I recall that it happened to me before, with other graphics pipelines.
Here is the fiddle link: https://jsfiddle.net/20azohgc/10/
Here is the code:
//Basic THREE setup:
const canvas = document.getElementById("canvasThree");
const scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, 1, 1, 500);
camera.position.set( 0, 0, 100 );
camera.lookAt( new THREE.Vector3( 0, 0, 0 ));
camera.position.set( 0, 0, 100 )
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) )
const renderer = new THREE.WebGLRenderer({ canvas });
const light = new THREE.PointLight(0xFFFFFF);
light.position.set(0, 1, 2);
scene.add(light);
var texture = new THREE.TextureLoader().load( "https://raw.githubusercontent.com/mrdoob/three.js/master/examples/textures/crate.gif" );
var material = new THREE.MeshBasicMaterial({ color: "white", map: texture });
const pos = new Float32Array([0, 0, 0, 0, 10, 0, 10, 10, 0, 0, 0, 0, 10, 0, 0, 10, 10, 0]);
const nrm = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
const tex = new Float32Array([0,0, 1,0, 1,1, 0,0, 0,1, 1,1]);
const geo = new THREE.BufferGeometry();
geo.addAttribute("position", new THREE.BufferAttribute(pos, 3));
geo.addAttribute("normal", new THREE.BufferAttribute(nrm, 3));
geo.addAttribute("uv", new THREE.BufferAttribute(tex, 2));
//This is a drawing group, each square is 6 indices (2 triangles with 3 vertices each).
geo.addGroup(0 ,6,0);
const mesh = new THREE.Mesh(geo, [material]);
mesh.position.set(-2,-0.5,0);
scene.add(mesh);
function update(){
scene.rotation.y = 0.25 * Math.cos(performance.now() * 0.001)
renderer.render(scene, camera);
requestAnimationFrame(update);
}
update();

How to add shading to object model in threeJS?

I have a custom-made object, an obelisk, next to a cube. The obelisk is made with THREE.Geometry (each vertex and face added manually), while the cube is made with THREE.BoxGeometry. They both use THREE.MeshNormalMaterial.
So why does the cube get colors that change with rotation, while the obelisk is just gray? I've managed to get other meshes to add color to the obelisk, but can't figure out how to get the sides to change colors during rotation.
<!DOCTYPE html>
<html>
<head>
<title>Washington Monument</title>
<style>
html, body {
margin: 0; padding:0;
overflow: hidden;
}
canvas {
width: 100%; height: 100%;
}
</style>
</head>
<body>
<script src="../../lib/three.min.js"></script>
<script>
var scene = new THREE.Scene();
var fieldOfView = 45;
var aspect = window.innerWidth/window.innerHeight;
var nearClippingPlane = 0.01;
var farClippingPlane = 1000;
var camera = new THREE.PerspectiveCamera(fieldOfView, aspect, nearClippingPlane, farClippingPlane);
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var obeliskMaterial = new THREE.MeshNormalMaterial();
var obeliskGeometry = new THREE.Geometry();
obeliskGeometry.vertices.push(new THREE.Vector3( 8.40, -80, 8.40));
obeliskGeometry.vertices.push(new THREE.Vector3( 8.40, -80, -8.40));
obeliskGeometry.vertices.push(new THREE.Vector3(-8.40, -80, -8.40));
obeliskGeometry.vertices.push(new THREE.Vector3(-8.40, -80, 8.40));
obeliskGeometry.vertices.push(new THREE.Vector3( 5.25, 72.36, 5.25));
obeliskGeometry.vertices.push(new THREE.Vector3( 5.25, 72.36, -5.25));
obeliskGeometry.vertices.push(new THREE.Vector3(-5.25, 72.36, -5.25));
obeliskGeometry.vertices.push(new THREE.Vector3(-5.25, 72.36, 5.25));
obeliskGeometry.vertices.push(new THREE.Vector3( 0, 89.29, 0));
obeliskGeometry.faces.push(new THREE.Face3(0, 1, 5), new THREE.Face3(0, 5, 4));
obeliskGeometry.faces.push(new THREE.Face3(1, 2, 6), new THREE.Face3(1, 6, 5));
obeliskGeometry.faces.push(new THREE.Face3(2, 3, 7), new THREE.Face3(2, 7, 6));
obeliskGeometry.faces.push(new THREE.Face3(3, 0, 4), new THREE.Face3(3, 4, 7));
obeliskGeometry.faces.push(new THREE.Face3(4, 5, 8));
obeliskGeometry.faces.push(new THREE.Face3(5, 6, 8));
obeliskGeometry.faces.push(new THREE.Face3(6, 7, 8));
obeliskGeometry.faces.push(new THREE.Face3(7, 4, 8));
var obeliskMesh = new THREE.Mesh(obeliskGeometry, obeliskMaterial);
scene.add(obeliskMesh);
var material = new THREE.MeshNormalMaterial();
var geom = new THREE.BoxGeometry(16, 16, 8);
var cube = new THREE.Mesh(geom, material);
cube.position.x = 40;
scene.add(cube);
camera.position.z = 320;
var render = function () {
requestAnimationFrame(render);
obeliskMesh.rotation.y += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
If you want to use MeshNormalMaterial in a custom geometry, you have to compute the normals of the geometry before creating the mesh:
obeliskGeometry.computeFaceNormals();
In your example:
[...]
obeliskGeometry.faces.push(new THREE.Face3(7, 4, 8));
obeliskGeometry.computeFaceNormals();
var obeliskMesh = new THREE.Mesh(obeliskGeometry, obeliskMaterial);
[...]

THREE.DoubleSide doesn't work with THREE.MeshLambertMaterial and custom geometry

I'm trying to make a double-sided mesh with THREE.MeshLambertMaterial, but only the front side is shaded. It works fine when I use THREE.MeshBasicMaterial. I am using the THREE.WebGLRenderer, version 57.
Here's a simplified example with a rectangle:
var rectWidth = 100, rectLength = 100;
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(0, rectWidth, 0));
geometry.vertices.push(new THREE.Vector3(rectLength, rectWidth, 0));
geometry.vertices.push(new THREE.Vector3(rectLength, 0, 0));
geometry.vertices.push(new THREE.Vector3(0, 0, 0));
geometry.faces.push(new THREE.Face4(0, 1, 2, 3));
// MeshBasicMaterial works
var material = new THREE.MeshLambertMaterial({
color: 0xCC0000,
side: THREE.DoubleSide,
});
geometry.computeFaceNormals();
geometry.computeVertexNormals();
var rect = new THREE.Mesh(geometry, material);
scene.add(rect);
What am I doing wrong? I found http://mrdoob.github.com/three.js/examples/webgl_performance_doublesided.html, which shows that THREE.DoubleSide works with THREE.MeshPhongMaterial (which also didn't work in my case). The example uses a built-in geometry though, whereas I am building a custom one, so I suppose I am missing something there.

Resources