I'm a beginner in three.js. My task is to build a simple FPS game. I'm having many troubles with the gun and the bullets. When I press "spacebar" my weapon shoots but the problem is that the bullets go in the right direction only for a small part of the screen then they start to go in direction that are not the ones I want.
This is an example :
image1
image2
Here is the code I wrote for the bullet :
// SHOOT BULLET
for(var index=0; index<bullets.length; index+=1){
if( bullets[index] === undefined ) continue;
if( bullets[index].alive == false ){
bullets.splice(index,1);
continue;
}
bullets[index].position.add(bullets[index].velocity);
}
if(keyboard[32] && canShoot <= 0){ // spacebar key
// creates a bullet as a Mesh object
var bullet = new THREE.Mesh(
new THREE.SphereGeometry(0.2,8,8),
new THREE.MeshBasicMaterial({color:0x42FFFF})
);
// position the bullet to come from the player's weapon
bullet.position.set(
camera.position.x - 0.7*parseInt(-Math.cos(camera.rotation.z)),
camera.position.y - 0.3,
camera.position.z +1*parseInt(-Math.cos(camera.rotation.z))
);
// set the velocity of the bullet
bullet.velocity = new THREE.Vector3( (-mouse.x - Math.sin(camera.rotation.y + Math.PI/6) * 7),//*parseInt(-Math.cos(camera.rotation.z)) ,
mouse.y,
Math.cos(camera.rotation.y)*parseInt(-Math.cos(camera.rotation.z))
).normalize();
console.info(bullet.velocity);
// after 1000ms, set alive to false and remove from scene
// setting alive to false flags our update code to remove
// the bullet from the bullets array
bullet.alive = true;
setTimeout(function(){
bullet.alive = false;
scene.remove(bullet);
}, 1000);
// add to scene, array, and set the delay to 10 frames
bullets.push(bullet);
scene.add(bullet);
canShoot = 10;
}
if(canShoot > 0) canShoot -= 1;
A rough concept of how you can set direction and movement of bullets:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 10000);
camera.position.set(0, 0, 1);
scene.add(camera);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var background = new THREE.Mesh(new THREE.SphereGeometry(1000, 90, 45), new THREE.MeshBasicMaterial({
color: "gray",
wireframe: true
}));
scene.add(background);
var weapon = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 5), new THREE.MeshBasicMaterial({
color: 0x5555ff
}));
weapon.position.set(2, -1, -2.5);
camera.add(weapon);
var emitter = new THREE.Object3D();
emitter.position.set(2, -1, -5);
camera.add(emitter);
var plasmaBalls = [];
window.addEventListener("mousedown", onMouseDown);
function onMouseDown() {
let plasmaBall = new THREE.Mesh(new THREE.SphereGeometry(0.5, 8, 4), new THREE.MeshBasicMaterial({
color: "aqua"
}));
plasmaBall.position.copy(emitter.getWorldPosition()); // start position - the tip of the weapon
plasmaBall.quaternion.copy(camera.quaternion); // apply camera's quaternion
scene.add(plasmaBall);
plasmaBalls.push(plasmaBall);
}
var speed = 50;
var clock = new THREE.Clock();
var delta = 0;
(function render() {
requestAnimationFrame(render);
delta = clock.getDelta();
plasmaBalls.forEach(b => {
b.translateZ(-speed * delta); // move along the local z-axis
});
renderer.render(scene, camera);
})()
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.115.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.115.0/examples/js/controls/OrbitControls.js"></script>
Related
Using the WebGLRenderer, successfully loaded an .obj file created in Cinema4d.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.z = 200;
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
var keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30, 100%, 75%)'), 1.0);
keyLight.position.set(-100, 0, 100);
var fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240, 100%, 75%)'), 0.75);
fillLight.position.set(100, 0, 100);
var backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(100, 0, -100).normalize();
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
const material = new THREE.LineBasicMaterial( {
color: 0xffffff,
linewidth: 1,
linecap: 'round', //ignored by WebGLRenderer
linejoin: 'round' //ignored by WebGLRenderer
} );
scene.add(material)
var objLoader = new THREE.OBJLoader();
objLoader.setPath('/examples/3d-obj-loader/assets/');
objLoader.load('Untitled2.obj', function (object) {
object.position.y -= 60;
scene.add(object);
});
var animate = function () {
requestAnimationFrame( animate );
controls.update();
renderer.render(scene, camera);
};
animate();
Aiming to convert this to vector using the SVGRenderer - tried swapping out the THREE.WebGLRenderer for SVGRenderer but there's clearly more to it than this, and can't find any walkthroughs, or breakdowns on here.
Can see that what I'm looking for is technically possible with three.js!
Linked an image of the 3d file I'm looking to vectorise - a simple mountain style scene - aiming for each edges of the vertices to be stroked, with no texture needed (white shape, black edges).
Tried making a JSON with Bodymovin and proved impossible to join al the paths of the vertices without lots of stray lines appearing.
enter image description here
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
Upon running there is a slow but consistent drop in fps. I have tried to identify the responsible function and it seems to be that:
updatepoints() and rotateTriangle() seem to be the main culprits but it's clear I have misunderstood something or used an inefficient means of calculating something somewhere
Upon further inspection using browser tools it seems to be an array and an object that are filling up the memory which I'm guessing is what is causing the frame drops.
I have also noticed that the buffer in the performance tab for the browser tools is filling up
I know bufferGeometry is the more efficient means of creating objects but I'd still like to know the cause the performance issues
Sorry to just dump code but I feel as though it'll be something obvious.
Any advice or ways of going about finding the problem and solution would be greatly appreciated
//every scene needs these
var scene, camera, renderer, controls;
//links div with canvas
var canvas = document.getElementById('canvas');
// What I need are number of particles and the length the curve goes to be uncoupled
// Each part of degree array serves one particles
// If I added a factor so:
// factor * coord *
//creating particles
var particleCount = 360;
var particles = [];
var particles2 = [];
var particles3 = [];
var SPEED = 0.01;
var radians, y, x;
var centerX = 0;
var centerY = 0;
var radius = 231.84;
var pointPositions=[];
var vupdateXvertices, updateYvertices, updateXvertices2, updateYvertices2,
updateXvertices3, updateYvertices3;
var pivot1;
var parent;
var pointsX = [];
var pointsY = [];
var particleMaterial = new THREE.MeshBasicMaterial({
color: 0x7a7a7a,
transparent: true,
opacity: 0.8
});
init();
animate();
function init() {
scene = new THREE.Scene();
//setup camera for scene
//PerspectiveCamera(fov, aspect, near, far [In terms of camera frustum plane])
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000;
//setup renderer for scene (generation of whatever you've made)
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x31AED1, 1);
renderer.setSize( window.innerWidth, window.innerHeight );
//OrbitControls(Camera, HTMLDOMElement)
controls = new THREE.OrbitControls( camera, renderer.domElement );
// Set to true to enable damping (inertia), which can be used to give a sense
//of weight to the controls. Default is false.
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = false;
console.log("Called");
fillSceneWithParticles();
fillSceneWithShapes();
canvas.appendChild( renderer.domElement );
renderer.render( scene, camera );
}
function fillSceneWithParticles() {
var particleGeometry = new THREE.SphereGeometry(3, 32, 32);
parent = new THREE.Object3D();
scene.add(parent);
for (var i = 0; i < particleCount; i++) {
particles[i] = new THREE.Mesh( particleGeometry, particleMaterial );
particles[i].position.x = 0;
particles[i].position.y = 0;
particles[i].position.z = (0);
particles2[i] = new THREE.Mesh( particleGeometry, particleMaterial );
particles2[i].position.x = (200);
particles2[i].position.y = (-115.57);
particles2[i].position.z = (0);
particles3[i] = new THREE.Mesh( particleGeometry, particleMaterial );
particles3[i].position.x = (0);
particles3[i].position.y = (231.84);
particles3[i].position.z = (0);
scene.add(particles[i]);
scene.add(particles2[i]);
scene.add(particles3[i]);
}
}
function fillSceneWithShapes() {
//Add a 2d Triangle W centre = 200, 115.57
var geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3(-200, -115.57, 0));
geometry.vertices.push( new THREE.Vector3( 200, -115.57, 0 ));
geometry.vertices.push( new THREE.Vector3( 0, 231.84, 0 ));
geometry.vertices.push( new THREE.Vector3( -200, -115.57, 0 ));
var material = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 10 } );
line = new THREE.Line( geometry, material );
scene.add(line);
}
function rotateTriangle() {
var geom = line.geometry.clone();
geom.applyMatrix(line.matrix);
updateXvertices = geom.vertices[0].x;
//The circle that we use to place our points
var centerX = 0;
var centerY = 0;
var radius = 231.84;
for(var degree = 90; degree < 450; degree++){
var radians = degree * Math.PI/180;
var x = centerX + radius * Math.cos(radians);
var y = centerY + radius * Math.sin(radians);
pointsX[degree - 90] = x;
pointsY[degree - 90] = y;
}
}
function updatePoints() {
//link counter with number of degrees initially created
//These are intialised because V1 = 120 degrees from V0 and V2 = 240 degrees
var counter = 120;
var counter2 = 240;
var zCounter = 0;
var curveFactor = 1;
var material = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 10 } );
var secondTriangle = new THREE.Geometry();
for (var i = 0; i < particleCount; i++) {
parent.add(particles[i]);
//Plot points around the circle relative to vertices of triangle
particles[i].position.x = (pointsX[i]);
particles[i].position.y = (pointsY[i]);
particles[i].position.z = zCounter * curveFactor;
//If array index out of bounds then loop back to the start of array
//i.e. Go back around the circle relative to the triangle vertices
parent.add(particles2[i]);
if (counter == 360) {
counter = 0;
}
particles2[i].position.x = (pointsX[counter]);
particles2[i].position.y = (pointsY[counter]);
particles2[i].position.z = zCounter * curveFactor;
counter++;
if (counter2 == 360) {
counter2 = 0;
}
parent.add(particles3[i]);
particles3[i].position.x = (pointsX[counter2]);
particles3[i].position.y = (pointsY[counter2]);
particles3[i].position.z = zCounter * curveFactor;
counter2++;
zCounter++;
}
//Give the second triangle the position of the last particles in array
secondTriangle.vertices.push( new THREE.Vector3(particles[particleCount-1].position.x, particles[particleCount-1].position.y, particles[particleCount-1].position.z ));
secondTriangle.vertices.push( new THREE.Vector3(particles2[particleCount-1].position.x, particles2[particleCount-1].position.y, particles2[particleCount-1].position.z ));
secondTriangle.vertices.push( new THREE.Vector3(particles3[particleCount-1].position.x, particles3[particleCount-1].position.y, particles3[particleCount-1].position.z ));
secondTriangle.vertices.push( new THREE.Vector3(particles[particleCount-1].position.x, particles[particleCount-1].position.y, particles[particleCount-1].position.z ));
line1 = new THREE.Line( secondTriangle, material );
scene.add(line1);
parent.add(line1);
}
function animate() {
requestAnimationFrame( animate );
controls.update();
rotateTriangle();
updatePoints();
line1.rotation.z -= SPEED *2;
line.rotation.z -= SPEED *2;
parent.rotation.z -= SPEED *2;
renderer.render( scene, camera );
}
In retrospect it seems obvious what the problem was.
Since I had geometry.vertices.push inside my animate loop it was continuously pushing new Vectors to a buffer.
I just had to move the pushing of those vertices and that solved any frame rate and memory problems I was having
I'm trying to determine why a Three.js scene does not render in Safari 11.0.2 (OSX 10.12.6).
/**
* Generate a scene object with a background color
**/
function getScene() {
var scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111);
return scene;
}
/**
* Generate the camera to be used in the scene. Camera args:
* [0] field of view: identifies the portion of the scene
* visible at any time (in degrees)
* [1] aspect ratio: identifies the aspect ratio of the
* scene in width/height
* [2] near clipping plane: objects closer than the near
* clipping plane are culled from the scene
* [3] far clipping plane: objects farther than the far
* clipping plane are culled from the scene
**/
function getCamera() {
var aspectRatio = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 10000);
camera.position.set(0,150,400);
camera.lookAt(scene.position);
return camera;
}
/**
* Generate the light to be used in the scene. Light args:
* [0]: Hexadecimal color of the light
* [1]: Numeric value of the light's strength/intensity
* [2]: The distance from the light where the intensity is 0
* #param {obj} scene: the current scene object
**/
function getLight(scene) {
var lights = [];
lights[0] = new THREE.PointLight( 0xffffff, 0.6, 0 );
lights[0].position.set( 100, 200, 100 );
scene.add( lights[0] );
var ambientLight = new THREE.AmbientLight(0x111111);
scene.add(ambientLight);
return light;
}
/**
* Generate the renderer to be used in the scene
**/
function getRenderer() {
// Create the canvas with a renderer
var renderer = new THREE.WebGLRenderer({antialias: true});
// Add support for retina displays
renderer.setPixelRatio(window.devicePixelRatio);
// Specify the size of the canvas
renderer.setSize(window.innerWidth, window.innerHeight);
// Add the canvas to the DOM
document.body.appendChild(renderer.domElement);
return renderer;
}
/**
* Generate the controls to be used in the scene
* #param {obj} camera: the three.js camera for the scene
* #param {obj} renderer: the three.js renderer for the scene
**/
function getControls(camera, renderer) {
var controls = new THREE.TrackballControls(camera, renderer.domElement);
controls.zoomSpeed = 0.4;
controls.panSpeed = 0.4;
return controls;
}
/**
* Get grass
**/
function getPlane(scene, loader) {
var texture = loader.load('grass.jpg');
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 10, 10 );
var material = new THREE.MeshBasicMaterial({
map: texture, side: THREE.DoubleSide
});
var geometry = new THREE.PlaneGeometry(1000, 1000, 10, 10);
var plane = new THREE.Mesh(geometry, material);
plane.position.y = -0.5;
plane.rotation.x = Math.PI / 2;
scene.add(plane);
return plane;
}
/**
* Add background
**/
function getBackground(scene, loader) {
var imagePrefix = '';
var directions = ['right', 'left', 'top', 'bottom', 'front', 'back'];
var imageSuffix = '.bmp';
var geometry = new THREE.BoxGeometry( 1000, 1000, 1000 );
var materialArray = [];
for (var i = 0; i < 6; i++)
materialArray.push( new THREE.MeshBasicMaterial({
map: loader.load(imagePrefix + directions[i] + imageSuffix),
side: THREE.BackSide
}));
var sky = new THREE.Mesh( geometry, materialArray );
scene.add(sky);
}
/**
* Add a character
**/
function getSphere(scene) {
var geometry = new THREE.SphereGeometry( 30, 12, 9 );
var material = new THREE.MeshPhongMaterial({
color: 0xd0901d,
emissive: 0xaf752a,
side: THREE.DoubleSide,
flatShading: true
});
var sphere = new THREE.Mesh( geometry, material );
// create a group for translations and rotations
var sphereGroup = new THREE.Group();
sphereGroup.add(sphere)
sphereGroup.position.set(0, 24, 100);
scene.add(sphereGroup);
return [sphere, sphereGroup];
}
/**
* Store all currently pressed keys
**/
function addListeners() {
window.addEventListener('keydown', function(e) {
pressed[e.key.toUpperCase()] = true;
})
window.addEventListener('keyup', function(e) {
pressed[e.key.toUpperCase()] = false;
})
}
/**
* Update the sphere's position
**/
function moveSphere() {
var delta = clock.getDelta(); // seconds
var moveDistance = 200 * delta; // 200 pixels per second
var rotateAngle = Math.PI / 2 * delta; // pi/2 radians (90 deg) per sec
// move forwards/backwards/left/right
if ( pressed['W'] ) {
sphere.rotateOnAxis(new THREE.Vector3(1,0,0), -rotateAngle)
sphereGroup.translateZ( -moveDistance );
}
if ( pressed['S'] )
sphereGroup.translateZ( moveDistance );
if ( pressed['Q'] )
sphereGroup.translateX( -moveDistance );
if ( pressed['E'] )
sphereGroup.translateX( moveDistance );
// rotate left/right/up/down
var rotation_matrix = new THREE.Matrix4().identity();
if ( pressed['A'] )
sphereGroup.rotateOnAxis(new THREE.Vector3(0,1,0), rotateAngle);
if ( pressed['D'] )
sphereGroup.rotateOnAxis(new THREE.Vector3(0,1,0), -rotateAngle);
if ( pressed['R'] )
sphereGroup.rotateOnAxis(new THREE.Vector3(1,0,0), rotateAngle);
if ( pressed['F'] )
sphereGroup.rotateOnAxis(new THREE.Vector3(1,0,0), -rotateAngle);
}
/**
* Follow the sphere
**/
function moveCamera() {
var relativeCameraOffset = new THREE.Vector3(0,50,200);
var cameraOffset = relativeCameraOffset.applyMatrix4(sphereGroup.matrixWorld);
camera.position.x = cameraOffset.x;
camera.position.y = cameraOffset.y;
camera.position.z = cameraOffset.z;
camera.lookAt(sphereGroup.position);
}
// Render loop
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
moveSphere();
moveCamera();
};
// state
var pressed = {};
var clock = new THREE.Clock();
// globals
var scene = getScene();
var camera = getCamera();
var light = getLight(scene);
var renderer = getRenderer();
// add meshes
var loader = new THREE.TextureLoader();
var floor = getPlane(scene, loader);
var background = getBackground(scene, loader);
var sphereData = getSphere(scene);
var sphere = sphereData[0];
var sphereGroup = sphereData[1];
addListeners();
render();
body { margin: 0; overflow: hidden; }
canvas { width: 100%; height: 100%; }
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js'></script>
<script src='https://threejs.org/examples/js/controls/TrackballControls.js'></script>
More generally, all of the examples at shadertoy.com [example] either do not appear or appear very faintly and almost entirely in white on Safari 11.0.2.
The same holds for the "Safari Technology Preview" even after I turn on all experimental web features, including WebGL 2.0.
I'd like to figure out how to make the scene render, but I'm more interested in learning how others attempt to debug this kind of problem. Are there tools or resources that can help one pinpoint this kind of problem (like a developer tools just for WebGL)?
This looks like a compositing bug in Safari. Hopefully Apple will fix it.
There are several workrounds. The easist seems to be to set the background color of the body or canvas to black.
/**
* Generate a scene object with a background color
**/
function getScene() {
var scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111);
return scene;
}
/**
* Generate the camera to be used in the scene. Camera args:
* [0] field of view: identifies the portion of the scene
* visible at any time (in degrees)
* [1] aspect ratio: identifies the aspect ratio of the
* scene in width/height
* [2] near clipping plane: objects closer than the near
* clipping plane are culled from the scene
* [3] far clipping plane: objects farther than the far
* clipping plane are culled from the scene
**/
function getCamera() {
var aspectRatio = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 10000);
camera.position.set(0,150,400);
camera.lookAt(scene.position);
return camera;
}
/**
* Generate the light to be used in the scene. Light args:
* [0]: Hexadecimal color of the light
* [1]: Numeric value of the light's strength/intensity
* [2]: The distance from the light where the intensity is 0
* #param {obj} scene: the current scene object
**/
function getLight(scene) {
var lights = [];
lights[0] = new THREE.PointLight( 0xffffff, 0.6, 0 );
lights[0].position.set( 100, 200, 100 );
scene.add( lights[0] );
var ambientLight = new THREE.AmbientLight(0x111111);
scene.add(ambientLight);
return light;
}
/**
* Generate the renderer to be used in the scene
**/
function getRenderer() {
// Create the canvas with a renderer
var renderer = new THREE.WebGLRenderer({antialias: true});
// Add support for retina displays
renderer.setPixelRatio(window.devicePixelRatio);
// Specify the size of the canvas
renderer.setSize(window.innerWidth, window.innerHeight);
// Add the canvas to the DOM
document.body.appendChild(renderer.domElement);
return renderer;
}
/**
* Generate the controls to be used in the scene
* #param {obj} camera: the three.js camera for the scene
* #param {obj} renderer: the three.js renderer for the scene
**/
function getControls(camera, renderer) {
var controls = new THREE.TrackballControls(camera, renderer.domElement);
controls.zoomSpeed = 0.4;
controls.panSpeed = 0.4;
return controls;
}
/**
* Get grass
**/
function getPlane(scene, loader) {
var texture = loader.load('grass.jpg');
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 10, 10 );
var material = new THREE.MeshBasicMaterial({
map: texture, side: THREE.DoubleSide
});
var geometry = new THREE.PlaneGeometry(1000, 1000, 10, 10);
var plane = new THREE.Mesh(geometry, material);
plane.position.y = -0.5;
plane.rotation.x = Math.PI / 2;
scene.add(plane);
return plane;
}
/**
* Add background
**/
function getBackground(scene, loader) {
var imagePrefix = '';
var directions = ['right', 'left', 'top', 'bottom', 'front', 'back'];
var imageSuffix = '.bmp';
var geometry = new THREE.BoxGeometry( 1000, 1000, 1000 );
var materialArray = [];
for (var i = 0; i < 6; i++)
materialArray.push( new THREE.MeshBasicMaterial({
map: loader.load(imagePrefix + directions[i] + imageSuffix),
side: THREE.BackSide
}));
var sky = new THREE.Mesh( geometry, materialArray );
scene.add(sky);
}
/**
* Add a character
**/
function getSphere(scene) {
var geometry = new THREE.SphereGeometry( 30, 12, 9 );
var material = new THREE.MeshPhongMaterial({
color: 0xd0901d,
emissive: 0xaf752a,
side: THREE.DoubleSide,
flatShading: true
});
var sphere = new THREE.Mesh( geometry, material );
// create a group for translations and rotations
var sphereGroup = new THREE.Group();
sphereGroup.add(sphere)
sphereGroup.position.set(0, 24, 100);
scene.add(sphereGroup);
return [sphere, sphereGroup];
}
/**
* Store all currently pressed keys
**/
function addListeners() {
window.addEventListener('keydown', function(e) {
pressed[e.key.toUpperCase()] = true;
})
window.addEventListener('keyup', function(e) {
pressed[e.key.toUpperCase()] = false;
})
}
/**
* Update the sphere's position
**/
function moveSphere() {
var delta = clock.getDelta(); // seconds
var moveDistance = 200 * delta; // 200 pixels per second
var rotateAngle = Math.PI / 2 * delta; // pi/2 radians (90 deg) per sec
// move forwards/backwards/left/right
if ( pressed['W'] ) {
sphere.rotateOnAxis(new THREE.Vector3(1,0,0), -rotateAngle)
sphereGroup.translateZ( -moveDistance );
}
if ( pressed['S'] )
sphereGroup.translateZ( moveDistance );
if ( pressed['Q'] )
sphereGroup.translateX( -moveDistance );
if ( pressed['E'] )
sphereGroup.translateX( moveDistance );
// rotate left/right/up/down
var rotation_matrix = new THREE.Matrix4().identity();
if ( pressed['A'] )
sphereGroup.rotateOnAxis(new THREE.Vector3(0,1,0), rotateAngle);
if ( pressed['D'] )
sphereGroup.rotateOnAxis(new THREE.Vector3(0,1,0), -rotateAngle);
if ( pressed['R'] )
sphereGroup.rotateOnAxis(new THREE.Vector3(1,0,0), rotateAngle);
if ( pressed['F'] )
sphereGroup.rotateOnAxis(new THREE.Vector3(1,0,0), -rotateAngle);
}
/**
* Follow the sphere
**/
function moveCamera() {
var relativeCameraOffset = new THREE.Vector3(0,50,200);
var cameraOffset = relativeCameraOffset.applyMatrix4(sphereGroup.matrixWorld);
camera.position.x = cameraOffset.x;
camera.position.y = cameraOffset.y;
camera.position.z = cameraOffset.z;
camera.lookAt(sphereGroup.position);
}
// Render loop
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
moveSphere();
moveCamera();
};
// state
var pressed = {};
var clock = new THREE.Clock();
// globals
var scene = getScene();
var camera = getCamera();
var light = getLight(scene);
var renderer = getRenderer();
// add meshes
var loader = new THREE.TextureLoader();
var floor = getPlane(scene, loader);
var background = getBackground(scene, loader);
var sphereData = getSphere(scene);
var sphere = sphereData[0];
var sphereGroup = sphereData[1];
addListeners();
render();
body { margin: 0; overflow: hidden; }
canvas { width: 100%; height: 100%; background: black; }
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js'></script>
<script src='https://threejs.org/examples/js/controls/TrackballControls.js'></script>
As for how to know how to find this bugs, in this particular case I don't know how I knew except experience. I know it's unfortunately common for browsers to get compositing bugs with WebGL because it's very hard to test. Most browsers test on servers without GPUs which means they don't test WebGL enough. They built their testing systems before compositing was GPU accelerated. Another reason is testing compositing is something that's browser specific so the WebGL tests can't include a test for it. It's something each browser vendor has to implement their own tests for and often their testing systems run the browsers in non-release modes or the APIs that might make it possible to test don't actually go through the same code as the code the draws to the screen .
For WebGL, you should generally get the same results across browsers and compositing issues are the most common place they get it wrong. Especially when not using the defauts. So, first I checked the if the context was set up non-default as in either alpha: false or premultipliedAlpha: false etc.. To do that I just opened Chrome's dev tools and selected the snippet context
Once I had the correct debugger context I just got the WebGL context from the first canvas
I saw alpha: false which is not the default so that was the first clue. If there was more than one canvas I would have had to use 'querySelectorAll' and try each canvas until I got the WebGL one.
Then I also saw your CSS is different than I would do it. I would have used
body { margin: 0; }
canvas { width: 100vw; height: 100vw; display: block; }
No need for overflow: hidden and clearly states what I want. I have strong opinions that the way most three.js apps size the canvas is an anti-pattern.
I saw that you set your css to make the canvas height 100% but you didn't set the body height and so if nothing else was done your canvas would have zero height. So, I set the background color of the canvas so I could see how big it was. I was assuming it was actually zero. That's when (a) I saw it was rendering and setting the background color made it appear and (b) your canvas appears because three.js is hacking in the canvas sizes based on window.innerHeight and also mucking with your css
I'm trying to load a .svg asset into my three.js scene, as a flat vector layer; I found this example with SVGLoader and SVGRenderer from another post, but I can't make it work.
The svg loaded is stuck in 2d space and not responding to camera movement, I can't access its position.
I tried to switch to WebGLRenderer, but the svg doesn’t get loaded.
The option of loading it as sprite would be good, but I would want the sprite to not face the camera and stay still in 3d space.
var svgManager = new THREE.SVGLoader();
var url = 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Europe_laea_location_map.svg';
function svg_loading_done_callback(doc) {
init();
svg(new THREE.SVGObject(doc));
ico();
animate();
};
svgManager.load(url,
svg_loading_done_callback,
function() {
console.log("Loading SVG...");
},
function() {
console.log("Error loading SVG!");
});
var AMOUNT = 100;
var container, camera, scene, renderer;
function init() {
scene = new THREE.Scene();
renderer = new THREE.SVGRenderer();
renderer.setClearColor(0x00ff00);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
var container = document.getElementById('container');
container.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 1100;
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableZoom = true;
window.addEventListener('resize', onWindowResize, false);
}
function svg(svgObject) {
svgObject.position.x = 510;
svgObject.position.y = -110;
svgObject.position.z = 0;
scene.add(svgObject);
}
function ico() {
geometry = new THREE.IcosahedronGeometry(100, 1)
material = new THREE.MeshNormalMaterial({});
ico = new THREE.Mesh(geometry, material);
ico.position.y = -300;
scene.add(ico);
ico2 = new THREE.Mesh(geometry, material);
ico2.position.y = 500;
ico2.position.x = -500;
ico2.position.z = -50;
scene.add(ico2);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
controls.update;
render();
}
function render() {
renderer.render(scene, camera);
}
body {
margin: 0;
}
canvas {
width: 100%;
height: 100%
}
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<div id="container"></div>
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/renderers/SVGRenderer.js"></script>
<script src="https://threejs.org/examples/js/renderers/Projector.js"></script>
<script src="https://threejs.org/examples/js/loaders/SVGLoader.js"></script>
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
The SVGLoader and SVGRenderer are two different things. The first loads an SVG file and converts it to three.js shapes (albeit with some limitations, i.e. can read very simple SVGs, does not render strokes but only filled objects, etc), while the latter renders three.js primitives using SVG elements instead of WebGL. In a sense, they are opposites of each other.
So, first of all, you'd need to use the WebGLRenderer for your case.
Then, you need to change the SVG loading callback. It receives an array of paths with which you can render the SVG.
See the changes in functions svg_loading_done_callback, init and svg, and run it in JSFiddle:
var svgManager = new THREE.SVGLoader();
var url = 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Europe_laea_location_map.svg';
function svg_loading_done_callback(paths) {
init();
svg(paths);
ico();
animate();
};
svgManager.load(url,
svg_loading_done_callback,
function() {
console.log("Loading SVG...");
},
function() {
console.log("Error loading SVG!");
});
var AMOUNT = 100;
var container, camera, scene, renderer;
function init() {
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x00ff00);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
var container = document.getElementById('container');
container.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 1100;
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableZoom = true;
window.addEventListener('resize', onWindowResize, false);
}
function svg(paths) {
var group = new THREE.Group();
group.position.x = 510;
group.position.y = -110;
group.position.z = 0;
for ( var i = 0; i < paths.length; i ++ ) {
var path = paths[ i ];
var material = new THREE.MeshBasicMaterial( {
color: path.color,
side: THREE.DoubleSide,
depthWrite: false
} );
var shapes = path.toShapes( true );
for ( var j = 0; j < shapes.length; j ++ ) {
var shape = shapes[ j ];
var geometry = new THREE.ShapeBufferGeometry( shape );
var mesh = new THREE.Mesh( geometry, material );
group.add( mesh );
}
}
scene.add( group );
}
function ico() {
geometry = new THREE.IcosahedronGeometry(100, 1)
material = new THREE.MeshNormalMaterial({});
ico = new THREE.Mesh(geometry, material);
ico.position.y = -300;
scene.add(ico);
ico2 = new THREE.Mesh(geometry, material);
ico2.position.y = 500;
ico2.position.x = -500;
ico2.position.z = -50;
scene.add(ico2);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
controls.update;
render();
}
function render() {
renderer.render(scene, camera);
}
PS: Check the SVG Loader to see what it's able to parse
I've been trying out Three.js today and I've had trouble getting my Mesh to change according using mesh.rotation.x += 10; for example.
The code below renders a triangle and the camera moves around onMouseMove but inside the render() function, it fails to scale or rotate the Mesh obj.
Appreciate the pointers.
<body>
<div id="container" style="border: #0f0 solid;">
</div>
<script type="text/javascript">
var mouseX = 0, mouseY = 0;
windowHalfX = window.innerWidth / 2,
windowHalfY = window.innerHeight / 2;
// get the DOM element to attach to
var container = document.getElementById("container");
// create a WebGL renderer, camera
// and a scene
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
camera = new THREE.PerspectiveCamera( 25, window.innerWidth / window.innerHeight, 50, 1e7 );
var scene = new THREE.Scene();
var obj;
var geom = new THREE.Geometry();
var stats;
init();
animate();
function init(){
// the camera starts at 0,0,0 so pull it back
camera.position.z = 400;
// start the renderer
// attach the render-supplied DOM element
container.appendChild(renderer.domElement);
// create a new mesh with triangle geometry
// create the sphere's material
var material = new THREE.MeshLambertMaterial(
{
color: 0x00FF00
});
var v1 = new THREE.Vector3(50,0,0);
var v2 = new THREE.Vector3(50,100,0);
var v3 = new THREE.Vector3(0, 50, 0);
geom.vertices.push(new THREE.Vertex(v1));
geom.vertices.push(new THREE.Vertex(v2));
geom.vertices.push(new THREE.Vertex(v3));
geom.faces.push(new THREE.Face3(0,1,2));
geom.computeFaceNormals();
obj = new THREE.Mesh(geom, material);
obj.doubleSided = true;
obj.rotation.x = 0.1;
// add the obj to the scene
scene.addObject(obj);
// create a point light
var pointLight = new THREE.PointLight( 0xFFFFFF );
// set its position
pointLight.position.x = 0;
pointLight.position.y = 0;
pointLight.position.z = 600;
//pointLight.lookAt(obj);
// add to the scene
scene.add(pointLight);
ambientLight = new THREE.AmbientLight( 0xbbbbbb );
scene.add(ambientLight);
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
stats.domElement.style.zIndex = 100;
container.appendChild( stats.domElement );
// draw!
renderer.render(scene, camera);
}
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function render() {
camera.position.x += ( mouseX - camera.position.x ) * .05;
camera.position.y += ( - mouseY + 200 - camera.position.y ) * .05;
camera.lookAt( scene.position );
var time = Date.now() * 0.0015;
for ( var i = 0; i < scene.objects.length; i ++ ) {
scene.objects[ i ].rotation.y = time * ( i % 2 ? 1 : -1 );
}
obj.rotation.x += 20;
renderer.clear();
renderer.render( scene, camera );
}
</script>
</body>
From r45 scene.addObject(obj); must be now scene.add(obj);
See Three.js commit log:
2011 10 06 - r45 - Object/Scene.add*() and Object/Scene.remove*() are now Object/Scene.add() and Object/Scene.remove()