ThreeJS - How to maintain object position after scene resize - three.js

I'm a novice to ThreeJS and I have a new problem. I place an arrow in the scene, but then when I resize the window, the position of the arrow (relative to the scene background) changes. How do I prevent this?
Here is the "good" positioning, where the arrow comes out of the person's head:
Here is the "bad" positioning, where the arrow has now moved to the side of the person's head:
My index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- Imporant meta information to make the page as rigid as possible on mobiles, to avoid unintentional zooming on the page itself -->
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Character Tutorial</title>
</head>
<body>
<!-- The loading element overlays all else until the model is loaded, at which point we remove this element from the DOM -->
<div class="loading" id="js-loader"><div class="loader"></div></div>
<div class="wrapper">
<!-- The canvas element is used to draw the 3D scene -->
<canvas id="c"></canvas>
</div>
<!-- The main Three.js file -->
<!-- <script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.min.js'></script>-->
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js'></script>
<!-- This brings in the ability to load custom 3D objects in the .gltf file format. Blender allows the ability to export to this format out the box -->
<!-- <script src='https://cdn.jsdelivr.net/gh/mrdoob/Three.js#r92/examples/js/loaders/GLTFLoader.js'></script>-->
<script src="js/script.js"></script>
</body>
</html>
My script.js:
// noinspection DuplicatedCode
// Copied from https://stackoverflow.com/questions/63776448/threejs-applying-edge-geometry-to-arrowhelper
class CustomArrow extends THREE.Object3D {
constructor( dir, origin, length, color, edgeColor, headLength, headWidth ) {
super();
// dir is assumed to be normalized
this.type = 'CustomArrow';
if ( dir === undefined ) dir = new THREE.Vector3( 0, 0, 1 );
if ( origin === undefined ) origin = new THREE.Vector3( 0, 0, 0 );
if ( length === undefined ) length = 1;
if ( color === undefined ) color = 0xffff00;
if ( headLength === undefined ) headLength = 0.2 * length;
if ( headWidth === undefined ) headWidth = 0.2 * headLength;
if ( this._lineGeometry === undefined ) {
this._lineGeometry = new THREE.BufferGeometry();
this._lineGeometry.setAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
// this._lineGeometry.position = new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 );
this._coneGeometry = new THREE.ConeBufferGeometry( 0.5, 1, 6);
this._coneGeometry.translate( 0, - 0.5, 0 );
this._axis = new THREE.Vector3();
}
this.position.copy( origin );
this.line = new THREE.Line( this._lineGeometry, new THREE.LineBasicMaterial( { color: edgeColor, toneMapped: false, linewidth: 4 } ) );
// this.line.matrixAutoUpdate = false;
this.add( this.line )
// base material
this.cone = new THREE.Mesh( this._coneGeometry, new THREE.MeshBasicMaterial( { color: color, toneMapped: false } ) );
this.add(this.cone);
// wire frame
this.wireframe = new THREE.Mesh( this._coneGeometry, new THREE.MeshBasicMaterial( {
color: edgeColor,
toneMapped: false,
wireframe: true,
wireframeLinewidth: 2 } ) );
this.add(this.wireframe);
this.setDirection( dir );
this.setLength( length, headLength, headWidth );
}
setDirection( dir ) {
// dir is assumed to be normalized
if ( dir.y > 0.99999 ) {
this.quaternion.set( 0, 0, 0, 1 );
} else if ( dir.y < - 0.99999 ) {
this.quaternion.set( 1, 0, 0, 0 );
} else {
this._axis.set( dir.z, 0, - dir.x ).normalize();
const radians = Math.acos( dir.y );
this.quaternion.setFromAxisAngle( this._axis, radians );
}
}
setLength( length, headLength, headWidth ) {
if ( headLength === undefined ) headLength = 0.2 * length;
if ( headWidth === undefined ) headWidth = 0.2 * headLength;
this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458
this.line.updateMatrix();
this.cone.scale.set( headWidth, headLength, headWidth );
this.cone.position.y = length;
this.cone.updateMatrix();
this.wireframe.scale.set( headWidth, headLength, headWidth );
this.wireframe.position.y = length;
this.wireframe.updateMatrix();
}
setColor( color ) {
this.line.material.color.set( color );
// this.cone.material.color.set( color );
// this.wireframe.material.color.set( color );
}
copy( source ) {
super.copy( source, false );
this.line.copy( source.line );
this.cone.copy( source.cone );
this.wireframe.copy( source.wireframe );
return this;
}
}
(function() {
// Set our main variables
let scene = new THREE.Scene(),
renderer,
camera,
cone,
backgroundLoader = new THREE.TextureLoader(),
arrow, // Surface normal direction
canRotate = false,
arrowLength = 1,
arrowHeadLength = 0.6,
arrowHeadWidth = 0.4,
pointer = new THREE.Vector3(),
lookAt = new THREE.Vector3(),
intersectPoint = new THREE.Vector3(),
mouse = new THREE.Vector2(), // for reuse
plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0),
raycaster = new THREE.Raycaster(); // Used to detect the click on our character
init();
function init() {
const canvas = document.querySelector('#c');
// Init the scene.
scene.background = backgroundLoader.load('https://assets.imgix.net/hp/snowshoe.jpg');
// Init the renderer.
renderer = new THREE.WebGLRenderer({canvas, antialias: true}); // what is anti-aliasing?
renderer.shadowMap.enabled = true;
// What is difference between renderer.setSize and renderer.setPixelRatio?
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
1,
1000
);
// camera.position.set(0, -3, 30);
// camera.position.set(0, 0, 1).setLength(6);
camera.position.set(0, 0, 6);
// Add arrow variables
const arrowDirection = new THREE.Vector3();
// Wrist
// const arrowPosition = new THREE.Vector3(-0.14, .4, 0);
// Left snow
// const arrowPosition = new THREE.Vector3(-2, -1.5, 0);
// Backpack
const arrowPosition = new THREE.Vector3(0.3, 1.49, 0);
// Calf
// const arrowPosition = new THREE.Vector3(0.10, -0.85, 0);
// const arrowPosition = new THREE.Vector3(0, 1, 0);
arrowDirection.subVectors( scene.position, new THREE.Vector3(1, 1, 1)).normalize();
// arrow = new THREE.ArrowHelper( arrowDirection, arrowPosition, arrowLength, 0xfffff00, arrowHeadLength, arrowHeadWidth);
arrow = new CustomArrow( arrowDirection, arrowPosition, arrowLength, 0xfffff00, 0x000000, arrowHeadLength, arrowHeadWidth);
arrow.castShadow = true;
scene.add( arrow );
}
function update() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
requestAnimationFrame(update);
}
update();
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
let width = window.innerWidth;
let height = window.innerHeight;
let canvasPixelWidth = canvas.width / window.devicePixelRatio;
let canvasPixelHeight = canvas.height / window.devicePixelRatio;
const needResize =
canvasPixelWidth !== width || canvasPixelHeight !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
// If user clicks, that toggles whether the arrow can move.
document.addEventListener('click', function (e) {
canRotate = ! canRotate;
})
document.addEventListener('mousemove', function (e) {
if (canRotate) {
pointer.x = (e.clientX / window.innerWidth) * 2 - 1;
pointer.y = - (e.clientY / window.innerHeight) * 2 + 1;
// Approach 0: https://stackoverflow.com/a/36071100/4570472
let vector = new THREE.Vector3(pointer.x, pointer.y, 0.5);
vector.unproject( camera );
let remainder = arrowLength * arrowLength - vector.x * vector.x - vector.y * vector.y
if (remainder <= 0){
vector.z = 0;
} else {
vector.z = Math.sqrt(remainder);
}
let dir = vector.normalize();
// Working, but doesn't track mouse exactly
arrow.setDirection(dir);
}
});
})(); // Don't add anything below this line

Related

How to resize threejs mesh via controls

The only way I know how to resize an extruded path is but reconstructing it. I want to know whether there is a way I can control the length/width/height in the threejs controls.
Here is my code:
'use strict';
/* global THREE, dat */
function main() {
const canvas = document.querySelector('#canvas');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 45;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 100;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 10, 20);
const controls = new THREE.OrbitControls(camera, canvas);
controls.target.set(0, 5, 0);
controls.update();
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
{
const planeSize = 40;
const loader = new THREE.TextureLoader();
const texture = loader.load('https://r105.threejsfundamentals.org/threejs/resources/images/checker.png');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.magFilter = THREE.NearestFilter;
const repeats = planeSize / 2;
texture.repeat.set(repeats, repeats);
const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
const planeMat = new THREE.MeshPhongMaterial({
map: texture,
side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(planeGeo, planeMat);
mesh.rotation.x = Math.PI * -.5;
scene.add(mesh);
}
{
// Create a Shape Mesh with basic material
const shape = new THREE.Shape();
const x_len = 12;
const y_len = 8;
const z_len = 1;
shape.moveTo( 0, 0 );
shape.lineTo( 0, y_len );
shape.lineTo( x_len, y_len );
shape.lineTo( x_len, 0 );
shape.lineTo( 0, 0 );
const thickness = 0.5;
shape.lineTo( thickness, thickness );
shape.lineTo( x_len-thickness, thickness );
shape.lineTo( x_len-thickness, y_len-thickness );
shape.lineTo( thickness, y_len-thickness );
shape.lineTo( thickness, thickness );
const extrudeSettings = {
steps: 2,
depth: z_len,
bevelEnabled: false,
bevelThickness: 1,
bevelSize: 1,
bevelOffset: 0,
bevelSegments: 1
};
const geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
const material = new THREE.MeshPhongMaterial({color: '#CA8'});
const mesh = new THREE.Mesh( geometry, material ) ;
scene.add( mesh );
}
class ColorGUIHelper {
constructor(object, prop) {
this.object = object;
this.prop = prop;
}
get value() {
return `#${this.object[this.prop].getHexString()}`;
}
set value(hexString) {
this.object[this.prop].set(hexString);
}
}
function makeXYZGUI(gui, vector3, name, onChangeFn) {
const folder = gui.addFolder(name);
folder.add(vector3, 'x', -10, 10).onChange(onChangeFn);
folder.add(vector3, 'y', 0, 10).onChange(onChangeFn);
folder.add(vector3, 'z', -10, 10).onChange(onChangeFn);
folder.open();
}
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.PointLight(color, intensity);
light.position.set(0, 10, 4);
scene.add(light);
const helper = new THREE.PointLightHelper(light);
scene.add(helper);
function updateLight() {
helper.update();
}
const gui = new dat.GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
gui.add(light, 'intensity', 0, 2, 0.01);
gui.add(light, 'distance', 0, 40).onChange(updateLight);
makeXYZGUI(gui, light.position, 'position');
}
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);
}
main();
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- Simple reset to delete the margins -->
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<!-- Our code -->
<canvas id="canvas"></canvas>
<script src="https://r105.threejsfundamentals.org/threejs/resources/threejs/r105/three.min.js"></script>
<script src="https://r105.threejsfundamentals.org/threejs/resources/threejs/r105/js/controls/OrbitControls.js"></script>
<script src="https://r105.threejsfundamentals.org/threejs/../3rdparty/dat.gui.min.js"></script>
</html>
In this code, I want to change x_len, y_len, z_len
I'm using a library called dat.gui.
The problem is that each of these values map to multiple properties. For example, x_len maps to
shape.curves[2].x
shape.curves[3].x
shape.curves[6].x
shape.curves[7].x
so I probably need something like:
gui.add(some object to point to all relevant curves, 'x', 0, 40).onChange(someCallback);
any help will be appreciated.

How to use line with width of three.js with morphTargets to animate one line moving to another

question reference
I want to implement an animation.
The animation should be a line move to another line. There will be some deformation in the process of the line moving
There is a correspondence between the points of the two lines.
I can use the basic line of three.js to animate one line moving to another.
<script type="module">
import * as THREE from '../../build/three.module.js'
import { OrbitControls } from '../jsm/controls/OrbitControls.js'
function main() {
var scene = new THREE.Scene()
const geometry = new THREE.BufferGeometry().setAttribute('position',
new THREE.Float32BufferAttribute([-2, 0, 0, -0.5, 0, -0.5, 0, 0, -2], 3))
const geometry1 = new THREE.BufferGeometry().setAttribute('position',
new THREE.Float32BufferAttribute([5, 0, 0, 1, 1, 1, 0, 0, 5], 3))
geometry.morphAttributes.position = [
geometry1.attributes.position,
]
var material = new THREE.LineBasicMaterial({
color: 0x0000ff,
})
var mesh = new THREE.Line(geometry, material)
mesh.morphTargetInfluences[0] = 0
scene.add(mesh)
/**
*
*/
var width = window.innerWidth
var height = window.innerHeight
var k = width / height
var s = 10
var camera = new THREE.OrthographicCamera(
-s * k,
s * k,
s,
-s,
-1500,
1500
)
camera.position.set(10, 10, 10)
camera.lookAt(10, 0, 0)
/**
*
*/
var renderer = new THREE.WebGLRenderer()
// window.renderer = renderer;
renderer.setSize(width, height)
renderer.setClearColor(0xb9d3ff, 1)
document.body.appendChild(renderer.domElement)
// renderer.render(scene, camera);
new OrbitControls(camera, renderer.domElement)
var clock = new THREE.Clock()
const axes = new THREE.AxesHelper(10)
scene.add(axes)
let flag = false
let index = 0
function render() {
renderer.render(scene, camera)
requestAnimationFrame(render)
if (index <0) {
flag = true
} else if (index > 1) {
flag = false
}
if (flag) {
index += 0.01
} else {
index -= 0.01
}
mesh.morphTargetInfluences[0] = index
console.log(flag, index)
}
render()
}
main()
</script>
Now I want to use the LineGeometry of three.js because this line has a width property. How to use the morphtargets with LineGeometry?
If the LineGeometry can't do it,any other bufferGeometry to replace LineGeometry?
Three.js 136.
<script type="module">
import * as THREE from '../../build/three.module.js'
import { OrbitControls } from '../jsm/controls/OrbitControls.js'
import { Line2 } from '../jsm/lines/Line2.js'
import { LineMaterial } from '../jsm/lines/LineMaterial.js'
import { LineGeometry } from '../jsm/lines/LineGeometry.js'
function main() {
var scene = new THREE.Scene()
const geometry2 = new LineGeometry()
geometry2.setPositions([-3, 0, 0, -0.5, 0, -0.5, 0, 0, -2])
console.log(geometry2)
const geometry1 = new LineGeometry()
geometry1.setPositions([-3, 0, 0, -1, 0, -1, 0, 0, -3])
geometry2.morphAttributes.position = [geometry1.attributes.position]
let matLine = new LineMaterial({
color: '#ffdb2d',
linewidth: 5, // in world units with size attenuation, pixels otherwise
})
let line = new Line2(geometry2, matLine)
line.morphTargetInfluences[0] = 0
scene.add(line)
/**
*/
var width = window.innerWidth
var height = window.innerHeight
var k = width / height
var s = 5
var camera = new THREE.OrthographicCamera(
-s * k,
s * k,
s,
-s,
-1500,
1500
)
camera.position.set(5, 5, 5)
camera.lookAt(5, 0, 0)
var renderer = new THREE.WebGLRenderer()
// window.renderer = renderer;
renderer.setSize(width, height)
renderer.setClearColor(0xb9d3ff, 1)
document.body.appendChild(renderer.domElement)
// renderer.render(scene, camera);
new OrbitControls(camera, renderer.domElement)
var clock = new THREE.Clock()
const axes = new THREE.AxesHelper(10)
scene.add(axes)
let flag = false
let index = 0
function render() {
renderer.render(scene, camera)
requestAnimationFrame(render)
if (index < 0) {
flag = true
} else if (index > 1) {
flag = false
}
if (flag) {
index += 0.01
} else {
index -= 0.01
}
line.morphTargetInfluences[0] = index
matLine.resolution.set(window.innerWidth, window.innerHeight) // resolution of the viewport
}
render()
}
main()
</script>
Use TubeGeometry:
const curve = new THREE.CatmullRomCurve3([new THREE.Vector3(-2, 0, 0), new THREE.Vector3(-0.5, 0, -0.5), new THREE.Vector3(0, 0, -2)])
var tubeGeometry = new THREE.TubeGeometry(curve, 100, 0.05, 50, false);
const curve1 = new THREE.CatmullRomCurve3([new THREE.Vector3(0, 0, 5,), new THREE.Vector3( 1, 1, 1,), new THREE.Vector3(5, 0, 0,)])
var tubeGeometry1 = new THREE.TubeGeometry(curve1, 100, 0.05, 50, false);
tubeGeometry.morphAttributes.position = [
tubeGeometry1.attributes.position,
]
var tubeMaterial = new THREE.MeshBasicMaterial({
side:THREE.DoubleSide,
color:'#ffffff',
});
var tube = new THREE.Mesh(tubeGeometry, tubeMaterial);
tube.morphTargetInfluences[0] = 0
scene.add(tube)
In the render function:
tube.morphTargetInfluences[0] += 0.01

three.js change object distance dynamically

I'm using three.js for graphical website.
It's concept is universe that has many text.
If I click the text, Regardless of it's distance, object have to move to fixed position(or camera's front)
So I wrote the code like this.
[index.html]
<html>
<head>
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://gitcdn.xyz/repo/thesmart/jquery-scrollspy/0.1.3/scrollspy.js"></script>
<script src="./src/WOW.js"></script>
<script src="./src/three.js"></script>
<script src="//cdn.rawgit.com/mrdoob/three.js/master/examples/js/loaders/ColladaLoader.js"></script>
<script src="https://unpkg.com/three.texttexture"></script>
<script src="https://unpkg.com/three.textsprite"></script>
<script src="./src/DeviceOrientationControls.js"></script>
<script src="./src/hammer.js"></script>
<script src="./src/Detector.js"></script>
<script src="./src/perlin.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" href="animate.css">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<meta charset="UTF-8">
</head>
<body>
<header>
<div class="header-left">
MAIN
</div>
<div class="header-right">
MISSION
PRODUCT
CULTURE
STORY
</div>
</header>
<main>
<!-- Universe -->
<section id="universe" class="wow" data-wow-duration="0.5s"></section>
<!-- Main -->
<section class="main" id="main">
</section>
<script src="./src/src.js"></script>
</main>
</body>
</html>
[src.js]
// VARIABLES
let clock, camera, scene, renderer, mixer;
const sleep = ms => new Promise(res => setTimeout(res, ms));
var myElement = document.getElementById("threejs");
const mouse = new THREE.Vector2();
const clicked = new THREE.Vector2();
const target = new THREE.Vector2();
const windowHalf = new THREE.Vector2( window.innerWidth / 2, window.innerHeight / 2 );
const moveState = {forward: 0, back: 0};
var isMobile = false;
var textCount = 500;
var firstTime = true;
var fontFamily = '"Courier New", Courier, monospace';
var lock = true;
var group = new THREE.Group();
const scrollPosition = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
checkMobile()
// WOW.js
var wow = new WOW();
wow.init();
init();
async function init() {
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
scene = new THREE.Scene();
// CAMERA
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2100 );
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 1200;
camera.lookAt(scene.position);
clock = new THREE.Clock();
// HELPER
const gridHelper = new THREE.PolarGridHelper( 8, 16 );
scene.add( gridHelper );
// LIGHT
const ambientLight = new THREE.AmbientLight( 0xffffff, 0.2 );
scene.add( ambientLight );
const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.8 );
directionalLight.position.set( 1, 1, - 1 );
scene.add( directionalLight );
// CONTROLS
if(isMobile) { // 모바일이면
var controls = new THREE.DeviceOrientationControls(camera);
console.log('isMobile true');
} else {
console.log('isMobile false');
}
// SATISFY THE DESIRES OF LOVE
let sprite = new THREE.TextSprite({
textSize: 5,
redrawInterval: 250,
texture: {
text: 'MAIN TEST',
fontFamily: fontFamily,
},
material: {
color: 'white',
},
});
sprite.position.x = 0;
sprite.position.y = 0;
sprite.position.z = 10;
scene.add(sprite);
// ADD MESH
var size = ( isMobile ? 2 : 2 );
var starsLights = new THREE.Group();
var starGeometry = new THREE.SphereGeometry(0.3, 16, 16);
var emptyGeometry = new THREE.Geometry();
for ( let i = 0; i < textCount; i ++ ) {
var lod = new THREE.LOD();
// Text
let sprite = new THREE.TextSprite({
textSize: size,
redrawInterval: 250,
texture: {
text: 'For Test',
fontFamily: fontFamily,
},
material: {
color: 'white',
transparent: true,
},
});
// Star
var starMaterial = new THREE.MeshBasicMaterial({color: 0xffffff, transparent: true});
var star = new THREE.Mesh(starGeometry, starMaterial);
// Dummy
var dummy = new THREE.Mesh(emptyGeometry, new THREE.MeshBasicMaterial());
// Add
lod.addLevel(sprite, 1);
lod.addLevel(star, 100, 240);
lod.addLevel(dummy, 200, 300);
lod.position.x = (Math.random() * 180-100);
lod.position.y = Math.random() * 180-100;
lod.position.z = Math.random() * 1000-40;
group.add(lod);
}
scene.add(group);
// Renderer
renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.getElementById("universe").appendChild(renderer.domElement);
// Event handler
window.addEventListener('load', refreshCheck, false);
window.addEventListener('resize', onWindowResize, false);
document.addEventListener('mousemove', onMouseMove, false);
document.addEventListener('mousewheel', onMouseWheel, false);
document.addEventListener('contextmenu', onContextMenu, false);
document.addEventListener('mouseup', onMouseClick, false);
function animate() {
target.x = ( 1 - mouse.x ) * 0.002;
target.y = ( 1 - mouse.y ) * 0.002;
camera.rotation.x += 0.05 * ( target.y - camera.rotation.x );
camera.rotation.y += 0.05 * ( target.x - camera.rotation.y );
if(isMobile) {
controls.update();
}
// Object change related to distance
group.children.forEach(function(child) {
child.update(camera);
})
// Render
requestAnimationFrame( animate );
render(scene, camera);
}
animate();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onMouseWheel(event) {
event.preventDefault();
camera.position.z -= event.deltaY * 0.2;
}
function render() {
const delta = clock.getDelta();
if ( mixer !== undefined ) mixer.update( delta );
renderer.render( scene, camera );
}
function onTransitionEnd( event ) {
console.log("Loading Complete");
event.target.remove();
}
// Exist functions
function checkMobile() {
var UserAgent = navigator.userAgent;
if (UserAgent.match(/iPhone|iPod|Android|Windows CE|BlackBerry|Symbian|Windows Phone|webOS|Opera Mini|Opera Mobi|POLARIS|IEMobile|lgtelecom|nokia|SonyEricsson/i) != null || UserAgent.match(/LG|SAMSUNG|Samsung/) != null) {
isMobile = true;
} else {
isMobile = false;
}
}
var raycaster = new THREE.Raycaster();
var mouseVector = new THREE.Vector3();
function getIntersects( x, y ) {
x = ( x / window.innerWidth ) * 2 - 1;
y = - ( y / window.innerHeight ) * 2 + 1;
mouseVector.set( x, y, 0.5 );
raycaster.setFromCamera( mouseVector, camera );
return raycaster.intersectObject( group, true );
}
var selectedObject = null;
var intersects;
function onMouseMove(event) {
event.preventDefault();
mouse.x = ( (event.clientX/2) - (windowHalf.x/2) );
mouse.y = ( (event.clientY/2) - (windowHalf.y/2) );
clicked.x = ( event.clientX / window.innerWidth ) * 2 - 1;
clicked.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
// Select object
if ( selectedObject ) {
selectedObject.material.color.set( '#ffffff' );
selectedObject = null;
}
intersects = getIntersects( event.layerX, event.layerY );
if ( intersects.length > 0 ) {
var res = intersects.filter( function ( res ) {
return res && res.object;
} )[ 0 ];
if ( res && res.object ) {
selectedObject = res.object;
selectedObject.material.color.set( '#f00' );
}
}
}
function onMouseClick() {
if(intersects[0]) {
console.log(intersects[0].point);
intersects[0].object.position.z += intersects[0].distance-70;
intersects[0].object.position.x = 0;
intersects[0].object.position.y = 0;
}
}
function onResize(event) {
const width = window.innerWidth;
const height = window.innerHeight;
windowHalf.set( width / 2, height / 2 );
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
}
function onContextMenu(event) { // Mouse right click
event.preventDefault();
}
function refreshCheck() {
if(window.performance) {
if(performance.navigation.type === 1) {
setTimeout(() => {
document.body.scrollTop = 0; // Other Browser
document.documentElement.scrollTop = 0; // IE
}, 0);
}
}
}
In the onMouseWheel() function, I detect current cursor point to object or not.
So, object's information will be stored in var intersects.
Also add onMouseClick(). And inside that function, I change object's position like this.
if(intersects[0]) {
console.log(intersects[0].point);
intersects[0].object.position.z += intersects[0].distance-70;
intersects[0].object.position.x = 0;
intersects[0].object.position.y = 0;
}
So if you click the object, object's x,y,z coordinate will be changed to, 0, 0, distance-70.
But it doesn't apply to the scene.
Refer to this site https://50-jahre-hitparade.ch/
If you click the text, text will be move to front of camera.
My goal is made it like above site.
(like this)
Why it doesn't work in my code?
Any solution here?
Thanks.
(Maybe I have to update into animate()?)
Source : https://github.com/teamhide/raycast
Launch : https://teamhide.github.io/raycast/
Instead of
if(intersects[0]) {
intersects[0].point.z = 100;
intersects[0].point.x = 100;
intersects[0].point.y = 100;
}
Try changing the position of the intersects[0].object.position like this,
if(intersects[0]) {
intersects[0].object.position.z = 100;
intersects[0].object.position.x = 100;
intersects[0].object.position.y = 100;
}

THREE.JS import a blender OBJ - add material

I have a simple square plate made in Blender.
I'm trying to add a simple texture to this object. I tried so many tutorials and code I found on the net, I just cant make it happen
my code is
<html>
<style>
body{
margin: 0;
overflow: hidden;
}
</style>
<canvas id="myCanvas"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/93/three.min.js"></script>
<script src="http://threejs.org/examples/js/loaders/MTLLoader.js"></script>
<script src="http://threejs.org/examples/js/loaders/OBJLoader.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="UnpackDepthRGBAShader.js"></script>
<script src="ShadowMapViewer.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45 ,window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 5, 14);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor(0xededed);
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var loader = new THREE.TextureLoader();
var texture = loader.load( "./2.jpg" );
// it's necessary to apply these settings in order to correctly display the texture on a shape geometry
//texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 0.05, 0.05 );
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();
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total ) {
console.log( item, loaded, total );
};
var textureLoader = new THREE.TextureLoader( manager );
var textureOBJ = textureLoader.load( './1.jpg' );
var onProgress = function ( xhr ) {
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round(percentComplete, 2) + '% downloaded' );
}
};
var onError = function ( xhr ) {
console.log(xhr);
};
var roundedRectShape = new THREE.Shape();
( function roundedRect( ctx, x, y, width, height, radius ) {
ctx.moveTo( x, y + radius );
ctx.lineTo( x, y + height - radius );
ctx.quadraticCurveTo( x, y + height, x + radius, y + height );
ctx.lineTo( x + width - radius, y + height );
ctx.quadraticCurveTo( x + width, y + height, x + width, y + height - radius );
ctx.lineTo( x + width, y + radius );
ctx.quadraticCurveTo( x + width, y, x + width - radius, y );
ctx.lineTo( x + radius, y );
ctx.quadraticCurveTo( x, y, x, y + radius );
} )( roundedRectShape, 0, 0, 18.5, 18.5, 2 );
addShape( roundedRectShape, 0x008000, -1.41, 0.5, 1, Math.PI / -2, 0, 0, 0.1 );
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
var loader = new THREE.OBJLoader( manager );
loader.load( './3.obj', function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.map = textureOBJ;
}
} );
object.position.y = -0.01;
object.position.x = 0;
object.position.z = 0;
scene.add( object );
}, onProgress, onError );
controls.update();
var animate = function () {
requestAnimationFrame( animate );
renderer.render(scene, camera);
};
animate();
function addShape( shape, color, x, y, z, rx, ry, rz, s ) {
var geometry = new THREE.ShapeBufferGeometry( shape );
var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( { side: THREE.DoubleSide, map: texture } ) );
mesh.position.set( x, y, z );
mesh.rotation.set( rx, ry, rz );
mesh.scale.set( s, s, s );
scene.add( mesh );
}
</script>
I'm trying to add this simple png as the texture. anyone can help?
plate - example -> http://37.59.53.90:8080/test1.html
I've managed to create a cup with texture -> http://37.59.53.90:8080/test.html
It looks like you're using THREE.TextureLoader incorrectly.
The texture loader's load() method takes two arguments;
- the URL of the image to be loaded, and
- a callback
The callback is invoked when the texture has loaded and is ready for use.
You should restructure your code so that the texture returned in the load() methods callback can be applied to your object.
To illustrate this, a quick solution to get textures loading and displaying on your object might look like this:
var loader = new THREE.OBJLoader( manager );
// Use a callback, in a similar way to your THREE.OBJLoader
new THREE.TextureLoader( manager ).load( './1.jpg' , function(texture) {
loader.load( './3.obj', function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
// Assign the loaded texture from the enclosing THREE.TextureLoader to the child material
child.material.map = texture;
}
});
object.position.y = -0.01;
object.position.x = 0;
object.position.z = 0;
scene.add( object );
}, onProgress, onError );
})

how can i modify mesh size in my scene?

First to say, I do not speak English well.
Anyway, Let's get something straight.
I want to modify mesh(cube) size when i scroll the mouse wheel to zoomin or zoomout.
I hope to increase mesh(cube) size when zoom in and Opposite case, too.
my code is below.
<script src="../lib/Three.js/build/Three.js"></script>
<script src="http://code.jquery.com/jquery.min.js"></script>
<script>
var CANVAS_WIDTH = 400,
CANVAS_HEIGHT = 300;
var renderer = null, //웹지엘 또는 2D
scene = null, //씬 객체
camera = null; //카메라 객체
var capture = false,
start = [],
angleX = 0,
angleY = 0,
zoom = 1.0;
function initWebGL()
{
setupRenderer();
setupScene();
setupCamera();
var myColor = new THREE.Color( 0xff0000 );
myColor.setRGB(0.0, 1.0, 0.0);
var alpha = 1.0;
renderer.setClearColor(myColor, alpha);
(function animLoop(){
//camera zoom in and zomm out
renderer.render(scene, camera);
requestAnimationFrame( animLoop );
})();
/**
mouse event code for screen control about zoom, rotate
**/
$(document).ready(function() {
console.log($("#my-canvas").length);
$("#my-canvas").on("mousedown", function(e) {
capture = true;
start = [e.pageX, e.pageY];
console.log("start:" + start);
});
$("#my-canvas").on("mouseup", function(e) {
console.log(e.type);
capture = false;
console.log("end capture");
});
$("#my-canvas").mousemove(function(e) {
console.log(e.type);
if (capture)
{
var x = (e.pageX - start[0]);
var y = (e.pageY - start[1]);
//시작위치 업데이트
start[0] = e.pageX;
start[1] = e.pageY;
angleX += x;
angleY += y;
//console.log()
}
});
});
$(document).ready(function(evt) {
$("#my-canvas").on("mousewheel", function (e) {
adjustZoom(window.event.wheelData);
}).on("DOMMouseScroll", function (e) {
//파이어폭스
adjustZoom(e.originalEvent.detail * -1.0);
});
});
function adjustZoom(delta) {
if(delta > 0)
{
zoom += 0.1;
} else {
zoom -= 0.1;
if(zoom < 0.01) { zoom = 0.1;}
}
}
}
function setupRenderer()
{
renderer = new THREE.WebGLRenderer({canvas: document.createElement( 'canvas')});
renderer.setSize( CANVAS_WIDTH, CANVAS_HEIGHT );
$(renderer.domElement).attr('id','my-canvas');
//캔버스 엘리먼트를 추가하는 곳
document.body.appendChild( renderer.domElement );
}
function setupScene()
{
scene = new THREE.Scene();
addMesh();
addLight();
}
function setupCamera()
{
camera = new THREE.PerspectiveCamera(
35, //시야
CANVAS_WIDTH / CANVAS_HEIGHT, //종횡비
.1, //전방 절단면
10000 //후방 절단면
);
camera.position.set(-15, 10, 10);
camera.lookAt( scene.position );
scene.add( camera );
}
function addMesh()
{
var cube = new THREE.Mesh(
new THREE.CubeGeometry( 5, 7, 5 ),
new THREE.MeshLambertMaterial( { color: 0x0000FF} )
);
scene.add(cube);
}
function addLight()
{
var light = new THREE.PointLight( 0xFFFFFF );
light.position.set( 20, 20, 20 );
scene.add(light);
}
</script>
You wish to modify the scale value of the object. This can be done for each axis.
Each mesh object has a scale value as a vector.
So this would
mesh.scale.set( 2, 1, 1 )
Or in your case
cube.scale.set();
You can also access it this way,
cube.scale.x = 2.0;
Though the cube object is stored locally, you might want to set the globally and alter this value with the mouse action.
Hope that well.
As a note, the question provides a bit too much of the script, shorter and faster to the point is better.

Resources