How to add texture to BufferGeometry faces.? - javascript

I have created a bufferGeometry , which consist of 5 planes (100x25) with two triangles each.
function createGeometry() {
var geometry = new THREE.PlaneGeometry(100, 25, 1);
return geometry;
}
function createScene() {
var bufferGeometry = new THREE.BufferGeometry();
var radius = 125;
var count = 5;
var positions = [];
var normals = [];
var colors = [];
var vector = new THREE.Vector3();
var color = new THREE.Color( 0xffffff );
var heartGeometry = createGeometry();
var geometry = new THREE.Geometry();
var step = 0;
for ( var i = 1, l = count; i <= l; i ++ ) {
geometry.copy( heartGeometry );
const y = i * 30
geometry.translate(-100, y, 0);
// color.setHSL( ( i / l ), 1.0, 0.7 );
geometry.faces.forEach( function ( face ) {
positions.push( geometry.vertices[ face.a ].x );
positions.push( geometry.vertices[ face.a ].y );
positions.push( geometry.vertices[ face.a ].z );
positions.push( geometry.vertices[ face.b ].x );
positions.push( geometry.vertices[ face.b ].y );
positions.push( geometry.vertices[ face.b ].z );
positions.push( geometry.vertices[ face.c ].x );
positions.push( geometry.vertices[ face.c ].y );
positions.push( geometry.vertices[ face.c ].z );
normals.push( face.normal.x );
normals.push( face.normal.y );
normals.push( face.normal.z );
normals.push( face.normal.x );
normals.push( face.normal.y );
normals.push( face.normal.z );
normals.push( face.normal.x );
normals.push( face.normal.y );
normals.push( face.normal.z );
colors.push( color.r );
colors.push( color.g );
colors.push( color.b );
colors.push( color.r );
colors.push( color.g );
colors.push( color.b );
colors.push( color.r );
colors.push( color.g );
colors.push( color.b );
});
}
bufferGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
bufferGeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
bufferGeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
var material = new THREE.MeshBasicMaterial({
vertexColors: THREE.VertexColors,
side: THREE.FrontSide
});
var mesh = new THREE.Mesh( bufferGeometry, material );
scene.add( mesh );
}
Now instead of coloring each plane how can i add a text to each plane. Say i just want to display 1,2,3,4,5 at the center of each plane.
What I know is the following has to be done to add the texture.
Generate texture from canvas
Change the material to Shader Material with map:texture
Add uvs to bufferGeometry.
But what is the relation between uvs and texture.
I have the texture creating function
//not sure for each character or one texture as a single texture
function createTexture(ch){
var fontSize = 20;
var c = document.createElement('canvas');
c.width = 100;
c.height = 25;
var ctx = c.getContext('2d');
ctx.font = fontSize+'px Monospace';
ctx.fillText(ch, c.width/2, c.height/2);
var texture = new THREE.Texture(c);
texture.flipY = false;
texture.needsUpdate = true;
return texture;
}
Full DEMO Code
EDIT
I am considering performance as high priority for this experiment. We can add each mesh for each text, but that will increase the number of mesh in screen and reduce performance. I am looking for any idea with a single mesh as in my example.
The closest I found is this, but i didn't understood the exact technique they are using.

You've to copy the first uv channel of the .faceVertexUvs property form the THREE.Geometry, similar as you do it with the vertex coordinates and normal vectors:
for ( var i = 1, l = count; i <= l; i ++ ) {
geometry.copy( heartGeometry );
const y = i * 30
geometry.translate(-100, y, 0);
geometry.faces.forEach( function ( face ) {
let f = [face.a, face.b, face.c];
for (let i=0; i < 3; ++i) {
positions.push( ...geometry.vertices[f[i]].toArray() );
normals.push( ...face.normal.toArray() );
colors.push( ...color.toArray() );
}
} );
geometry.faceVertexUvs[0].forEach( function ( faceUvs ) {
for (let i=0; i < 3; ++i) {
uv.push( ...faceUvs[i].toArray() );
}
} );
}
If you want to define multiple textures for one geometry, then you've to use multiple THREE.Materials for one THREE.Mesh.
Define groups (see .addGroup) for the THREE.BufferGeometry. Each group associates a range of vertices to a material.
var bufferGeometry = new THREE.BufferGeometry();
bufferGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
bufferGeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
bufferGeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
bufferGeometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( uv, 2 ) );
let materials = []
let v_per_group= positions.length / 3 / count;
for ( var i = 0; i < count; i ++ ) {
bufferGeometry.addGroup(i * v_per_group, v_per_group, i);
let material = new THREE.MeshBasicMaterial({
vertexColors: THREE.VertexColors,
side: THREE.FrontSide,
map : createTexture("button" + (i+1))
});
materials.push(material);
}
var mesh = new THREE.Mesh( bufferGeometry, materials );
scene.add( mesh );
var camera, scene, renderer, controls, stats;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45.0, window.innerWidth / window.innerHeight, 100, 1500.0 );
camera.position.z = 480.0;
scene.add( camera );
controls = new THREE.TrackballControls( camera, renderer.domElement );
controls.minDistance = 100.0;
controls.maxDistance = 800.0;
controls.dynamicDampingFactor = 0.1;
scene.add( new THREE.AmbientLight( 0xffffff, 1 ) );
createScene();
//stats = new Stats();
//document.body.appendChild( stats.dom );
window.addEventListener( 'resize', onWindowResize, false );
}
function createGeometry() {
var geometry = new THREE.PlaneGeometry(100, 25, 1);
return geometry;
}
function createTexture(ch){
var fontSize = 20;
var c = document.createElement('canvas');
c.width = 128;
c.height = 32;
var ctx = c.getContext('2d');
ctx.beginPath();
ctx.rect(0, 0, 128, 32);
ctx.fillStyle = "white";
ctx.fill();
ctx.fillStyle = "black";
ctx.font = fontSize+'px Monospace';
ctx.fillText(ch, 20, 24);
var texture = new THREE.Texture(c);
texture.flipY = true;
texture.needsUpdate = true;
return texture;
}
function createScene() {
var radius = 125;
var count = 5;
var vector = new THREE.Vector3();
var color = new THREE.Color( 0xffffff );
var heartGeometry = createGeometry();
var geometry = new THREE.Geometry();
var positions = [];
var normals = [];
var colors = [];
var uv = [];
for ( var i = 1, l = count; i <= l; i ++ ) {
geometry.copy( heartGeometry );
const y = i * 30
geometry.translate(-100, y, 0);
geometry.faces.forEach( function ( face ) {
let f = [face.a, face.b, face.c];
for (let i=0; i < 3; ++i) {
positions.push( ...geometry.vertices[f[i]].toArray() );
normals.push( ...face.normal.toArray() );
colors.push( ...color.toArray() );
}
} );
geometry.faceVertexUvs[0].forEach( function ( faceUvs ) {
for (let i=0; i < 3; ++i) {
uv.push( ...faceUvs[i].toArray() );
}
} );
}
var bufferGeometry = new THREE.BufferGeometry();
bufferGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
bufferGeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
bufferGeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
bufferGeometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( uv, 2 ) );
let materials = []
let v_per_group = positions.length / 3 / count;
for ( var i = 0; i < count; i ++ ) {
bufferGeometry.addGroup(i * v_per_group, v_per_group, i);
let material = new THREE.MeshBasicMaterial({
vertexColors: THREE.VertexColors,
side: THREE.FrontSide,
map : createTexture("button" + (i+1))
});
materials.push(material);
}
var mesh = new THREE.Mesh( bufferGeometry, materials );
scene.add( mesh );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
//stats.update();
renderer.render( scene, camera );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>

Related

How can i move the "camera" of the canvas in HTML?

I'm making a 3D game which guides you across skyboxes, and what I need to do is for it to detect when the user presses a key, and move the camera that way (I'm fine with standard WASD).
How could I do this?
JavaScript:
var world = document.getElementById("boxDiv");
var x;
var y;
document.addEventListener('mousemove', function (e)
{
x = e.clientX;
y = e.clientY;
y = -y;
world.style.transform = "translateZ(600px) rotateX("+y+"deg) rotateY("+x+"deg)";
});
This code is for the skybox generation.
I think this is one of the best minimal reproducible examples on WASD controls on three.js
Kudos for the author Fyrestar
Relevant code is below:
// author: Fyrestar <info#mevedia.com>
var camera, scene, renderer, mesh, goal, keys, follow;
var time = 0;
var newPosition = new THREE.Vector3();
var matrix = new THREE.Matrix4();
var stop = 1;
var DEGTORAD = 0.01745327;
var temp = new THREE.Vector3;
var dir = new THREE.Vector3;
var a = new THREE.Vector3;
var b = new THREE.Vector3;
var coronaSafetyDistance = 0.3;
var velocity = 0.0;
var speed = 0.0;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.set( 0, .3, 0 );
scene = new THREE.Scene();
camera.lookAt( scene.position );
var geometry = new THREE.BoxBufferGeometry( 0.2, 0.2, 0.2 );
var material = new THREE.MeshNormalMaterial();
mesh = new THREE.Mesh( geometry, material );
goal = new THREE.Object3D;
follow = new THREE.Object3D;
follow.position.z = -coronaSafetyDistance;
mesh.add( follow );
goal.add( camera );
scene.add( mesh );
var gridHelper = new THREE.GridHelper( 40, 40 );
scene.add( gridHelper );
scene.add( new THREE.AxesHelper() );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
keys = {
a: false,
s: false,
d: false,
w: false
};
document.body.addEventListener( 'keydown', function(e) {
const key = e.code.replace('Key', '').toLowerCase();
if ( keys[ key ] !== undefined )
keys[ key ] = true;
});
document.body.addEventListener( 'keyup', function(e) {
const key = e.code.replace('Key', '').toLowerCase();
if ( keys[ key ] !== undefined )
keys[ key ] = false;
});
}
function animate() {
requestAnimationFrame( animate );
speed = 0.0;
if ( keys.w )
speed = 0.01;
else if ( keys.s )
speed = -0.01;
velocity += ( speed - velocity ) * .3;
mesh.translateZ( velocity );
if ( keys.a )
mesh.rotateY(0.05);
else if ( keys.d )
mesh.rotateY(-0.05);
a.lerp(mesh.position, 0.4);
b.copy(goal.position);
dir.copy( a ).sub( b ).normalize();
const dis = a.distanceTo( b ) - coronaSafetyDistance;
goal.position.addScaledVector( dir, dis );
goal.position.lerp(temp, 0.02);
temp.setFromMatrixPosition(follow.matrixWorld);
camera.lookAt( mesh.position );
renderer.render( scene, camera );
}

Three.js collision detection

I think I'm missing something very basic, but I can't find an answer, nor in documentation or other, working codes.
I'm making something like a basic museum using THREE.js libraries. I've set up most stuff, but I want to give the camera a collision. I made it like that :
var d = camera.position.distanceTo( plane_8.position );
if ( d < 200 )
{
camera.position = previousPosition;
camera.rotation = previousRotation;
}
Simple, but should work, at least against one wall. But it doesn't. What have I forgotten ?
Full code:
<html>
<head>
<title>#10 - WebGL - Three.js</title>
<style>canvas { width: 100%; height: 100% }</style>
</head>
<body>
<script src="js/three.js"></script>
<script src="js/THREEx.KeyboardState.js"></script>
<script>
var keyboard = new THREEx.KeyboardState();
var clock = new THREE.Clock();
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 4096 );
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
camera.position.set(0,0,1900);
scene.fog = new THREE.Fog( 0x555555, 2048, 4096 );
//=================================================================
var texture = THREE.ImageUtils.loadTexture('img/grass.jpg');
texture.repeat.set( 7,7);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.anisotropy = 16;
var textureW = THREE.ImageUtils.loadTexture('img/Brickwall.jpg');
textureW.repeat.set( 1,1);
textureW.wrapS = THREE.RepeatWrapping;
textureW.wrapT = THREE.RepeatWrapping;
textureW.anisotropy = 16;
var textureS = THREE.ImageUtils.loadTexture('img/styropian.jpeg');
textureS.repeat.set( 1,1);
textureS.wrapS = THREE.RepeatWrapping;
textureS.wrapT = THREE.RepeatWrapping;
textureS.anisotropy = 16;
//Mona Lisa
var textureM = THREE.ImageUtils.loadTexture('img/MonaLisa.jpg');
textureM.anisotropy = 16;
var planeMaterialM = new THREE.MeshPhongMaterial({map: textureM});
var planeGeometryM = new THREE.PlaneGeometry(385, 577);
var planeM = new THREE.Mesh( planeGeometryM, planeMaterialM );
planeM.position.x -= 500;
planeM.position.z -= 1000;
scene.add( planeM );
var planeMaterial = new THREE.MeshPhongMaterial({map: texture});
var planeGeometry = new THREE.PlaneGeometry(8192, 8192);
var plane = new THREE.Mesh( planeGeometry, planeMaterial );
plane.rotation.x = - Math.PI / 2;
plane.position.y -= 512;
plane.position.z -= 512;
scene.add( plane );
var planeMaterial_2 = new THREE.MeshPhongMaterial({color: 0x999999});
var planeGeometry_2= new THREE.CubeGeometry( 8192, 8, 4096 );
var plane_2 = new THREE.Mesh( planeGeometry_2, planeMaterial_2 );
plane_2.position.y += 512;
plane_2.position.z += 1024;
scene.add( plane_2 );
var planeMaterial_3 = new THREE.MeshPhongMaterial({map:textureW});
var planeGeometry_3= new THREE.CubeGeometry( 4096, 1024, 8 );
var plane_3 = new THREE.Mesh( planeGeometry_3, planeMaterial_3 );
plane_3.position.z -= 1024;
scene.add( plane_3 );
var planeMaterial_4 = new THREE.MeshPhongMaterial({map:textureW});
var planeGeometry_4= new THREE.CubeGeometry( 60,1024,2048 );
var plane_4 = new THREE.Mesh( planeGeometry_4, planeMaterial_4 );
plane_4.position.x -= 2048;
scene.add( plane_4 );
var plane_5 = new THREE.Mesh( planeGeometry_4, planeMaterial_4 );
plane_5.position.x -= 1024;
scene.add( plane_5);
var plane_6 = new THREE.Mesh( planeGeometry_4, planeMaterial_4 );
plane_6.position.x -= 0;
scene.add( plane_6);
var plane_7 = new THREE.Mesh( planeGeometry_4, planeMaterial_4 );
plane_7.position.x += 1024;
scene.add( plane_7);
var plane_8 = new THREE.Mesh( planeGeometry_4, planeMaterial_4 );
plane_8.position.x += 2048;
scene.add( plane_8);
var planeMaterial_C = new THREE.MeshPhongMaterial({map:textureW});
var planeGeometry_C= new THREE.CubeGeometry( 5120, 1024, 60 );
var plane_C = new THREE.Mesh( planeGeometry_C, planeMaterial_C );
plane_C.position.z =+ 2048;
plane_C.position.x =+ 512;
scene.add( plane_C );
var cubeGeometry = new THREE.CubeGeometry(50,50,50,1,1,1);
var wireMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe:true } );
MovingCube = new THREE.Mesh( cubeGeometry, wireMaterial );
MovingCube.position.set(0, -100, 1900);
scene.add( MovingCube );
var light = new THREE.AmbientLight( 0x101020 );
scene.add(light);
var pointLight = new THREE.PointLight( 0xffffff, 1, 2048 );
pointLight.position.set( -512, 0, -512 );
scene.add( pointLight );
var pointLight2 = new THREE.PointLight( 0xffffff, 1, 3000 );
pointLight2.position.set( 0, 0, 1536 );
scene.add( pointLight2 );
var pointLight3 = new THREE.PointLight( 0xffffff, 1, 2048 );
pointLight3.position.set( 512, 0, -512 );
scene.add( pointLight3 );
var kat=0;
var katL=0;
function render() {
requestAnimationFrame(render);
kat += 0.02;
katL += 0.07;
var delta = clock.getDelta();
var moveDistance = 700 * delta;
var rotateAngle = Math.PI / 3.5 * delta;
var previousPosition = camera.position.clone();
var previousRotation = camera.rotation.clone();
if ( keyboard.pressed("W") )
camera.translateZ( -moveDistance );
if ( keyboard.pressed("S") )
camera.translateZ( moveDistance );
if ( keyboard.pressed("Q") )
camera.translateX( -moveDistance );
if ( keyboard.pressed("E") )
camera.translateX( moveDistance );
if ( keyboard.pressed("A") )
camera.rotateOnAxis( new THREE.Vector3(0,1,0), rotateAngle);
if ( keyboard.pressed("D") )
camera.rotateOnAxis( new THREE.Vector3(0,1,0), -rotateAngle);
var d = camera.position.distanceTo( plane_8.position );
if ( d < 200 )
{
camera.position = previousPosition;
camera.rotation = previousRotation;
}
renderer.render(scene, camera);
}
render();
</script>
</body>
I'm currently developing collisions for my project. Try using raycasts. My player (which i can cantrol by WSAD and mouse) emmits raycasts and check wheater they hits any objects.
Part of the code:
this.update = function (timestamp) {
if (!this.enabled) return;
if (this.hitTest) {
this.doHitTest();
}
camera.quaternion.multiplyQuaternions(this.angleQuaternion, camera.quaternion);
setFromQuaternionYComponent(this.object.quaternion, camera.quaternion);
var delta = (timestamp - lastTimestamp) / 1000;
lastTimestamp = timestamp;
var actualMoveSpeed = delta * this.movementSpeed;
if (this.moveForward && !lockMoveForward) this.object.translateZ(-actualMoveSpeed);
if (this.moveBackward && !lockMoveBackward) this.object.translateZ(actualMoveSpeed);
if (this.moveLeft && !lockMoveLeft) this.object.translateX(-actualMoveSpeed);
if (this.moveRight && !lockMoveRight) this.object.translateX(actualMoveSpeed);
if (this.verticalMovement && this.moveUp) this.object.translateY(actualMoveSpeed);
if (this.verticalMovement && this.moveDown) this.object.translateY(-actualMoveSpeed);
var hasPosition = this.sensor && this.sensor.getState().hasPosition;
var vrCameraPosition;
if (hasPosition) {
vrCameraPosition = camera.position.clone();
vrCameraPosition.applyQuaternion(this.angleQuaternion);
}
if (hasPosition) {
camera.position.add(vrCameraPosition);
} else {
//camera.position.copy(this.object.position);
camera.position.set(this.object.position.x, camera.position.y, this.object.position.z);
}
};
this.doHitTest = function () {
this.unlockAllDirections();
var hitObjects = [];
var cameraDirection = this.getDirection2(new THREE.Vector3(0, 0, 0)).clone();
for (var i = 0; i < 4; i++) {
// Applying rotation for each direction:
var direction = cameraDirection.clone();
direction.applyMatrix4(rotationMatrices[i]);
var rayCaster = new THREE.Raycaster(camera.position, direction);
var intersects = rayCaster.intersectObjects(this.hitMeshesArray, true);
if ((intersects.length > 0 && intersects[0].distance < hitTestDistance)) {
this.lockDirectionByIndex(i);
hitObjects.push(intersects[0]);
// console.log(intersects[0].object.name, i);
}
}
return hitObjects;
};
this.getDirection2 = function (v) {
var direction = new THREE.Vector3(0, 0, -1);
var rotation = new THREE.Euler(0, 0, 0, "YXZ");
var rx = camera.rotation.x;
var ry = camera.rotation.y;
// console.log("DIRECTION:", this);
rotation.set(rx, ry, 0);
v.copy(direction).applyEuler(rotation);
// console.log(v);
return v;
};
Try putting all on jsbin or simillar so we can check it.

Rotate the mergeometry object at its center in Three.js

I am struggling to find the way to rotate the object at its center. At the moment i am able to rotate the scene, but when i do the rotation, the object goes away from the user. I look into the some the already asked questions in the same line on the forum, but couldn't able to get it work. Below is the part of the html/three.js file i am using /attached you will find the complete working example.Any help is greatly appreciated
<script src="../build/three.min.js"></script>
<script src="js/controls/TrackballControls.js"></script>
<script src="js/libs/stats.min.js"></script>
<script>
var container, stats;
var camera, controls, scene, renderer;
var pickingData = [], pickingTexture, pickingScene;
var objects = [];
var highlightBox;
var splitCoord;
var avStdProp;
var mouse = new THREE.Vector2();
var offset = new THREE.Vector3( 10, 10, 10 );
var geom = new THREE.BoxGeometry(0.005, 0.005, 0.005 );
geom.colorsNeedUpdate = true;
init();
animate();
function init() {
container = document.getElementById( "container" );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.x=250;
camera.position.y=300;
camera.position.z=400;
renderer = new THREE.WebGLRenderer( { antialias: true } );
controls = new THREE.TrackballControls(camera);
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 4;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
scene = new THREE.Scene();
pickingScene = new THREE.Scene();
pickingTexture = new THREE.WebGLRenderTarget(800, 800);
pickingTexture.minFilter = THREE.LinearFilter;
pickingTexture.generateMipmaps = false;
scene.add( new THREE.AmbientLight( 0x555555 ) );
var light = new THREE.SpotLight( 0xffffff, 1.5 );
light.position.set( 0, 500, 2000 );
scene.add( light );
var geometry = new THREE.Geometry(),
pickingGeometry = new THREE.Geometry(),
pickingMaterial = new THREE.MeshBasicMaterial( { vertexColors: THREE.VertexColors } ),
defaultMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff, shading: THREE.FlatShading, vertexColors: THREE.VertexColors } );
function applyVertexColors( g, c ) {
g.faces.forEach( function( f ) {
var n = ( f instanceof THREE.Face3 ) ? 3 : 4;
for( var j = 0; j < n; j ++ ) {
f.vertexColors[ j ] = c;
}
} );
}
var color = new THREE.Color();
var matrix = new THREE.Matrix4();
var quaternion = new THREE.Quaternion();
var coord="219_163_189;130_173_179;161_113_231;92_103_176;169_193_180;161_165_187;262_163_166;198_143_155;161_189_155;125_121_107";
splitCoord=coord.split(";");
var coordColr="0_255_255;255_255_0;0_0_255;0_255_0;255_255_0;0_255_0;0_0_255;0_255_255;255_255_0;210_210_45";
var splitCoordColor=coordColr.split(";");
var avgStd="1_0;3_0;0_0;2_0;3_0;2_0;0_0;1_0;3_0;3_0.35";
avStdProp=avgStd.split(";");
for ( var i = 0; i < splitCoord.length; i++ ) {
var position = new THREE.Vector3();
var xyz=splitCoord[i].split("_");
var col=splitCoordColor[i].split("_");
position.x = xyz[0];
position.y = xyz[1];
position.z = xyz[2];
var rotation = new THREE.Euler();
rotation.x = 0
rotation.y = 0;
rotation.z = 0;
var scale = new THREE.Vector3();
scale.x = 200 + 100;
scale.y = 200 + 100;
scale.z = 200 + 100;
quaternion.setFromEuler( rotation, false );
matrix.compose( position, quaternion, scale );
// give the geom's vertices a random color, to be displayed
col[0]=col[0]/255;
col[1]=col[1]/255;
col[2]=col[2]/255;
applyVertexColors(geom, color.setRGB(col[0], col[1], col[2]));
geometry.merge( geom, matrix );
// give the geom's vertices a color corresponding to the "id"
applyVertexColors( geom, color.setHex( i ) );
pickingGeometry.merge( geom, matrix );
pickingData[ i ] = {
position: position,
rotation: rotation,
scale: scale
};
}
var drawnObject = new THREE.Mesh( geometry, defaultMaterial );
scene.add( drawnObject );
pickingScene.add( new THREE.Mesh( pickingGeometry, pickingMaterial ) );
highlightBox = new THREE.Mesh(
new THREE.BoxGeometry( 0.009, 0.009, 0.009 ),
new THREE.MeshLambertMaterial( { color: 0xffffff }
) );
scene.add( highlightBox );
//renderer.setClearColor( 0xffffff );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(800,800);
renderer.sortObjects = false;
container.appendChild( renderer.domElement );
renderer.domElement.addEventListener( 'mousemove', onMouseMove );
}
//
function onMouseMove( e ) {
mouse.x = e.clientX;
mouse.y = e.clientY;
}
function pick() {
//render the picking scene off-screen
renderer.render( pickingScene, camera, pickingTexture );
//create buffer for reading single pixel
var pixelBuffer = new Uint8Array( 4 );
//read the pixel under the mouse from the texture
renderer.readRenderTargetPixels(pickingTexture, mouse.x+window.pageXOffset, pickingTexture.height - (mouse.y+window.pageYOffset), 1, 1, pixelBuffer);
//interpret the pixel as an ID
var id = ( pixelBuffer[0] << 16 ) | ( pixelBuffer[1] << 8 ) | ( pixelBuffer[2]);
var data = pickingData[ id ];
if (data) {
//move our highlightBox so that it surrounds the picked object
if (data.position && data.rotation && data.scale && controls.enabled){
highlightBox.position.copy( data.position );
highlightBox.rotation.copy( data.rotation );
highlightBox.scale.copy( data.scale ).add( offset );
highlightBox.visible = true;
}
}
else {
highlightBox.visible = false;
}
}
function animate() {
requestAnimationFrame( animate );
render();
//stats.update();
}
function render() {
controls.update();
pick();
renderer.render(scene, camera);
}
any help?
You can set your objects geometry to center, so the center of the mesh will then be at position (0,0,0) and it wont "move away" while rotating.
Do it like this:
geometry.center();
var drawnObject = new THREE.Mesh( geometry, defaultMaterial );
scene.add( drawnObject );
Update
Because you want to use picking in an unusual way by saving your geometrys coordinates into an array, centering the geometry doesnt help you. Your question was "Rotate the mergeometry object at its center", but it seems like you want to rotate the camera around your geometrys center.
Calculate the bounding sphere of your geometry and set the controls target to its position:
drawnObject.geometry.computeBoundingSphere();
controls.target = drawnObject.geometry.boundingSphere.center;

Clickable Three JS Convex Objects (once clicked reveals image)

I adjusted an example from the three js website.
I'm looking for making the small floating objects have a click event.
The click event would trigger an image or video revealed on the larger convex shape in the center
Concept + Images
http://kevinwitkowski.tumblr.com/post/109592122645/workshop-update
Working Sample
Here is my current code.
var container;
var camera, scene, renderer;
var mesh;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
// array of functions for the rendering loop
var onRenderFcts= [];
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2( 0xd6e3e8, 0.0030 );
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 1000);
camera.position.z = 0;
controls = new THREE.OrbitControls(camera)
var light, object, materials;
light = new THREE.DirectionalLight( 0xe8dbd6 );
light.position.set( -50, -80, -10 );
scene.add( light );
light = new THREE.DirectionalLight( 0xd6dae8 );
light.position.set( 20, 120, 1 );
scene.add( light );
light = new THREE.DirectionalLight( 0xd6e8e4 );
light.position.set( 0, 1, 30 );
scene.add( light );
var map = THREE.ImageUtils.loadTexture( 'textures/1.jpeg' );
map.wrapS = map.wrapT =
THREE.RepeatWrapping;
map.anisotropy = 16;
var materials = [
new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.FlatShading, vertexColors: THREE.VertexColors } )
//new THREE.MeshBasicMaterial( { color: 0x00000, shading: THREE.FlatShading, wireframe: true, transparent: false, opacity: 0.5} )
];
// random convex 1
points = [];
for ( var i = 0; i < 30; i ++ ) {
points.push( randomPointInSphere( 50 ) );
}
object = THREE.SceneUtils.createMultiMaterialObject( new THREE.ConvexGeometry( points ), materials );
object.position.set( 0, 0, 0);
scene.add( object );
// random convex 2
points = [];
for ( var i = 0; i < 30; i ++ ) {
points.push( randomPointInSphere( 15 ) );
}
object = THREE.SceneUtils.createMultiMaterialObject( new THREE.ConvexGeometry( points ), materials );
object.position.set( 15, 50, -60 );
scene.add( object );
// random convex 3
points = [];
for ( var i = 0; i < 30; i ++ ) {
points.push( randomPointInSphere( 15 ) );
}
object = THREE.SceneUtils.createMultiMaterialObject( new THREE.ConvexGeometry( points ), materials );
object.position.set( 30, 10, 80 );
scene.add( object );
// random convex 4
points = [];
for ( var i = 0; i < 30; i ++ ) {
points.push( randomPointInSphere( 8 ) );
}
object = THREE.SceneUtils.createMultiMaterialObject( new THREE.ConvexGeometry( points ), materials );
object.position.set( -80, -50, 20 );
scene.add( object );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setClearColor( 0xf5f5f5 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//
window.addEventListener( 'resize', onWindowResize, true );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
mouseX = ( event.clientX - windowHalfX );
mouseY = ( event.clientY - windowHalfY );
}
//
function randomPointInSphere( radius ) {
return new THREE.Vector3(
( Math.random() - 0.5 ) * 1 * radius,
( Math.random() - 0.5 ) * 2 * radius,
( Math.random() - 0.5 ) * 2 * radius
);
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
var timer = Date.now() * 0.00005;
camera.position.x = Math.cos( timer ) * 300;
camera.position.z = Math.sin( timer ) * 300;
camera.lookAt( scene.position );
for ( var i = 0, l = scene.children.length; i < l; i ++ ) {
var object = scene.children[ i ];
object.rotation.x = timer * 1;
object.rotation.y = timer * 3;
}
// handle window resize
window.addEventListener('resize', function(){
renderer.setSize( window.innerWidth, window.innerHeight )
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
}, true)
renderer.render( scene, camera );
}
var lastTimeMsec= null
requestAnimationFrame(function animate(nowMsec){
// keep looping
requestAnimationFrame( animate );
// measure time
lastTimeMsec = lastTimeMsec || nowMsec-1000/60
var deltaMsec = Math.min(200, nowMsec - lastTimeMsec)
lastTimeMsec = nowMsec
// call each update function
onRenderFcts.forEach(function(onRenderFct){
onRenderFct(deltaMsec/1000, nowMsec/1000)
})
})
The normal way of doing this is using a THREE.Raycaster and THREE.Projector to cast a ray from the camera through space, then finding if an object intersects with this ray.
See this example: http://soledadpenades.com/articles/three-js-tutorials/object-picking/
Thankfully, others have implemented libraries such as ObjectControls: https://github.com/cabbibo/ObjectControls
This allows you to directly attach hover or select events to meshes and it will just work.
CreateMultiMaterialObject method creates an object3D, so when you click, it is necessary to specify the second parameter (recursion) = true:
var intersects = raycaster.intersectObjects( objects, true );
if ( intersects.length > 0 ) {
intersects[ 0 ].object.material.color.setHex( Math.random() * 0xffffff );
}

Three.js - how to detect what shape was selected? after drag

I made a canvas with shapes in it...the shapes are draggable.
Everything seems to work fine...But now I'm trying to figure out
how can I detect what shape was selected/dragged?
this is my code: (Javascript)
var container, stats;
var camera, scene, projector, renderer;
var objects = [], plane;
var mouse = new THREE.Vector2(),
offset = new THREE.Vector3(),
INTERSECTED, SELECTED;
var basic_x_dist = 0;
var cameraX = 0,cameraY = 0,cameraZ = 100; // default-same as camera.position.z!
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 500 );
camera.position.z = 300;
scene = new THREE.Scene();
scene.add( new THREE.AmbientLight( 0x505050 ) );
var light = new THREE.SpotLight( 0xffffff, 1.5 );
light.position.set( 0, 500, 2000 );
light.castShadow = true;
scene.add( light );
var geometry = new THREE.CubeGeometry( 7, 7, 1, 3, 3, 1);
for ( var i = 0; i < 5; i ++ ) {
var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { map: THREE.ImageUtils.loadTexture( 'red.png' ) } ) );
//object.material.ambient = object.material.color;
object.position.x = basic_x_dist;
basic_x_dist += 10;
//object.position.x = Math.random() * 100 - 50;
//object.position.y = Math.random() * 60 - 30;
//object.position.z = Math.random() * 80 - 40;
//object.rotation.x = ( Math.random() * 360 ) * Math.PI / 180;
//object.rotation.y = ( Math.random() * 360 ) * Math.PI / 180;
//object.rotation.z = ( Math.random() * 360 ) * Math.PI / 180;
//object.scale.x = Math.random() * 2 + 1;
//object.scale.y = Math.random() * 2 + 1;
//object.scale.z = Math.random() * 2 + 1;
//object.castShadow = true;
//object.receiveShadow = true;
scene.add( object );
objects.push( object );
}
plane = new THREE.Mesh( new THREE.PlaneGeometry( 2000, 2000, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0x000000, opacity: 0.25, transparent: true, wireframe: true } ) );
plane.lookAt( camera.position );
plane.visible = false;
scene.add( plane );
projector = new THREE.Projector();
renderer = new THREE.CanvasRenderer();
renderer.sortObjects = false;
renderer.setSize( window.innerWidth, window.innerHeight );
//renderer.shadowMapEnabled = true;
//renderer.shadowMapSoft = true;
//renderer.shadowCameraNear = 3;
//renderer.shadowCameraFar = camera.far;
//renderer.shadowCameraFov = 50;
//renderer.shadowMapBias = 0.0039;
//renderer.shadowMapDarkness = 0.5;
//renderer.shadowMapWidth = 1024;
//renderer.shadowMapHeight = 1024;
container.appendChild( renderer.domElement );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'three.js webgl - draggable cubes';
container.appendChild( info );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
renderer.domElement.addEventListener( 'mousemove', onDocumentMouseMove, false );
renderer.domElement.addEventListener( 'mousedown', onDocumentMouseDown, false );
renderer.domElement.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.onkeypress=key_event;
}
function onDocumentMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
if ( SELECTED ) {
var intersects = ray.intersectObject( plane );
SELECTED.position.copy( intersects[ 0 ].point.subSelf( offset ) );
return;
}
var intersects = ray.intersectObjects( objects );
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
if ( INTERSECTED ) INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
INTERSECTED = intersects[ 0 ].object;
INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
plane.position.copy( INTERSECTED.position );
}
container.style.cursor = 'pointer';
} else {
if ( INTERSECTED ) INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
INTERSECTED = null;
container.style.cursor = 'auto';
}
}
function onDocumentMouseDown( event ) {
event.preventDefault();
var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
var intersects = ray.intersectObjects( objects );
if ( intersects.length > 0 ) {
SELECTED = intersects[ 0 ].object;
var intersects = ray.intersectObject( plane );
offset.copy( intersects[ 0 ].point ).subSelf( plane.position );
container.style.cursor = 'move';
}
}
function onDocumentMouseUp( event ) {
event.preventDefault();
if ( INTERSECTED ) {
plane.position.copy( INTERSECTED.position );
SELECTED = null;
}
container.style.cursor = 'auto';
}
function rotateLeft(){
cameraX += 5;
}
function rotateRight(){
cameraX -= 5;
}
function rotateUp(){
cameraY += 5;
}
function rotateDown(){
cameraY -= 5;
}
function zoomIn(){
cameraZ += 5;
}
function zoomOut(){
cameraZ -= 5;
}
function showPositions(){
for(var i=0; i<5; i++){
alert(objects[i].position.x);
alert(objects[i].position.y);
alert(objects[i].position.z);
}
}
function key_event( event ) {
var unicode=event.keyCode? event.keyCode : event.charCode;
//alert(unicode); // find the char code
switch(unicode){
case 97: rotateLeft(); break;
case 100: rotateRight(); break;
case 119: rotateUp(); break;
case 120: rotateDown(); break;
case 122: zoomIn(); break;
case 99: zoomOut(); break;
case 115: showPositions(); break;
}
}
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
camera.position.x = cameraX; // updating the camera view-x scale after events
camera.position.y = cameraY; // updating the camera view-y scale after events
camera.position.z = cameraZ; // updating the camera view-z scale after events
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
I found pretty simple solution...but I guess that's the way it always works :-) All you have to do for the detection is 2 things: First of all add another variable: var thisObject; After that you have to go to the onMouseDown() function. Right after the SELECTED = intersects[0].object; you have to write this thing:
for(var i=0; i<objects.length; i++)
{
if(SELECTED.position.x == objects[i].position.x)
thisObject = i;
}
...Now thisObject holds the index of the current shape (that was selected/dragged) in objects array...yeah that simple :-)

Categories

Resources