Hello, I’m struggling already for sometime with the following. I’m trying to create a click event that allso works on touch devices. I have things working in such a way that the objects are clickable with the mouse but on touch the objects seem to be only clickable when the mouse is hovering over a object and then when the object is being touched it is clickable. Also I noticed that when I click an object with the mouse (for now the function being called is opening up a new window) that when I return to the main window the object is still being selected and dragged/moved by the mouse until I click again. I tried already numerous things and watched many tutorials but I can’t figure things out. Still a newbie here so probably I’m just overlooking something simple (t least that is what i hope). Thanks in advance for looking into this and here is my code:
// Model
let myModel;
let modelPath_MyModel = '/wp-content/uploads/2021/05/new_brain.glb';
let isLoaded = false;
// Material
let texturePath_Enviroment = '/wp-content/uploads/2021/05/Matcap-test34-min.png';
let mat_Enviroment;
let mat_GlassMatCapBack;
let mat_GlassMatCapFront;
let mat_BrainCoreBlue;
let mat_BrainInnerOutterBlue;
let mat_BrainCoreRed;
let mat_BrainInnerOutterRed;
let mat_BrainInnerOutterRed2;
let brainRight;
const statsEnabled = false;
let container, stats;
// three
let scene;
let camera;
let pointer;
let controls;
let renderer;
let delta;
let clock = new THREE.Clock();
let currentIntersect;
let mouseX = 0;
let mouseY = 0;
let targetX = 0;
let targetY = 0;
const windowHalfX = window.innerWidth / 2;
const windowHalfY = window.innerHeight / 2;
function initMainApp () {
buildScene();
buildLightEnviroment();
buildMaterial();
buildModel();
watchLoadingManager();
buildSphereGeometry();
}
function buildScene () {
const container = document.querySelector('#mainCanvas');
scene = new THREE.Scene();
//scene.background = new THREE.Color(0x000000);
camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.z = 14;
camera.position.y = 1;
const cameraHolder = new THREE.Group();
cameraHolder.add(camera);
scene.add(cameraHolder);
renderer = new THREE.WebGLRenderer({ container, antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.shadowMap.needsUpdate = true;
stats = new Stats();
container.appendChild(renderer.domElement);
// container.onmousemove = function(){
controls = new THREE.OrbitControls(camera, container );
//controls.addEventListener('change', render);
controls.enableDamping = true;
controls.dampingFactor = 0.08;
controls.enableZoom = false;
controls.enablePan = false;
controls.enabled = true;
controls.maxAzimuthAngle = Math.PI * 0.2;
controls.minAzimuthAngle = Math.PI * 1.7;
controls.maxPolarAngle = 1.7;
controls.minPolarAngle = 1.2;
controls.autoRotate = false;
controls.autoRotateSpeed = 2;
//controls.addEventListener('mousemove', onDocumentMouseMove, false)
//controls.update();
}
function buildLightEnviroment () {
const light_Ambient = new THREE.AmbientLight(0xFFFFFF);
light_Ambient.intensity = 0.75;
scene.add(light_Ambient);
mat_Enviroment = new THREE.TextureLoader().load(texturePath_Enviroment);
mat_Enviroment.mapping = THREE.SphericalReflectionMapping;
}
const fontLoader = new THREE.FontLoader()
fontLoader.load(
'/wp-content/static/Metrophobic_Regular.json',
(font) =>
{
//Services Text
const textGeometry = new THREE.TextBufferGeometry(
'Services',
{
font: font,
size: 0.17,
height: 0.03,
curveSegments: 4,
bevelEnabled: true,
bevelThickness: 0.003,
bevelSize: 0.002,
bevelOffset: 0,
bevelSegments: 3,
}
)
const textMaterial = new THREE.MeshMatcapMaterial({
matcap: mat_Enviroment,
color: 0x0000ff,
//shininess: 2500,
transparent: true,
opacity: 1,
depthWrite: true,
//depthTest: true,
blending: THREE.AdditiveBlending,
})
text = new THREE.Mesh(textGeometry, textMaterial)
text.position.x = -1.05,
text.position.y = 0.9,
text.position.z = 0.35;
scene.add(text);
//Projects Text
const textGeometry2 = new THREE.TextBufferGeometry(
'Projects',
{
font: font,
size: 0.17,
height: 0.03,
curveSegments: 4,
bevelEnabled: true,
bevelThickness: 0.003,
bevelSize: 0.002,
bevelOffset: 0,
bevelSegments: 3,
})
const textMaterial2 = new THREE.MeshMatcapMaterial({
matcap: mat_Enviroment,
color: 0xffffff,
transparent: true,
opacity: 1,
depthWrite: true,
//depthTest: true,
blending: THREE.AdditiveBlending,
})
text2 = new THREE.Mesh(textGeometry2, textMaterial2)
text2.position.x = -0.42,
text2.position.y = 2.8;
text2.position.z = 1.45;
scene.add(text2);
//Creators Text
const textGeometry3 = new THREE.TextBufferGeometry(
'Creators',
{
font: font,
size: 0.17,
height: 0.03,
curveSegments: 4,
bevelEnabled: true,
bevelThickness: 0.003,
bevelSize: 0.002,
bevelOffset: 0,
bevelSegments: 3,
}
)
const textMaterial3 = new THREE.MeshMatcapMaterial({
matcap: mat_Enviroment,
color: 0xffffff,
transparent: true,
opacity: 0.95,
depthWrite: true,
blending: THREE.AdditiveBlending,
//side: THREE.FrontSide,
})
text3 = new THREE.Mesh(textGeometry3, textMaterial3)
text3.position.x = 0.15,
text3.position.y = 1.5,
text3.position.z = -1.45;
scene.add(text3);
gsap.fromTo(text.position, {y: 0.85},{duration: 4, y: 1.05, ease: 'linear.in', yoyo: true, repeat: -1 })
gsap.fromTo(text2.position, {y: 2.4},{duration: 4, y: 2.75, ease: 'linear.in', yoyo: true, repeat: -1 });
gsap.fromTo(text3.position, {y: 1.45},{duration: 4, y: 1.5, ease: 'linear.in', yoyo: true, repeat: -1 })
})
function buildSphereGeometry () {
const matcapTexture = new THREE.TextureLoader().load('/wp-content/uploads/2021/05/Matcap-balls36-min.png');
const geometry = new THREE.SphereGeometry( 0.60, 32, 32 );
const geometryA = new THREE.SphereGeometry( 0.3, 32, 32 );
const geometry1 = new THREE.SphereGeometry( 0.60, 32, 32 );
const geometryB = new THREE.SphereGeometry( 0.3, 32, 32 );
const geometry2 = new THREE.SphereGeometry( 0.60, 32, 32 );
const geometryC = new THREE.SphereGeometry( 0.3, 32, 32 );
//Blue Ball
const material = new THREE.MeshMatcapMaterial({
color: 0x03acee,
transparent: true,
opacity: 0.9,
depthWrite: true,
blending: THREE.AdditiveBlending,
})
material.matcap = matcapTexture
sphere = new THREE.Mesh( geometry, material );
sphere.position.x = -0.6;
sphere.position.y = 1;
sphere.position.z = 0;
sphere.renderOrder = 2;
sphere.callback = objectClickHandler;
scene.add( sphere );
//Blue ball inner
const materialA = new THREE.MeshPhongMaterial({
color: 0x03acee,
//emissive: 0xFFFF00,
transparent: true,
opacity: 0.7,
shininess: 250,
depthWrite: true,
blending: THREE.AdditiveBlending,
})
//materialA.matcap = matcapTexture
sphereA = new THREE.Mesh( geometryA, materialA );
sphereA.position.y = 1;
sphereA.position.x = -0.6;
sphereA.position.z = 0;
sphereA.renderOrder = 1;
scene.add( sphereA );
//Green Ball
const material2 = new THREE.MeshMatcapMaterial({
color: 0x00ff00,
transparent: true,
opacity: 0.9,
depthWrite: true,
blending: THREE.AdditiveBlending,
})
material2.matcap = matcapTexture
sphere2 = new THREE.Mesh( geometry1, material2 );
sphere2.position.y = 2.65;
sphere2.position.x = 0;
sphere2.position.z = 1.1;
sphere2.renderOrder = 2;
sphere2.callback = objectClickHandler2;
scene.add( sphere2 );
//Green Ball Inner
const materialB = new THREE.MeshPhongMaterial({
color: 0x00ff00,
transparent: true,
opacity: 0.7,
shininess: 250,
depthWrite: true,
blending: THREE.AdditiveBlending,
})
sphereB = new THREE.Mesh( geometryB, materialB );
sphereB.position.y = 2.65;
sphereB.position.x = 0;
sphereB.position.z = 1.1;
sphereB.renderOrder = 1;
scene.add( sphereB );
//Red Ball
const material3 = new THREE.MeshMatcapMaterial({
color: 0xfff200,
transparent: true,
opacity: 0.9,
depthWrite: true,
blending: THREE.AdditiveBlending,
})
material3.matcap = matcapTexture
sphere3 = new THREE.Mesh( geometry2, material3 );
sphere3.position.x = 0.6;
sphere3.position.y = 1.525;
sphere3.position.z = -1.9;
sphere3.renderOrder = 2;
sphere3.callback = objectClickHandler3;
scene.add( sphere3 );
//Red Ball inner
const materialC = new THREE.MeshPhongMaterial({
color: 0xfff200,
transparent: true,
shininess: 250,
opacity: 0.9,
depthWrite: true,
blending: THREE.AdditiveBlending,
})
sphereC = new THREE.Mesh( geometryC, materialC );
sphereC.position.y = 1.525;
sphereC.position.x = 0.6;
sphereC.position.z = -1.9;
sphereC.renderOrder = 1;
scene.add( sphereC );
gsap.fromTo(sphere.position, {y: 0.9},{duration: 4, y: 1.1, ease: 'linear.in', yoyo: true, repeat: -1 });
gsap.fromTo(sphereA.position, {y: 0.9},{duration: 4, y: 1.1, ease: 'linear.in', yoyo: true, repeat: -1 });
gsap.fromTo(sphere2.position, {y: 2.5},{duration: 4, y: 2.8, ease: 'linear.in', yoyo: true, repeat: -1 });
gsap.fromTo(sphereB.position, {y: 2.5},{duration: 4, y: 2.8, ease: 'linear.in', yoyo: true, repeat: -1 });
gsap.fromTo(sphere3.position, {y: 1.5},{duration: 4, y: 1.55, ease: 'linear.in', yoyo: true, repeat: -1 });
gsap.fromTo(sphereC.position, {y: 1.5},{duration: 4, y: 1.55, ease: 'linear.in', yoyo: true, repeat: -1 });
};
//Raycaster
raycaster = new THREE.Raycaster();
function buildModel () {
const loader_GLTF = new THREE.GLTFLoader();
loader_GLTF.load(modelPath_MyModel, function (gltf) {
myModel = gltf.scene;
scene.add(myModel);
myModel.position.y = -2.3;
myModel.traverse(function (child) {
if (child.isMesh) {
child.frustumCulled = false;
if ( child.name == 'brain_right_core') {
child.material = mat_BrainCoreBlue;
child.renderOrder = 1;
gsap.fromTo(child.scale, {y: 1, x: 1},{duration: 1.5, y: 1.1, x: 1.1, ease: 'none', yoyo: true, repeat: -1 });
child.castShadow = true;
child.receiveShadow = true;
} else if ( child.name == 'brain_right_inner' ) {
child.material = mat_BrainInnerOutterBlue;
child.renderOrder = 2;
gsap.fromTo(child.scale, {y: 1, x: 1},{duration: 1.5, y: 1.05, x: 1.05, ease: 'none', yoyo: true, repeat: -1 });
} else if ( child.name == 'brain_right_outer' ) {
child.material = mat_BrainInnerOutterBlue;
child.renderOrder = 4;
gsap.fromTo(child.scale, {y: 1, x: 1},{duration: 1.5, y: 1.1, x: 1.1, ease: 'none', yoyo: true, repeat: -1 });
} else if ( child.name == 'brain_left_core') {
child.material = mat_BrainCoreRed;
child.renderOrder = 2;
gsap.fromTo(child.scale, {y: 1, x: 1},{duration: 1.5, y: 1.1, x: 1.1, ease: 'none', yoyo: true, repeat: -1 });
} else if ( child.name == 'brain_left_inner') {
child.material = mat_BrainInnerOutterRed;
child.renderOrder = 3;
child.castShadow = true;
child.receiveShadow = true;
gsap.fromTo(child.scale, {y: 1, x: 1},{duration: 1.5, y: 1.05, x: 1.05, ease: 'none', yoyo: true, repeat: -1 });
} else if ( child.name == 'brain_left_outer') {
child.material = mat_BrainInnerOutterRed2;
child.renderOrder = 5;
gsap.fromTo(child.scale, {y: 1, x: 1},{duration: 1.5, y: 1.1, x: 1.1, ease: 'none', yoyo: true, repeat: -1 });
} else if ( child.name == 'bottle') {
child.material = mat_GlassMatCapBack;
child.renderOrder = 6;
let bottleClone = child.clone();
bottleClone.material = mat_GlassMatCapFront;
scene.getObjectByName( "BrainBottle" ).add( bottleClone );
}
}
});});
}
function buildMaterial () {
mat_GlassMatCapBack = new THREE.MeshMatcapMaterial({
color: 0xFFFFFF,
matcap: mat_Enviroment,
side: THREE.BackSide,
transparent: true,
opacity: 0.35,
blending: THREE.AdditiveBlending, // THREE.CustomBlending for normal look
});
mat_GlassMatCapFront = new THREE.MeshMatcapMaterial({
color: 0xFFFFFF,
matcap: mat_Enviroment,
side: THREE.FrontSide,
transparent: true,
opacity: 0.65,
blending: THREE.AdditiveBlending, // THREE.CustomBlending for normal look
});
mat_BrainCoreBlue = new THREE.MeshPhongMaterial({
color: 0x03acee,
//emissive: 0x000000,
shininess: 2500,
blending: THREE.AdditiveBlending,
side: THREE.FrontSide,
depthWrite: false,
//depthTest: true,
transparent: true,
opacity: 0.95,
});
mat_BrainInnerOutterBlue = new THREE.MeshPhongMaterial({
color: 0x03acee,
emissive: 0x000000,
//shininess: 2500,
blending: THREE.CustomBlending,
side: THREE.FrontSide,
depthWrite: false,
//depthTest: true,
transparent: true,
opacity: 0.25,
});
mat_BrainCoreRed = new THREE.MeshPhongMaterial({
color: 0xcb5332,
emissive: 0x000000,
shininess: 25,
blending: THREE.CustomBlending,
side: THREE.FrontSide,
depthWrite: false,
//depthTest: true,
transparent: true,
opacity: 0.95,
});
mat_BrainInnerOutterRed = new THREE.MeshPhongMaterial({
color: 0xcb5332,
emissive: 0xFFFF00,
shininess: 25,
blending: THREE.CustomBlending,
side: THREE.FrontSide,
depthWrite: false,
//depthTest: true,
transparent: true,
opacity: 0.25,
});
mat_BrainInnerOutterRed2 = new THREE.MeshPhongMaterial({
color: 0x000000,
emissive: 0xFFFF00,
shininess: 2500,
blending: THREE.CustomBlending,
side: THREE.FrontSide,
depthWrite: false,
//depthTest: true,
transparent: true,
opacity: 0.15,
});
}
// EVENTS
document.addEventListener( 'mousemove', onDocumentMouseMove );
window.addEventListener( 'resize', onWindowResize );
function onWindowResize() {
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
function onDocumentMouseMove( event ) {
mouseX = ( event.clientX - windowHalfX );
mouseY = ( event.clientY - windowHalfY );
}
function objectClickHandler(){
window.open('/services');
}
function objectClickHandler2(){
window.open('/projects');
}
function objectClickHandler3(){
window.open('/creators');
}
//Cursor
cursor = new THREE.Vector2();
function onDocumentMouseDown(event4) {
//event4.preventDefault();
{
pointer.x = event4.pageX / window.width * 2 - 1
pointer.y = - (event4.pageY / window.height * 2 - 2.95);
}
}
window.addEventListener('mousemove', (event3) =>
{
cursor.x = event3.pageX / window.innerWidth * 2 - 1
cursor.y = - (event3.pageY / window.innerHeight * 2 - 2.95);
})
//function onDocumentMouseDown(event4){
// event4.preventDefault();
//window.addEventListener( 'mousedown', onDocumentMouseDown );
//window.addEventListener('mousedown', () =>
window.addEventListener('pointerdown',() =>
{
if(currentIntersect)
{
if(currentIntersect.object === sphere)
{
sphere.callback();
}
else if(currentIntersect.object === sphere2)
{
sphere2.callback();
console.log('click on object 2')
}
else if(currentIntersect.object === sphere3)
{
sphere3.callback();
console.log('click on object 3')
}
}
})
function animate () {
requestAnimationFrame(animate);
delta = clock.getDelta();
//Cast a Ray
raycaster.setFromCamera(cursor, camera)
const objectsToTest = [sphere, sphere2, sphere3]
const intersects = raycaster.intersectObjects(objectsToTest)
for(const object of objectsToTest)
{
if(object === sphere)
{
sphere.material.color.set('#03acee')
}
else if(object === sphere2)
{
sphere2.material.color.set('#3cb878')
}
else if(object === sphere3)
{
sphere3.material.color.set('#ec0c57')
}
for(const intersect of intersects)
{
if(object === sphere)
{
intersect.object.material.color.set('#6dcff6')
}
else if(object === sphere2)
{
intersect.object.material.color.set('#a5f3bf')
}
else if(object === sphere3)
{
intersect.object.material.color.set('#a5f3bf')
}
}
}
if(intersects.length)
{
if(!currentIntersect)
{
console.log('mouse enter')
}
currentIntersect = intersects[0]
}
else
{
if(currentIntersect)
{
console.log('mouse leave')
}
currentIntersect = null
}
render();
if ( statsEnabled ) stats.update();
}
function render() {
targetX = mouseX * .001;
targetY = mouseY * .001;
if ( myModel );{
myModel.rotation.y += 0.05 * ( targetX - myModel.rotation.y );
myModel.rotation.x += 0.05 * ( targetY - myModel.rotation.x );
}
controls.update()
renderer.render(scene, camera);
}
function startApplication () {
animate();
}
function watchLoadingManager () {
THREE.DefaultLoadingManager.onStart = function ( url, itemsLoaded, itemsTotal ) {
// console.log('Started loading file: ' + url + '.\nLoaded ' + itemsLoaded + ' of ' + itemsTotal + ' files.');
};
THREE.DefaultLoadingManager.onLoad = function () {
console.log('Loading Complete!');
isLoaded = true;
startApplication();
};
THREE.DefaultLoadingManager.onProgress = function ( url, itemsLoaded, itemsTotal ) {
// console.log('Loading file: ' + url + '.\nLoaded ' + itemsLoaded + ' of ' + itemsTotal + ' files.');
};
THREE.DefaultLoadingManager.onError = function ( url ) {
// console.log('There was an error loading ' + url);
};
}
initMainApp();