extrusion with threejs has wrong dimensions - three.js

I'm trying to understand how to extrude a path using threejs.
I looked at https://threejs.org/docs/index.html#api/en/geometries/ExtrudeGeometry
which is what I need.
Here is the code I tried:
// ------------------------------------------------
// BASIC SETUP
// ------------------------------------------------
// Create an empty scene
var scene = new THREE.Scene();
// Create a basic perspective camera
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.z = 150;
// Create a renderer with Antialiasing
var renderer = new THREE.WebGLRenderer({antialias:true});
// Configure renderer clear color
renderer.setClearColor("#000000");
// Configure renderer size
renderer.setSize( window.innerWidth, window.innerHeight );
// Append Renderer to DOM
document.body.appendChild( renderer.domElement );
// ------------------------------------------------
// FUN STARTS HERE
// ------------------------------------------------
function make_graphics(){
// clean up:
for( var i = scene.children.length - 1; i >= 0; i--) {
obj = scene.children[i];
scene.remove(obj);
}
// Create a Shape Mesh with basic material
const shape = new THREE.Shape();
const x_len = 12;
const y_len = 8;
shape.moveTo( 0, 0 );
shape.lineTo( 0, y_len );
shape.lineTo( x_len, y_len );
shape.lineTo( x_len, 0 );
shape.lineTo( 0, 0 );
const extrudeSettings = {
steps: 2,
depth: 12,
bevelEnabled: true,
bevelThickness: 1,
bevelSize: 1,
bevelOffset: 0,
bevelSegments: 1
};
const geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00, wireframe:true } );
const mesh = new THREE.Mesh( geometry, material ) ;
scene.add( mesh );
// Render Loop
var render = function () {
requestAnimationFrame( render );
mesh.rotation.x += 0.001;
mesh.rotation.y += 0.001;
// Render the scene
renderer.render(scene, camera);
};
render(1, 1, 1);
}
document.addEventListener("DOMContentLoaded", function(){
make_graphics();
});
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Three.js 101</title>
<!-- Simple reset to delete the margins -->
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
<!-- Three.js CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js"></script>
</head>
<body>
<!-- Our code -->
<script src="script.js"></script>
</body>
</html>
The extrusion is very long. It should be 12 by 8 by 12 but you can see it looks like a long rod. Does anyone know why the dimensions look wrong?

You're using an old version of Three.js (r83). In that version, what became the depth option in ExtrudeGeometry was called amount, and it defaults to 100 if it's not present. If you change depth to amount in your extrudeSettings object, or (preferably) change your CDN link to import a more recent version of Three.js, your code should work as expected.

Related

Three JS - window.onload first displays scene too small before resizing when opening browser

I am learning WebGL and I want to do something basic: whenever I open index.html, I want the rendered scene to fit the window. However, when I try running my code (that I adapted from the WebGL tutorials), for a split second, the scene is displayed at a small size before being resized. Visually, this is jarring. How do I prevent that from happening?
My two files:
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- <meta charset="utf-8" name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=1">-->
<meta charset="utf-8">
<title>ThreeJS Rotation</title>
<style>
body { margin: 0; }
</style>
</head>
<body>
<script type="module" src="js/script.js"></script>
</body>
</html>
js/script.js:
// import * as THREE from './three.module.js'
//
// import {OrbitControls} from "./OrbitControls";
// See https://stackoverflow.com/questions/63269365/three-js-does-not-provide-an-export-named-eventdispatcher-while-loading-orbitcon
import { OrbitControls } from 'https://unpkg.com/three#0.119.1/examples/jsm/controls/OrbitControls.js';
import * as THREE from 'https://unpkg.com/three#0.119.1/build/three.module.js';
// import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three#0.121.1/examples/jsm/controls/OrbitControls.js';
const scene = new THREE.Scene();
// Add background image
// scene.background = new THREE.Color(0x19d7f8);
const loader = new THREE.TextureLoader();
scene.background = loader.load('https://assets.imgix.net/hp/snowshoe.jpg')
// Arguments:
// 1) Field of Value (degrees)
// 2) Aspect ratio
// 3) Near clipping plane
// 4) Far clipping plane
const camera = new THREE.PerspectiveCamera( 50 , window.innerWidth / window.innerHeight, 0.1, 2000 );
camera.position.set(0, 0, 5 )
const renderer = new THREE.WebGLRenderer();
// // Need to set size of renderer. For performance, may want to reduce size.
// // Can also reduce resolution by passing false as third arg to .setSize
// renderer.setSize( window.innerWidth, window.innerHeight );
// Add the rendered to the HTML
document.body.appendChild( renderer.domElement );
function resizer() {
var width = window.innerWidth;
let height = window.innerHeight;
let backgroundImg = scene.background;
let bgWidth = backgroundImg.image.width;
let bgHeight = backgroundImg.image.height;
let texAspect = bgWidth / bgHeight;
let aspect = width / height;
let relAspect = aspect / texAspect;
scene.background.repeat = new THREE.Vector2( Math.max(relAspect, 1), Math.max(1/relAspect,1) );
scene.background.offset = new THREE.Vector2( -Math.max(relAspect-1, 0)/2, -Math.max(1/relAspect-1, 0)/2 );
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix()
}
window.onload = resizer
window.addEventListener('resize', resizer)
var controls = new OrbitControls(camera, renderer.domElement);
// Prevent Ctrl + Mouse from panning
controls.enablePan = false;
controls.update();
// A BoxGeometry is an object that contains all points (vertices) and fill (faces)
// of the cube
// const geometry = new THREE.BoxGeometry();
// // Allegedly, BoxBufferGeometry is faster
// const geometry = new THREE.BoxBufferGeometry();
// // Determines surface color (maybe texture?)
// const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
//
// // Mesh takes a geometry and applies the material to it
// const cube = new THREE.Mesh( geometry, material );
//
// scene.add( cube );
// Add arrow variables
const arrowDirection = new THREE.Vector3();
// Center of screen
const arrowPosition = new THREE.Vector3(0, 0, 0);
//
// const arrowPosition = new THREE.Vector3(0, 1, 0);
//
// const arrowPosition = new THREE.Vector3(0, 0, 0);
arrowDirection.subVectors( scene.position, new THREE.Vector3(1, 1, 1)).normalize();
const arrow = new THREE.ArrowHelper( arrowDirection, arrowPosition, 1, 0xffff00, 0.6, 0.4);
scene.add( arrow );
// This somehow creates a loop that causes the rendered to draw the scene
// every time the screen is refreshed (typically 60fps)
function animate() {
requestAnimationFrame( animate );
// arrow.rotation.x += 0.01;
// arrow.rotation.y += 0.01;
// cube.rotation.x += 0.01;
// cube.rotation.y += 0.01;
renderer.render( scene, camera );
controls.update();
}
animate();
You can try to set the renderer size before adding the renderer canvas to the dom
const width = window.innerWidth;
const height = window.innerHeight;
renderer.setSize(width, height);
document.body.appendChild( renderer.domElement );

Is there a way to prevent culling a line when using an orthographic camera?

When using an orthographic camera I can't see the back side of my circle when it is angled.
It's as though the circle is being treated as a disc with a face that is blocking the view of where I expect to see the circle. Is there any way to use the orthographic camera but have not do any culling at all or at the very least not do any culling on this circle?
Do a rotate on this example to see what I'm saying:
// ------------------------------------------------
// BASIC SETUP
// ------------------------------------------------
// hard code canvas dimensions
const scale = 2;
const canvasHeight = 350 * scale;
const canvasWidth = 350 * scale;
// Create an empty scene
var scene = new THREE.Scene();
// Create a basic perspective camera
//var camera = new THREE.PerspectiveCamera( 75, canvasWidth/canvasHeight, 0.1, 1000 );
var camera = new THREE.OrthographicCamera( canvasWidth / - 2, canvasWidth / 2, canvasHeight / 2, canvasHeight / - 2, 1, 1000 );
camera.position.z = 4;
// Create a renderer with Antialiasing
var renderer = new THREE.WebGLRenderer({antialias:true});
// Configure renderer clear color
renderer.setClearColor("#C3C3C3");
// Configure renderer size
renderer.setSize(canvasWidth, canvasHeight);
// Append Renderer to DOM
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.update();
setTimeout(function() {
controls.reset();
}, 5000)
// ------------------------------------------------
// FUN STARTS HERE
// ------------------------------------------------
// Render Loop
var render = function () {
requestAnimationFrame( render );
//cube.rotation.x += 0.01;
//cube.rotation.y += 0.01;
controls.update();
// Render the scene
renderer.render(scene, camera);
// console.log(visibleWidthAtZDepth(camera,))
};
render();
function drawCircle()
{
let radius = canvasWidth / 2 - 5,
segments = 64,
material = new THREE.LineBasicMaterial( { color: 0x0000ff } ),
geometry = new THREE.CircleGeometry( radius, segments );
geometry.vertices.shift();
scene.add( new THREE.LineLoop( geometry, material ) );
}
drawCircle();
<!DOCTYPE html>
<html>
<head>
<meta name=viewport content="width=device-width,initial-scale=1">
<meta charset="utf-8"/>
</head>
<body>
</body>
<style>
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.js"></script>
<script src="https://unpkg.com/three#0.85.0/examples/js/controls/OrbitControls.js"></script>
<script src="bolt-hole-calculator.js"></script>
</html>
Set your camera further away from the origin. You are encountering the circle intersecting the near plane, because the camera is only 4 units from the origin, and the circle radius is much larger than that.
// ------------------------------------------------
// BASIC SETUP
// ------------------------------------------------
// hard code canvas dimensions
const scale = 2;
const canvasHeight = 350 * scale;
const canvasWidth = 350 * scale;
// Create an empty scene
var scene = new THREE.Scene();
// Create a basic perspective camera
//var camera = new THREE.PerspectiveCamera( 75, canvasWidth/canvasHeight, 0.1, 1000 );
var camera = new THREE.OrthographicCamera(canvasWidth / -2, canvasWidth / 2, canvasHeight / 2, canvasHeight / -2, 1, 1000);
camera.position.z = 500;
// Create a renderer with Antialiasing
var renderer = new THREE.WebGLRenderer({
antialias: true
});
// Configure renderer clear color
renderer.setClearColor("#C3C3C3");
// Configure renderer size
renderer.setSize(canvasWidth, canvasHeight);
// Append Renderer to DOM
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.update();
setTimeout(function() {
controls.reset();
}, 5000)
// ------------------------------------------------
// FUN STARTS HERE
// ------------------------------------------------
// Render Loop
var render = function() {
requestAnimationFrame(render);
//cube.rotation.x += 0.01;
//cube.rotation.y += 0.01;
controls.update();
// Render the scene
renderer.render(scene, camera);
// console.log(visibleWidthAtZDepth(camera,))
};
render();
function drawCircle() {
let radius = canvasWidth / 2 - 5,
segments = 64,
material = new THREE.LineBasicMaterial({
color: 0x0000ff
}),
geometry = new THREE.CircleGeometry(radius, segments);
geometry.vertices.shift();
scene.add(new THREE.LineLoop(geometry, material));
}
drawCircle();
// Do a rotate on this example to see what I 'm saying:
<!DOCTYPE html>
<html>
<head>
<meta name=viewport content="width=device-width,initial-scale=1">
<meta charset="utf-8" />
</head>
<body>
</body>
<style>
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.js"></script>
<script src="https://unpkg.com/three#0.85.0/examples/js/controls/OrbitControls.js"></script>
<script src="bolt-hole-calculator.js"></script>
</html>

three.js morph animation isnt animating correctly

I am trying implement a simple animation on a icosphere. The animation only consistst of 3 keyframes. Starting position, randomly selected vertices that have been pulled off to the side and then back to starting position. i used these two sources to try to create this.
https://www.youtube.com/watch?v=JKB4aPUkCJw
http://stemkoski.github.io/Three.js/Model-Animation.html
It seems like the animation completely disregards what the json file tells it to do and instead just moves some vertices randomly and then back to starting position.
here is my code
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>My first three.js app</title>
<style>
body{
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="three.min.js"></script>
<script src="ColladaLoader.js"></script>
<script src="OrbitControls.js"></script>
<script src="TrackballControls.js"></script>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js">
</script>
<script>
var scene, camera, renderer;
var geometry, material, mesh;
var controls;
var obj, android;
var animOffset = 0, // starting frame of animation
walking = false,
duration = 5000, // milliseconds to complete animation
keyframes = 3, // total number of animation frames
interpolation = duration / keyframes, // milliseconds per frame
lastKeyframe = 0, // previous keyframe
currentKeyframe = 0;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth /
window.innerHeight, 1, 10000 );
camera.position.z = 5;
var light = new THREE.PointLight(0xffffff, 0.9);
light.position.set(0, 100, 10);
scene.add(light);
var light2 = new THREE.PointLight(0xffffff, 0.9);
light.position.set(0, 0, 100);
scene.add(light2);
var light1 = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(light1);
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor(0xb7b7b7);
document.body.appendChild( renderer.domElement );
controls = new THREE.OrbitControls( camera );
var loader = new THREE.ObjectLoader();
loader.load('/three/star3.json', function (obj){
scene.add(obj);
obj.position.set(0, -0.5, 0);
});
}
var jsonLoader = new THREE.JSONLoader();
jsonLoader.load( "/three/portstar.json", addModelToScene );
// addModelToScene function is called back after model has loaded
function addModelToScene( geometry, materials )
{
// for preparing animation
for (var i = 0; i < materials.length; i++)
materials[i].morphTargets = true;
var material = new THREE.MultiMaterial( materials );
android = new THREE.Mesh( geometry, material );
android.scale.set(10,10,10);
scene.add( android );
}
function animate() {
controls.update();
render();
requestAnimationFrame( animate );
}
function render(){
if ( android ) // exists / is loaded
{
// Alternate morph targets
time = new Date().getTime() % duration;
keyframe = Math.floor( time / interpolation ) + animOffset;
if ( keyframe != currentKeyframe )
{
android.morphTargetInfluences[ lastKeyframe ] = 0;
android.morphTargetInfluences[ currentKeyframe ] = 1;
android.morphTargetInfluences[ keyframe ] = 0;
lastKeyframe = currentKeyframe;
currentKeyframe = keyframe;
}
android.morphTargetInfluences[ keyframe ] =
( time % interpolation ) / interpolation;
android.morphTargetInfluences[ lastKeyframe ] =
1 - android.morphTargetInfluences[ keyframe ];
}
//obj.rotation.x += 0.5;
renderer.render( scene, camera );
}
init();
render();
animate();
</script>
</body>
Everything has been exported the way showed in the video but i have also tried 30 other export settings trying to figure this out. Also, if anyone has any helpful links that would help me learn three.js feel free to comment them. I would really like to get good at it but i am having alot of trouble.

How to make a flat ring in Three.js?

I was able to make a donut with Three.js using THREE.TorusGeometry. But I can't get it to look like a flat ring like the ones in these pictures:
http://www.google.com/imgres?imgurl=http://www.titanjewellery.co.uk/Mens/TI21-Titanium-8mm-Flat-Brushed-Ring.jpg&imgrefurl=http://www.titanjewellery.co.uk/Mens/8mm-Brushed-Titanium-Flat-Ring.html&h=301&w=232&sz=16&tbnid=LCN7eQuo2wyG_M:&tbnh=90&tbnw=69&zoom=1&usg=__3vayMvDy26tsj2hwvCK9SsYwVwY=&docid=ZMdcBBBQOzMSoM&sa=X&ei=pEhsUeL4FKWJiAKCzIHYCQ&ved=0CEAQ9QEwBA&dur=1660
Here's what my donut looks like:
Is there another Three.js geometry that can generate a flat ring (right with flat inner and outer walls)? Or another way of going about this?
Thanks for any pointers you can share! :)
Update:
The code and dependencies were taken from:
http://mrdoob.github.io/three.js/examples/misc_controls_trackball.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - trackball controls</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
color: #000;
font-family:Monospace;
font-size:13px;
text-align:center;
font-weight: bold;
background-color: #fff;
margin: 0px;
overflow: hidden;
}
#info {
color:#000;
position: absolute;
top: 0px; width: 100%;
padding: 5px;
}
a {
color: red;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info">
three.js - trackball controls example</br>MOVE mouse & press LEFT/A: rotate, MIDDLE/S: zoom, RIGHT/D: pan
</div>
<script src="three.min.js"></script>
<script src="TrackballControls.js"></script>
<script src="Detector.js"></script>
<script src="stats.min.js"></script>
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats;
var camera, controls, scene, renderer;
var cross;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 500;
controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
controls.keys = [ 65, 83, 68 ];
controls.addEventListener( 'change', render );
// world
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 );
var radius = 100;
var tubeRadius = 50;
var radialSegments = 8 * 10;
var tubularSegments = 6 * 15;
var arc = Math.PI * 2;
var geometry = new THREE.TorusGeometry( radius, tubeRadius, radialSegments, tubularSegments, arc );
var material = new THREE.MeshLambertMaterial( { color:0xffffff, shading: THREE.FlatShading } );
for ( var i = 0; i < 1; i ++ ) {
var mesh = new THREE.Mesh( geometry, material );
mesh.updateMatrix();
mesh.matrixAutoUpdate = false;
scene.add( mesh );
}
// lights
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 1, 1, 1 );
scene.add( light );
light = new THREE.DirectionalLight( 0x002288 );
light.position.set( -1, -1, -1 );
scene.add( light );
light = new THREE.AmbientLight( 0x222222 );
scene.add( light );
// renderer
renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setClearColor( scene.fog.color, 1 );
renderer.setSize( window.innerWidth, window.innerHeight );
container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
controls.handleResize();
render();
}
function animate() {
requestAnimationFrame( animate );
controls.update();
}
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>
http://jsfiddle.net/alininja/b4qGx/1/
There are multiple options:
Use TubeGeometry - this is probably what you need
ExtrudeGeometry to extrude a disk
lathe an offset rectangle with LatheGeometry
Use THREE.Shape -> grab the tube like shape from the webgl_geometry_shapes sample
You can use the RingGeometry function. The following code adds to the scene a full (between 0 and 360 degrees) wireframed red ring of inner radius equals to 10 and outer radio equals to 20. You can play with the other indicated variables to adjust the aspect of the disc you want to generate ()
var geometry = new THREE.RingGeometry(10, 20, thetaSegments, phiSegments, 0, Math.PI * 2);
var ring = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({color: 0xff0000, wireframe: true}));
ring.position.set(25, 30, 0);
scene.add(ring);
Check this code!
var geometry = new THREE.TorusGeometry( 3, 0.5, 20, 2999 );
ring1 = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({color: 0xffffff, wireframe: true}));
scene.add(ring1);

camera inside a sphere

I want to create a skydome and made the shpere, texture loading also fine but I cannot move the camera inside the sphere.
The sphere disappears. I know it is an amateur issue but cannot see the inside of the sphere.
Is it some kind of cutting or Z-buffer issue?
How can I fix it?
My code:
<html>
<head>
<script src="js/jquery-1.8.3.min.js"></script>
<script src="js/three.min.js"></script>
</head>
<body>
<div id="container">
</div>
<script>
function addSpaceSphere( ){
// set up the sphere vars
var radius = 200,
segments = 16,
rings = 16;
var material = new THREE.MeshPhongMaterial({
color:0xFFFFFF,
map: THREE.ImageUtils.loadTexture( 'textures/SPACE014SX.png' )
});
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(
radius,
segments,
rings
),
material
);
// add the sphere to the scene
scene.add(sphere);
}
function addLights(){
// create a point light
var ambient = new THREE.AmbientLight( 0xFFFFFF );
scene.add( ambient );
}
function render() {
camera.lookAt( focus );
camera.updateProjectionMatrix();
renderer.render( scene, camera );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function createScene(){
// add the camera to the scene
scene.add(camera);
// the camera starts at 0,0,0
// so pull it back
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 300;
// start the renderer
renderer.setSize(WIDTH, HEIGHT);
$container.append(renderer.domElement);
addSpaceSphere( );
addLights();
animate();
}
var WIDTH = window.innerWidth;
var HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.01,
FAR = 10000;
var focus = new THREE.Vector3( 0, 0, 0 );
var isUserInteracting = false,
onPointerDownPointerX = 0, onPointerDownPointerY = 0,
lon = 0, onPointerDownLon = 0,
lat = 0, onPointerDownLat = 0,
phi = 0, theta = 0;
var $container = $('#container');
// create a WebGL renderer, camera
// and a scene
//var renderer = new THREE.CanvasRenderer();
var renderer = new THREE.WebGLRenderer();
var camera = new THREE.PerspectiveCamera(
VIEW_ANGLE, ASPECT, NEAR, FAR
);
var scene = new THREE.Scene();
createScene();
</script>
</body>
make the skydome material double-sided -- it's being culled. Set the 'side' attribute to THREE.DoubleSide
(or THREE.BackSide should work too, if the camera is ONLY inside the sphere)

Resources