GLB animation in three.js is too fast - animation

I have uploaded a glb file with an animation, and the animation is moving extremely fast, and I do not know why.
This is my character's animation code:
class MainChar extends THREE.Object3D {
constructor() {
super();
this.object = new THREE.Object3D();
this.object.position.set(0, 1, 50);
this.object.scale.x=20;
this.object.scale.y=20;
this.object.scale.z=20;
//load house model form blender file
/*
loader.setPath('../../models/characters/');
const gltf = loader.load('Douglas.glb', (gltf) => {
gltf.scene.traverse(c => {
c.castShadow = true;
});
this.object.add( gltf.scene);
});
*/
const loader = new THREE.GLTFLoader();
loader.setPath('../../models/characters/');
const gltf = loader.load('walk.glb', (gltf) => {
gltf.scene.traverse(c => {
c.castShadow = true;
});
this.mixer = new THREE.AnimationMixer( gltf.scene );
this.mixer.timeScale=1/5;
var action = this.mixer.clipAction( gltf.animations[ 0 ] );
action.play();
this.object.add( gltf.scene );
});
//save keyboard bindings
this.keyboard = new THREEx.KeyboardState();
/*
//creating a box (need to change it to a character with animations)
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
this.object = new THREE.Mesh( geometry, material );
this.object.scale.x=5;
this.object.scale.y=10;
this.object.scale.z=5;
//starting position for character
this.object.position.set(0, 10, 50);
*/
this.update = function (time) {
if ( this.mixer ){
this.mixer.update( time );
console.log(time);
}
//MOVEMENT OF BOX
//speed
var moveDistance = 0.5 ;
// var rotateAngle = Math.PI / 2 * 0.05;
// move forwards/backwards/left/right
if ( this.keyboard.pressed("W") ){
this.object.translateZ( -moveDistance );
}
if ( this.keyboard.pressed("S") ){
this.object.translateZ( moveDistance );
}
if ( this.keyboard.pressed("A") ){
this.object.translateX( -moveDistance );
}
if ( this.keyboard.pressed("D") ){
this.object.translateX( moveDistance );
}
// move forwards/backwards/left/right
if ( this.keyboard.pressed("up") ){
this.object.translateZ( -moveDistance );
}
if ( this.keyboard.pressed("down") ){
this.object.translateZ( moveDistance );
}
if ( this.keyboard.pressed("left") ){
this.object.translateX( -moveDistance );
}
if ( this.keyboard.pressed("right") ){
this.object.translateX( moveDistance );
}
// FOR CAMERA ROTATIONS
//this.object.rotateOnAxis( new THREE.Vector3(0,1,0), -rotateAngle);
//this.object.rotateOnAxis( new THREE.Vector3(0,1,0), rotateAngle);
//var rotation_matrix = new THREE.Matrix4().identity();
if ( this.keyboard.pressed("Z") )
{
this.object.position.set(0, 1, 50);
this.object.rotation.set(0,0,0);
}
/*
// global coordinates
if ( this.keyboard.pressed("left") )
this.object.position.x -= moveDistance;
if ( this.keyboard.pressed("right") )
this.object.position.x += moveDistance;
if ( this.keyboard.pressed("up") )
this.object.position.z -= moveDistance;
if ( this.keyboard.pressed("down") )
this.object.position.z += moveDistance;
*/
};
}
}
This is the time class that allows the game to be paused, as well as returns the delta time:
class Time {
constructor(){
this.is_pause = false;
this.accumalated_run_time = 0;
this.clock = new THREE.Clock();
this.pause_clock = new THREE.Clock();
}
getRunTime()
{
this.accumalated_run_time += this.clock.getDelta();
return this.accumalated_run_time
}
pause()
{
this.is_pause = true;
}
unpause()
{
this.is_pause = false;
this.clock.getDelta();
}
}
This is the sceneManager that calls up my character for updating animations:
class SceneManager {
constructor(canvas) {
//this entire function renders a scene where you can add as many items as you want to it (e.g. we can create the house and add as
//many items as we want to the house). It renders objects from other javascript files
//------------------------------------------------------------------------------------------------------------------------------------------
//These are supposed to act like constants. DO NOT CHANGE
this.GAME_PAUSE = "pause";
this.GAME_RUN = "run";
//------------------------------------------------------------------------------------------------------------------------------------------
//we use (this) to make variables accessible in other classes
this.time = new Time();
this.game_state = this.GAME_RUN;
this.screenDimensions = {
width: canvas.width,
height: canvas.height
};
//the essentials for rendering a scene
this.scene = this.buildScene();
this.renderer = this.buildRender(this.screenDimensions);
this.camera = this.buildCamera(this.screenDimensions);
this.managers = this.createManagers();
this.loadToScene(this.managers[0].entities);
//allow camera to orbit target (player)
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
this.controls.target.set(0, 20, 0);
this.controls.update();
}
loadToScene(entities)
{
for (let i = 0 ; i < entities.length ; i++)
{
console.log("before" +i.toString());
this.scene.add(entities[i].object);
console.log("after");
}
}
//this function creates our scene
buildScene() {
//create a new scene
const scene = new THREE.Scene();
//set the scene's background-> in this case it is our skybox
const loader = new THREE.CubeTextureLoader();
//it uses different textures per face of cube
const texture = loader.load([
'../skybox/House/posx.jpg',
'../skybox/House/negx.jpg',
'../skybox/House/posy.jpg',
'../skybox/House/negy.jpg',
'../skybox/House/posz.jpg',
'../skybox/House/negz.jpg'
]);
scene.background = texture;
//if we wanted it to be a colour, it would have been this commented code:
//scene.background = new THREE.Color("#000");
return scene;
}
//this creates a renderer for us
buildRender({ width, height }) {
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true, alpha: true
});
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
return renderer;
}
//create a camera for the screen
buildCamera({ width, height }) {
//SETTING FIELD OF VIEW, ASPECT RATIO (which should generally be width/ height), NEAR AND FAR (anything outside near/ far is clipped)
const aspectRatio = width / height;
const fieldOfView = 60;
const nearPlane = 1;
const farPlane = 1000;
//there are 2 types of cameras: orthographic and perspective- we will use perspective (more realistic)
const camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, nearPlane, farPlane);
//set where the camera is
camera.position.set(-50, 50, 70);
return camera;
}
//add subjects to the scene
createManagers() {
const managers=[new EntityManager()];
//can be altered so we can add multiple entities, and depending on which position
//it is, certain ones won't be paused, and some will be
managers[0].register(new GeneralLights());
managers[0].register(new House());
managers[0].register(new MainChar());
managers[0].register(new SceneSubject())
return managers;
}
//this updates the subject/model every frame
update() {
//won't call this loop if it's paused-> only for objects that need to be paused (managers that need to be paused)
if (this.game_state == this.GAME_RUN)
{
const runTime = this.time.getRunTime();
this.managers[0].update(runTime);
}
//update orbit controls
this.controls.update();
this.renderer.render(this.scene, this.camera);
}
//this resizes our game when screen size changed
onWindowResize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
pause(){ //when pause mode is entered. The pause menu needs to be rendered.
this.game_state = this.GAME_PAUSE;
this.time.pause();
}
unpause(){
this.game_state = this.GAME_RUN;
this.time.unpause();
}
}

I think the issue is with your AnimationMixer.update() call. If you look at the docs, update is expecting a time-delta in seconds, but it looks like you're passing the total running time. This means it should receive the time passed since the last frame. You can fix this by using clock.getDelta(); as the argument:
this.update = function (time) {
if ( this.mixer ){
const delta = this.clock.getDelta();
this.mixer.update(delta);
}
// ...
}

Related

How to remove Box3 in ThreeJS?

I'm using Box3 to detect intersections so player could collect coins. I'd like the coin to be removed after detecting that it's intersecting with player but for some reason, I can't remove its (coin's) Box3.
I've read the documentation and deduced that Box3 is connected to the item's geometry, but removing the geometry and removing the item from the scene doesn't seem to remove Box3; it just stays in place, still interacting with player.
My code fiddle: https://jsfiddle.net/ImLost/g3mu1fqe/2/
Code:
function main() {
const canvas = document.querySelector('#canva');
const renderer = new THREE.WebGLRenderer({ canvas });
renderer.setSize(window.innerWidth, window.innerHeight);
/* Camera */
const fov = 40;
const aspect = window.innerWidth / window.innerHeight;
const near = 0.1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 65, -45);
camera.up.set(0, 0, 1);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
/* Lights */
const mainLight = new THREE.DirectionalLight(0xffffff, .85);
mainLight.position.set(0, 20, 0);
scene.add(mainLight);
mainLight.castShadow = true;
mainLight.shadow.mapSize.width = 2048;
mainLight.shadow.mapSize.height = 2048;
/* Board */
const boardGeometry = new THREE.PlaneGeometry(50, 50);
const boardMaterial = new THREE.MeshToonMaterial({ color: 0xEEEEEE, side: THREE.DoubleSide });
const board = new THREE.Mesh(boardGeometry, boardMaterial);
board.rotation.x = Math.PI / 2; //The board must be placed flat on the x axis
scene.add(board);
/* Player */
const playerBox = new THREE.Box3() // Used to determine collisions
const playerGeometry = new THREE.BoxGeometry(1, 1, 1.5);
const playerMaterial = new THREE.MeshToonMaterial({ color: 0xAAAAAA });
const player = new THREE.Mesh(playerGeometry, playerMaterial);
player.geometry.computeBoundingBox(playerBox);
scene.add(player);
/* Box helper */
const playerHelper = new THREE.Box3Helper(playerBox, 0xffff00);
scene.add(playerHelper);
/* Coin */
const smallCollectibleRadius = .4
const bigCollectibleRadius = .6
const coinBox = new THREE.Box3();
const coinGeometry = new THREE.SphereGeometry(smallCollectibleRadius, 100, 100);
const coinMaterial = new THREE.MeshToonMaterial({ color: 0xffff00, emissive: 0xffff00 });
const coin = new THREE.Mesh(coinGeometry, coinMaterial);
coin.position.set(0, 0, 3)
scene.add(coin);
coin.geometry.computeBoundingBox(coinBox);
const coinHelper = new THREE.Box3Helper(coinBox, 0xffff00);
scene.add(coinHelper);
function checkCollision(box) {
var collision = playerBox.intersectsBox(box);
if (collision == true) {
return true
}
}
document.addEventListener("keypress", function (event) {
if (checkCollision(coinBox)) {
console.log("Yummy coin!")
coinGeometry.dispose()
coin.geometry.dispose()
scene.remove(coin)
}
});
function render(time) {
time *= 0.001;
const speed = 0.0005
const rotSpeed = 0.00005
const dir = new THREE.Vector3();
playerBox.copy(player.geometry.boundingBox).applyMatrix4(player.matrixWorld);
coinBox.copy(coin.geometry.boundingBox).applyMatrix4(coin.matrixWorld);
document.addEventListener("keypress", function (event) {
if (event.keyCode == 119) {
player.getWorldDirection(dir);
player.position.addScaledVector(dir, speed);
}
if (event.keyCode == 115) {
player.getWorldDirection(dir);
player.position.addScaledVector(dir, -speed);
}
if (event.keyCode == 97) {
player.rotation.y += rotSpeed
}
if (event.keyCode == 100) {
player.rotation.y -= rotSpeed
}
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
coinGeometry.dispose()
coin.geometry.dispose()
scene.remove(coin)
The code above does not invalidate your coin object, nor its .geometry property--it simply discards the buffer and attribute data from memory. Other properties, like boundingBox still exist. Otherwise, you would be getting errors when you copy the bounding box into coinBox after the coin has been "consumed."
Now, you can invalidate the whole coin by setting it to null:
scene.remove(coin)
coin = null
However, JavaScript is garbage-collected, and you may still be able to access the object before it is actually removed from the heap. I would recommend a simple logical workaround:
scene.remove(coin)
coin.userData.consumed = true
coin = null
Then in your renderer and key event listener, add checks for the new property:
document.addEventListener("keypress", function (event) {
if (coin !== null && !('consumed' in coin.userData) && checkCollision(coinBox)) {
playerBox.copy(player.geometry.boundingBox).applyMatrix4(player.matrixWorld);
if( coin !== null && !('consumed' in coin.userData) ){
coinBox.copy(coin.geometry.boundingBox).applyMatrix4(coin.matrixWorld);
}

THREE.js pointerlock controls not moving camera around on mouse movement

I tried to follow the source code at https://threejs.org/examples/misc_controls_pointerlock.html without the divs, but it didn't work. I then tried following the code here https://sbcode.net/threejs/pointerlock-controls/ but it also did not work.
I simply want to be able to look around with the pointerlock controls, for first person view. I will be able to sort out the movement of the controls afterwards.
Currently I have a model (mainChar), where the camera is attached to him. I would like the pointerlock controls to be attached to his position somehow.
This is my code that doesn't work:
//IMPORT STATEMENTS
import { EntityManager } from './EntityManager.js';
import { LightingManager } from './LightingManager.js';
import { Time } from '../Time.js';
import { PauseMenu } from '../SceneSubjects/Menu/PauseMenu.js';
import { keyboardManager } from './KeyboardManager.js';
//lights
import { GeneralLights } from '../SceneSubjects/lighting/GeneralLights.js';
import { CeilingLight } from '../SceneSubjects/lighting/CeilingLight.js';
import { CeilingLightObj } from '../SceneSubjects/objects/CeilingLightObj.js';
//objects
import { House } from '../SceneSubjects/House.js';
import { SceneSubject } from '../SceneSubjects/objects/SceneSubject.js';
import { TestBlock } from '../SceneSubjects/characters/TestBlock.js';
import { Door } from '../SceneSubjects/objects/Door.js';
import { MainChar } from '../SceneSubjects/characters/MainChar.js';
//other
import { PointerLockControls } from '../../jsm/PointerLockControls.js';
import { OrbitControls } from '../../jsm/OrbitControls.js';
import * as THREE from '../../../jsm/three.module.js';
//==================================================================================================
//Global Variables
//lights
var generalLights = new GeneralLights();
//ceiling lights
var bedroomLightObj = new CeilingLightObj();
var kitchenLightObj = new CeilingLightObj();
var studyLightObj = new CeilingLightObj();
var hallwayLightObj1 = new CeilingLightObj();
var hallwayLightObj2 = new CeilingLightObj();
var bathroomLightObj = new CeilingLightObj();
var loungeLightObj = new CeilingLightObj();
var bedroomLight = new CeilingLight();
var kitchenLight = new CeilingLight();
var studyLight = new CeilingLight();
var hallwayLight1 = new CeilingLight();
var bathroomLight = new CeilingLight();
var hallwayLight2 = new CeilingLight();
var loungeLight = new CeilingLight();
//objects
var house = new House();
var sceneSubject = new SceneSubject();
var testBlock = new TestBlock();
var testdoor = new Door();
export var mainChar = new MainChar(testBlock);
export class SceneManager {
constructor(canvas) {
//this entire function renders a scene where you can add as many items as you want to it (e.g. we can create the house and add as
//many items as we want to the house). It renders objects from other javascript files
//------------------------------------------------------------------------------------------------------------------------------------------
//These are supposed to act like constants. DO NOT CHANGE
this.GAME_PAUSE = "pause";
this.GAME_RUN = "run";
this.GAME_START = "start";
//------------------------------------------------------------------------------------------------------------------------------------------
//we use (this) to make variables accessible in other classes
this.time = new Time();
this.objPauseMenu;
this.game_state = this.GAME_RUN;
this.width_screen = canvas.width;
this.height_screen = canvas.height;
this.screenDimensions = {
width: canvas.width,
height: canvas.height
};
//the essentials for rendering a scene
this.scene = this.buildScene();
this.renderer = this.buildRender(this.screenDimensions);
this.camera = this.buildCamera(this.screenDimensions);
//comment this out
// this.controls = new OrbitControls(this.camera, this.renderer.domElement);
//initialise pointerlock controls
this.pointerLockControls = new PointerLockControls(this.camera, this.renderer.domElement);
this.pointerLockControls.unlock();
//this.scene.add(this.pointerLockControls.getObject());
//====================
//adjust the ceiling light properties in the house
this.setCeilingLightProperties();
this.managers = this.createManagers();
//load things to scene
this.loadToScene(this.managers[0].lights);
this.loadToScene(this.managers[1].entities);
//---------------------------------------------------------------------------------------------------------------------------------
// Ok, now we have the cube. Next we'll create the hud. For that we'll
// need a separate scene which we'll render on top of our 3D scene. We'll
// use a dynamic texture to render the HUD.
// We will use 2D canvas element to render our HUD.
//---------------------------------------------------------------------------------------------------------------------------------
}
loadToScene(entities) {
for (let i = 0; i < entities.length; i++) {
this.scene.add(entities[i].object);
}
}
//this function creates our scene
buildScene() {
//create a new scene
const scene = new THREE.Scene();
//set the scene's background-> in this case it is our skybox
const loader = new THREE.CubeTextureLoader();
//it uses different textures per face of cube
const texture = loader.load([
'../skybox/House/posx.jpg',
'../skybox/House/negx.jpg',
'../skybox/House/posy.jpg',
'../skybox/House/negy.jpg',
'../skybox/House/posz.jpg',
'../skybox/House/negz.jpg'
]);
scene.background = texture;
//if we wanted it to be a colour, it would have been this commented code:
//scene.background = new THREE.Color("#000");
return scene;
}
//this creates a renderer for us
buildRender({ width, height }) {
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true, alpha: true
});
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
return renderer;
}
//create a camera for the screen
buildCamera({ width, height }) {
//SETTING FIELD OF VIEW, ASPECT RATIO (which should generally be width/ height), NEAR AND FAR (anything outside near/ far is clipped)
const aspectRatio = width / height;
const fieldOfView = 60;
const nearPlane = 1;
const farPlane = 1000;
//there are 2 types of cameras: orthographic and perspective- we will use perspective (more realistic)
const camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, nearPlane, farPlane);
//Set camera initial position to main character
let pos = mainChar.returnWorldPosition();
camera.position.set(pos.x, pos.y + 10, pos.z - 10);
return camera;
}
setCeilingLightProperties() {
//set their light positions
bedroomLightObj.setLightPosition(0, 21, 50);
bedroomLight.setLightPosition(0, 16, 50);
loungeLightObj.setLightPosition(-45, 21, -60);
loungeLight.setLightPosition(-45, 16, -60);
studyLightObj.setLightPosition(35, 21, -50);
studyLight.setLightPosition(35, 16, -50);
kitchenLight.setLightPosition(-45, 16, 5);
kitchenLightObj.setLightPosition(-45, 21, 5);
bathroomLight.setLightPosition(45, 16, 15);
bathroomLightObj.setLightPosition(45, 21, 15);
hallwayLightObj1.setLightPosition(0, 21, -60);
hallwayLight1.setLightPosition(0, 16, -60);
hallwayLightObj2.setLightPosition(0, 21, 0);
hallwayLight2.setLightPosition(0, 16, 0);
}
//add subjects to the scene
createManagers() {
const managers = [new LightingManager(), new EntityManager()];
//can be altered so we can add multiple entities, and depending on which position
//it is, certain ones won't be paused, and some will be
//Note that these variables are declared globally before the class definition
/*This is so that we can use any of these object's methods or values later somewhere else*/
//lights
// managers[0].register(generalLights);
managers[0].register(bedroomLight);
managers[0].register(loungeLight);
managers[0].register(studyLight);
managers[0].register(hallwayLight1);
managers[0].register(hallwayLight2);
managers[0].register(kitchenLight);
managers[0].register(bathroomLight);
//entities
managers[1].register(loungeLightObj);
managers[1].register(studyLightObj);
managers[1].register(kitchenLightObj);
managers[1].register(bathroomLightObj);
managers[1].register(bedroomLightObj);
managers[1].register(hallwayLightObj1);
managers[1].register(hallwayLightObj2);
managers[1].register(house);
testdoor.setPosition(0, -0.5, 33);
//testdoor.setRotation(-Math.PI/2);
managers[1].register(testdoor);
managers[1].register(mainChar);
managers[1].register(sceneSubject);
managers[1].register(testBlock);
return managers;
}
updateCameraPosition() {
//Match camera position and direction to the character's position and direction
let pos = mainChar.returnWorldPosition();
let dir = mainChar.returnObjectDirection();
//Set y to 10 to move camera closer to head-height
//UNCOMMENT FOR 3RD PERSON
// this.camera.position.set(pos.x, 10 +10, pos.z + 20);
// this.camera.rotation.set(dir.x - 0.5, dir.y, dir.z);
//UNCOMMENT FOR FIRST PERSON
this.camera.position.set(pos.x, 15, pos.z - 5);
this.camera.rotation.set(dir.x, dir.y, dir.z);
}
//this updates the subject/model every frame
update() {
//won't call this loop if it's paused-> only for objects that need to be paused (managers that need to be paused)
if (this.game_state == this.GAME_RUN) {
//TO EXPERIMENT WITH FOR LOOKING AROUND!
// this.camera.position.x += ( keyboardManager.getMouseX() - this.camera.position.x ) ;
// this.camera.position.y += ( - keyboardManager.getMouseY() - this.camera.position.y );
// this.camera.lookAt( this.scene.position );
const runTime = this.time.getRunTime();
this.managers[0].update(runTime);
this.managers[1].update(runTime);
//update orbit controls
//comment out this.controls.update()
//this.controls.update();
this.renderer.render(this.scene, this.camera);
}
else {
//comment out
// this.controls.update();
this.renderer.autoClear = true;
//render scene1
this.renderer.render(this.scene, this.camera);
//prevent canvas from being erased with next .render call
this.renderer.autoClear = false;
//just render scene2 on top of scene1
this.renderer.render(this.objPauseMenu.scene, this.objPauseMenu.camera);
// renderer.autoClear = true;
}
//update orbit controls
//comment out
// this.controls.update();
//uncomment this
this.updateCameraPosition();
}
//this resizes our game when screen size changed
onWindowResize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
pause() { //when pause mode is entered. The pause menu needs to be rendered.
this.game_state = this.GAME_PAUSE;
this.time.pause();
//comment out
// this.controls.enabled = false; // stop orbit controls from responding to use input
this.objPauseMenu = new PauseMenu(this.width_screen, this.height_screen);
}
unpause() {
this.game_state = this.GAME_RUN;
this.time.unpause();
//comment out
// this.controls.enabled = true; // start orbit controls tp respond to input
}
}
pointerLockControls.unlock() deactivates the controls
this should work
this.pointerLockControls.lock()

Draw a 2D line with width in three.js

I'm looking to draw a continuous line with a given thickness showing only the edges using three.js. I have achieved it. I'm trying to add thickness to the line but it is not getting reflected in the scene due to some angle in three.js. Can anyone help me out with the issue.
Here's the fiddle https://jsfiddle.net/16vhjm0y/1/
var renderer, scene, camera;
var line;
var count = 0;
var mouse = new THREE.Vector3();
var mesh3D;
var maxPoint = 6;
var height = window.innerHeight * .99;
var plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); // facing us for mouse intersection
var raycaster = new THREE.Raycaster();
var point3ds = [];
var usePerspectiveCamera = false; // toggles back and forth
var perspOrbit;
var perspCam;
var orthoOrbit;
var orthoCam;
var labelRenderer, labelAjay;
var testBoolean = false;
var mouseDownBoolean = false;
var distanceData, showDistanceData;
var ajay;
var arrAjay = [];
var arrAjayFinal = [];
var mouseUpBoolean = false;
init();
animate();
function init() {
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, height);
document.body.appendChild(renderer.domElement);
// scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
// camera perspective
perspCam = new THREE.PerspectiveCamera(45, window.innerWidth / height, 1, 10000);
perspCam.position.set(0, 0, 200);
// camera ortho
var width = window.innerWidth;
//var height = window.innerHeight;
orthoCam = new THREE.OrthographicCamera(-width / 2, width / 2, height / 2, -height / 2, 0, 1200);
// assign cam
camera = perspCam;
someMaterial = new THREE.MeshBasicMaterial({ color: 0xA9A9A9, side: THREE.DoubleSide, transparent: true, opacity: 0.3 });
// grid
var grid = new THREE.GridHelper(1024, 56);
grid.rotateX(Math.PI / 2);
// scene.add(grid);
// geometry
var geometry = new THREE.BufferGeometry();
var MAX_POINTS = 500;
positions = new Float32Array(MAX_POINTS * 3);
geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
// material
var material = new THREE.LineBasicMaterial({
color: 0xff0000,
linewidth: 10
});
// line
line = new THREE.Line(geometry, material);
// line.position.z = 20;
scene.add(line);
// var geometry = new THREE.BoxBufferGeometry( 10, 2, 20 );
// var edgesPavement = new THREE.EdgesGeometry( geomPavement );
// var lineGeometry = new THREE.LineSegmentsGeometry().setPositions( edgesPavement.attributes.position.array );
// var lineMaterial = new THREE.LineMaterial( { color: 0xff0000, linewidth: 10 } );
// lineMaterial.resolution.set( window.innerWidth, window.innerHeight ); // important, for now...
// var line = new THREE.LineSegments2( lineGeometry, lineMaterial );
// scene.add( line );
document.addEventListener("mousemove", onMouseMove, false);
document.addEventListener('mousedown', onMouseDown, false);
document.addEventListener('mouseup', onMouseUp, false);
createUI();
labelRenderer = new THREE.CSS2DRenderer();
ajay = document.createElement('div');
ajay.className = 'ajay';
ajay.style.color = "black";
ajayInsert = document.createElement('div');
ajayInsert.className = 'ajay';
ajayInsert.style.color = "black";
// ajay.style.color = "black";
// console.log(ajay)
labelAjay = new THREE.CSS2DObject(ajay);
labelAjayFinal = new THREE.CSS2DObject(ajayInsert);
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0';
labelRenderer.domElement.style.pointerEvents = 'none';
ajay.style.display = "none";
ajayInsert.style.display = "none";
}
// update line
function updateLine() {
positions[count * 3 - 3] = mouse.x;
positions[count * 3 - 2] = mouse.y;
positions[count * 3 - 1] = mouse.z;
line.geometry.attributes.position.needsUpdate = true;
}
// mouse move handler
function onMouseMove(event) {
var rect = renderer.domElement.getBoundingClientRect();
mouse.x = (event.clientX - rect.left) / (rect.right - rect.left) * 2 - 1;
mouse.y = - ((event.clientY - rect.top) / (rect.bottom - rect.top)) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
mouse = raycaster.ray.intersectPlane(plane, mouse);
if (count !== 0 && count < maxPoint) {
updateLine();
}
testBoolean = true;
if (testBoolean == true) {
// scene.remove(labelAjay);
var geometry = line.geometry;
geometry.computeBoundingBox();
center = geometry.boundingBox.getCenter();
// line.localToWorld(center);
// console.log(center);
if (mouseDownBoolean == true) {
labelAjay.position.set(mouse.x, mouse.y, mouse.z);
// console.log(line.position)
scene.add(labelAjay);
document.body.appendChild(labelRenderer.domElement);
// console.log(positions);
distanceData = point3ds[0].distanceTo(new THREE.Vector3(mouse.x, mouse.y, mouse.z));
showDistanceData = Math.round(distanceData * 1000);
// console.log(point3ds[0]);
// console.log(point3ds[1]);
// console.log(distanceData);
// console.log(showDistanceData)
ajay.textContent = showDistanceData + ' mm';
// console.log(labelRenderer)
}
// console.log(labelRenderer.domElement)
// document.getElementsByClassName("ajay").remove();
// document.getElementsByClassName("ajay").outerHTML = "";
}
}
// add point
function addPoint(event) {
if (count < maxPoint) {
console.log("point nr " + count + ": " + mouse.x + " " + mouse.y + " " + mouse.z);
positions[count * 3 + 0] = mouse.x;
positions[count * 3 + 1] = mouse.y;
positions[count * 3 + 2] = mouse.z
count++;
line.geometry.setDrawRange(0, count);
updateLine();
point3ds.push(new THREE.Vector3(mouse.x, mouse.y, mouse.z));
} else {
console.log('max points reached: ' + maxPoint);
}
}
function getPointInBetweenByLen(pointA, pointB, length) {
var dir = pointB.clone().sub(pointA).normalize().multiplyScalar(length);
return pointA.clone().add(dir);
}
// mouse down handler
function onMouseDown(evt) {
mouseDownBoolean = true;
// force add an extra point on first click so buffer line can display
// buffer geometry requires two points to display, so first click should add two points
if (count === 0) {
addPoint();
}
if (count < maxPoint) {
addPoint();
}
}
function onMouseUp(event){
mouseUpBoolean = true;
if(mouseUpBoolean == true){
// showDistanceData = Math.round(distanceData * 1000);
arrAjay.push(showDistanceData);
console.log(arrAjay);
arrAjayFinal = arrAjay.splice(-1)[0];
var geometry = line.geometry;
geometry.computeBoundingBox();
center = geometry.boundingBox.getCenter();
if (mouseDownBoolean == true) {
labelAjayFinal.position.set(center.x, center.y, center.z);
scene.add(labelAjayFinal);
document.body.appendChild(labelRenderer.domElement);
// distanceData = point3ds[0].distanceTo(new THREE.Vector3(mouse.x, mouse.y, mouse.z));
// showDistanceData = Math.round(distanceData * 1000);
console.log('arrAjayFinal', arrAjayFinal);
ajayInsert.textContent = arrAjayFinal;
}
}
}
// render
function render() {
renderer.render(scene, camera);
labelRenderer.render(scene, camera);
}
// animate
function animate() {
requestAnimationFrame(animate);
render();
}
// loop through all the segments and create their 3D
function create3D() {
if (!mesh3D && point3ds && point3ds.length) {
console.log('creating 3D');
mesh3D = new THREE.Mesh(); // metpy mesh but is the root mesh for all 3D
scene.add(mesh3D);
// prepare create segments from point3ds - every two points create a segement
var index = 1;
var segmentHeight = 56;
point3ds.forEach(point3d => {
if (index < point3ds.length) {
var seg = new Segment(point3d, point3ds[index], someMaterial, segmentHeight);
mesh3D.add(seg.mesh3D);
index++;
}
});
}
}
function createUI() {
// create3D
var btn = document.createElement('button');
document.body.appendChild(btn);
btn.innerHTML = 'Create3D';
btn.addEventListener('mousedown', () => {
create3D();
// add orbiting controls to both cameras
var controls;
if (!perspOrbit) {
perspOrbit = new THREE.OrbitControls(perspCam, renderer.domElement);
perspOrbit.screenSpacePanning = true;
// raotation is enabled once create3D is pressed
setToFullOrbit(perspOrbit);
perspOrbit.enabled = true; // set to true by default
}
// add orbit to orthocam
if (!orthoOrbit) {
orthoOrbit = new THREE.OrbitControls(orthoCam, renderer.domElement);
orthoOrbit.screenSpacePanning = true;
orthoOrbit.enabled = false; // set to false by default
//orthoOrbit.enableDamping = true;
//orthoOrbit.dampingFactor = .15;
}
});
}
function switchCam() {
usePerspectiveCamera = !usePerspectiveCamera;
if (usePerspectiveCamera) {
if (perspCam) {
camera = perspCam;
perspOrbit.enabled = true;
orthoOrbit.enabled = false;
} else {
throw new Error('Switch to perspective cam failed, perspective cam is null');
}
} else {
if (orthoCam) {
camera = orthoCam;
orthoOrbit.enabled = true;
perspOrbit.enabled = false;
} else {
throw new Error('Switch to ortho cam failed, orthoCam is null');
}
}
}
function rotateCam90() {
if (camera instanceof THREE.OrthographicCamera) {
orthoOrbit.update();
camera.applyMatrix(new THREE.Matrix4().makeRotationZ(Math.PI / 2));
}
}
function reset() {
scene.remove(mesh3D);
mesh3D = null;
for (var i = 0; i < 3 * 8; i++) {
positions[i] = 0;
}
count = 0;
line.geometry.setDrawRange(0, count);
updateLine();
point3ds = [];
}
function setToFullOrbit(orbitControl) {
// how far you can orbit vertically
orbitControl.minPolarAngle = 0;
orbitControl.maxPolarAngle = Math.PI;
// How far you can dolly in and out ( PerspectiveCamera only )
orbitControl.minDistance = 0;
orbitControl.maxDistance = Infinity;
orbitControl.enableZoom = true; // Set to false to disable zooming
orbitControl.zoomSpeed = 1.0;
orbitControl.enableRotate = true;
// allow keyboard arrows
orbitControl.enableKeys = true;
// Set to false to disable panning (ie vertical and horizontal translations)
orbitControl.enablePan = true;
}
// each segment knows how to create its 3D
class Segment {
constructor(start, end, material, height) {
this.start = start;
this.end = end;
this.height = height; // height of the segment's 3D
this.material = material;
this.mesh3D = null;
this.create3D();
}
create3D() {
if (this.start && this.end) {
//create the shape geometry
var distStartToEnd = this.start.distanceTo(this.end);
var vec2s = [
new THREE.Vector2(),
new THREE.Vector2(0, this.height),
new THREE.Vector2(distStartToEnd, this.height),
new THREE.Vector2(distStartToEnd, 0)
];
console.log('vec2s', vec2s);
var shape = new THREE.Shape(vec2s);
var geo = new THREE.BoxGeometry(5, 5, 5);
// console.log('shape', shape);
var geo = new THREE.ShapeGeometry(shape);
geo.applyMatrix(new THREE.Matrix4().makeRotationX(THREE.Math.degToRad(90)));
this.mesh3D = new THREE.Mesh(geo, this.material);
this.alignRotation();
this.alignPosition();
// the mesh3D should be added to the scene outside of this class
}
}
alignRotation() {
var p1 = this.start.clone();
var p2 = this.end.clone();
var direction = new THREE.Vector3();
direction.subVectors(p2, p1);
direction.normalize();
this.mesh3D.quaternion.setFromUnitVectors(new THREE.Vector3(1, 0, 0), direction);
}
alignPosition() {
if (this.mesh3D) {
this.mesh3D.position.copy(this.start);
} else {
throw new Error('mesh3D null');
}
}
}
The linewidth parameter relies on native WebGL support for drawing line thickness, but its performance is very spotty across browsers & operating systems. I think Windows doesn't support it, but MacOS does, so it shouldn't be relied upon. See this discussion on the Three.js Github for several bug reports.
As a workaround, they've created LineGeometry, which sort of re-builds a line with geometry to allow for thickness. See this example for how to use it. It even allows for dashed lines. After importing the module, you can implement it with:
const geometry = new LineGeometry();
geometry.setPositions( positions );
geometry.setColors( colors );
matLine = new LineMaterial( {
color: 0xffffff,
linewidth: 5, // in pixels
vertexColors: true,
dashed: false
} );
line = new Line2( geometry, matLine );
line.computeLineDistances();
scene.add( line );

MTLLoader breaks other 3js code and isn't loading texture right

I am having trouble getting the MTLLoader to work correctly. I have already been able to use the OBJLoader by itself to load the 3d object and I have a camera that works properly too in my scene. When I try and use the MTLLoader with the OBJLoader the object loads but it breaks my other three.js code. I get these errors:
three.js:24415 Uncaught TypeError: Cannot set property 'value' of undefined
at initMaterial (three.js:24415)
at setProgram (three.js:24493)
at WebGLRenderer.renderBufferDirect (three.js:23552)
at renderObject (three.js:24269)
at renderObjects (three.js:24239)
at WebGLRenderer.render (three.js:24037)
at render (demo2.html:480)
The object loads and it looks like some textures load but the textures don't look right, the camera breaks. I have been having trouble with this and could really use some guidance.
Here is my MTLLoader code by itself
var mesh = null;
var mtlLoader = new THREE.MTLLoader();
mtlLoader.load( 'dapHouseGood5.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.load( 'dapHouseGood5.obj', function ( object ) {
mesh = object;
scene.add( mesh );
} );
Here is the rest of my three.js code for reference
<script>
/* global THREE */
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const renderer2 = new THREE.WebGLRenderer({canvas});
var kitchenCameraActive = false;
document.getElementById("roomSelect").addEventListener("change", changeIt);
function changeIt(e) {
document.getElementById(e.target.value).click();
console.log(e);
}
var fov = 45;
var aspect = 2; // the canvas default
var near = 0.1;
var far = 100;
var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(-97.570, 5.878, -5.289);
camera.rotation.set(0,0,0);
const controls = new THREE.OrbitControls(camera, canvas);
controls.target.set(0, 5, 0);
controls.update();
document.getElementById("kitchen").addEventListener("click", changeCamera);
document.getElementById("bathroom").addEventListener("click", changeCamera);
document.getElementById("deck").addEventListener("click", changeCamera);
document.getElementById("livingRoom").addEventListener("click", changeCamera);
document.getElementById("bedRoom").addEventListener("click", changeCamera);
document.getElementById("walkway").addEventListener("click", changeCamera);
document.getElementById("sideHouse").addEventListener("click", changeCamera);
document.getElementById("frontPorch").addEventListener("click", changeCamera);
document.getElementById("garageDoor").addEventListener("click", changeCamera);
document.getElementById("insideGarage").addEventListener("click", changeCamera);
function changeCamera(e) {
camera.rotation.set(e.toElement.attributes[5].nodeValue,
e.toElement.attributes[6].nodeValue, e.toElement.attributes[7].nodeValue);
camera.fov = e.toElement.attributes[4].nodeValue;
camera.position.set(e.toElement.attributes[1].nodeValue,
e.toElement.attributes[2].nodeValue, e.toElement.attributes[3].nodeValue);
camera.updateProjectionMatrix();
if (e.target.id == "walkway" || e.target.id == "frontPorch" || e.target.id ==
"garageDoor" || e.target.id == "insideGarage")
{
controls.target.set(0, 5, 0);
controls.update();
}
if(e.target.id == "kitchen"){
controls.target.set(7, 6, 7);
}
if(e.target.id == "bathroom"){
controls.target.set(-9,15,-7);
}
if(e.target.id == "deck"){
controls.target.set(31, 7, 1);
}
if(e.target.id == "livingRoom"){
controls.target.set(-12.5, 1.5, -18.5);
}
if(e.target.id == "bedRoom"){
controls.target.set(-15.7, 14, -21);
}
if(e.target.id == "insideGarage"){
controls.target.set(24.405, 6.733, -6.425);
}
controls.update();
console.log(e);
}
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
{
const planeSize = 40;
}
{
const skyColor = 0xB1E1FF; // light blue
const groundColor = 0xB97A20; // brownish orange
const intensity = 1;
const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
scene.add(light);
}
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(5, 10, 2);
scene.add(light);
scene.add(light.target);
}
var mesh = null;
var mtlLoader = new THREE.MTLLoader();
mtlLoader.load( 'dapHouseGood5.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.load( 'dapHouseGood5.obj', function ( object ) {
mesh = object;
scene.add( mesh );
} );
} );
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function onPositionChange(o) {
console.log("position changed in object");
console.log(o);
console.log('camera_default: '+camera.position.x+', '+camera.position.y+',
'+camera.position.z);
console.log('camera_default: '+camera.rotation.x+', '+camera.rotation.y+',
'+camera.rotation.z);
console.log(camera.fov);
console.log('quaternion_default: '+camera.quaternion.x+', '+
camera.quaternion.y+', '+camera.quaternion.z+', '+camera.quaternion.w);
}
controls.addEventListener('change', onPositionChange);
var mouse = new THREE.Vector2();
var raycaster, mouse = { x : 0, y : 0};
init();
function init () {
//Usual setup code here.
raycaster = new THREE.Raycaster();
renderer.domElement.addEventListener( 'click', raycast, false );
}
function raycast ( e ) {
//1. sets the mouse position with a coordinate system where the center
// of the screen is the origin
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
//2. set the picking ray from the camera position and mouse coordinates
raycaster.setFromCamera( mouse, camera );
//var mouse3D = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, -(
event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
//raycaster.setFromCamera( mouse3D, camera );
//3. compute intersections
var intersects = raycaster.intersectObjects( scene.children, true );
for ( var i = 0; i < intersects.length; i++ ) {
console.log( intersects[ i ].object.name );
}
}
}
main();
</script>

THREE.JS Update 64 - SpriteMaterial - definition changed

I have a current application that runs on Three.js V60. I want to migrate it to V64 but I have issue with one of functionnality which is a mouse tooltip. It follows the example from http://stemkoski.github.io/Three.js/Mouse-Tooltip.html.
In V64, we don't have useScreenCoordinates, sizeAttenuation and alignment properties, so i have strange behaviour with the tooltip when I removed this parameters. The behaviour I have is that mousetooltip is fixed on scene. Can someone help me ?
Below is a testing code I have made :
<pre><code>
// standard global variables
var container, scene, camera, renderer, controls, stats;
// custom global variables
var cube;
var projector, mouse = { x: 0, y: 0 }, INTERSECTED;
var ballSprite;
init();
animate();
// FUNCTIONS
function init()
{
// SCENE
scene = new THREE.Scene();
// CAMERA
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
scene.add(camera);
camera.position.set(0,150,400);
camera.lookAt(scene.position);
// RENDERER
renderer = new THREE.WebGLRenderer( {antialias:true} );
renderer.setClearColor(0xFFFFFF, 1.0);
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
container = document.getElementById( 'ThreeJS' );
container.appendChild( renderer.domElement );
// LIGHT
var light = new THREE.PointLight(0xffffff);
light.position.set(0,250,0);
scene.add(light);
////////////
// CUSTOM //
////////////
var cubeGeometry = new THREE.CubeGeometry( 50, 50, 50 );
var cubeMaterial = new THREE.MeshBasicMaterial( { color: 0x000088 } );
cube = new THREE.Mesh( cubeGeometry, cubeMaterial );
cube.position.set(0,26,0);
scene.add(cube);
// initialize object to perform world/screen calculations
projector = new THREE.Projector();
// when the mouse moves, call the given function
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
var ballTexture = THREE.ImageUtils.loadTexture( 'http://stemkoski.github.io/Three.js/images/redball.png' );
var ballMaterial = new THREE.SpriteMaterial( { map: ballTexture} );
ballSprite = new THREE.Sprite( new THREE.SpriteMaterial(ballMaterial) );
ballSprite.scale.set( 32, 32, 1.0 );
ballSprite.position.set( 50, 50, 0 );
scene.add( ballSprite );
}
function onDocumentMouseMove( event )
{
// the following line would stop any other event handler from firing
// (such as the mouse's TrackballControls)
// event.preventDefault();
// update sprite position
ballSprite.position.set( event.clientX, event.clientY, 0 );
}
function animate()
{
requestAnimationFrame( animate );
render();
update();
}
function update()
{
}
function render()
{
renderer.clear();
renderer.render( scene, camera );
}
</code></pre>
Update :
I have looked at the webgl_sprites.html example and have adapted my using ortho cam. It works partially : I have now the tooltip that is display orthogonally but it doesn't follow the mouse (while it works with previous V60).
While the example uses a picture, I use a canvas2D to draw some text and lines, convert it as a texture and apply it to a spriteMaterial and create a mesh from it.
When I drag the mouse, the mesh coordonates changed but on the screen, it stays static.
Can someone helps me?
Here is the code :
<pre><code>
THREE.MouseTooltip = function (o) {
Object.call(this);
var defaults = { // default options
ResourcesPath: "", // Location of ressoruce file
ImagesPath: "",
Scene: null,
Container: null
};
this.options = $.extend(defaults, o); // merge defaults and options object
if (this.options.Scene == null || this.options.Container == null) {
throw "Error : MouseTooltip scene and container inputs must be specified";
return;
}
this.canvas = null;
this.context = null;
this.texture = null;
this.material = null;
this.mesh = null;
this.width = 0
this.updateDisplay = false;
this.init(this.options.Scene);
};
THREE.MouseTooltip.prototype = Object.create(Object.prototype);
THREE.MouseTooltip.prototype.init = function (scene) {
this.canvas = document.createElement('canvas');
this.canvas.width = this.options.Container.offsetWidth;
this.canvas.height = this.options.Container.offsetHeight;
this.context = this.canvas.getContext('2d');
this.context.font = "20px Arial";
this.context.fillStyle = "rgba(0,0,0,0.95)";
this.context.fillText('', 0, 20);
this.width = 20;
this.texture = new THREE.Texture(this.canvas);
this.texture.needsUpdate = true;
this.material = new THREE.SpriteMaterial({ map: this.texture/*, useScreenCoordinates: true, alignment: THREE.SpriteAlignment.topLeft */});
this.mesh = new THREE.Sprite(this.material);
this.mesh.name = "tooltip";
this.mesh.scale.set(this.canvas.width/1.5, this.canvas.height/1.5, 1.0);
this.mesh.material.depthTest = false;
this.mesh.material.transparent = false;
this.mesh.matrixAutoUpdate = false;
this.mesh.visible = false;
this.mesh.userData = "";
scene.add(this.mesh);
};
THREE.MouseTooltip.prototype.setContent = function (message) {
if (message == this.mesh.userData) {
return;
}
var metrics = this.context.measureText(message);
var lineHeight = 20;
this.width = metrics.width + 8;
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.context.fillStyle = "rgba(0,0,0,1)"; // black border
this.context.beginPath();
this.context.moveTo(0, (lineHeight + 8) / 2);
this.context.lineTo(10, (lineHeight + 8) / 2 + 10);
this.context.lineTo(10, (lineHeight + 8) / 2 - 10);
this.context.lineTo(0, (lineHeight + 8) / 2);
this.context.fill();
this.context.closePath();
this.context.fillRect(12, 0, this.width, lineHeight + 8);
this.context.fillStyle = "rgba(255,255,255,1)"; // white filler
this.context.fillRect(14, 2, this.width - 4, lineHeight + 4);
this.context.fillStyle = "rgba(0,0,0,1)"; // text color
this.context.fillText(message, 16, lineHeight);
this.mesh.userData = message;
this.texture.needsUpdate = true;
};
THREE.MouseTooltip.prototype.isVisible = function (b) {
return this.mesh.visible;
};
THREE.MouseTooltip.prototype.hide = function (b) {
this.mesh.visible = false;
};
THREE.MouseTooltip.prototype.show = function (b) {
this.mesh.visible = true;
};
THREE.MouseTooltip.prototype.clear = function () {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.texture.needsUpdate = true;
};
THREE.MouseTooltip.prototype.move = function (mouseX, mouseY) {
this.mesh.position.x = (mouseX - this.options.Container.offsetLeft+16) - this.canvas.width;
this.mesh.position.y = (mouseY - this.options.Container.offsetTop) - this.canvas.height;
this.mesh.position.z = 1;
};
</pre></code>
Regarding to the example in http://threejs.org/examples/webgl_sprites.html your actual positions would be
this.mesh.position.x = -(SCREEN_WIDTH / 2) + mouseX;
this.mesh.poyition.y = (SCREEN_WIDTH / 2) - mouseY;

Resources