How to express pixel width in Three.js world space? - three.js

Three.js offers a special renderer, examples/js/renderers/CSS2DRenderer, that allows html overlays on a standard WebGL-rendered scene (see the official demo, here.)
The CSS2DRenderer accomplishes the positioning of the html item with CSS transforms. Here is how the renderer relates world space to screen space:
vector.setFromMatrixPosition( object.matrixWorld );
vector.applyProjection( viewProjectionMatrix );
var element = object.element;
var style = 'translate(-50%,-50%) translate(' + ( vector.x * _widthHalf + _widthHalf ) + 'px,' + ( - vector.y * _heightHalf + _heightHalf ) + 'px)';
element.style.WebkitTransform = style;
element.style.MozTransform = style;
element.style.oTransform = style;
element.style.transform = style;
In the live snippet, below, I have positioned several text elements, alongside a grid, like axis labels in a data plot. My problem is to choose a position in three.js world space for the html labels that accounts for their pixel width. I have framed each label with a plane to show the gap to the edge of the grid – I need to eliminate that gap!
var renderer, labelRenderer, scene, camera, controls, sprite, stats, rot, planes, ctx, fontFamily, fontSize;
rot = 0; // this drives load(?)
init();
//animate();
render();
function init() {
fontFamily = "monospace";
fontSize = "10px";
stats = new Stats();
stats.showPanel(1);
document.body.appendChild(stats.dom);
var canvas = document.createElement('canvas')
ctx = canvas.getContext('2d')
ctx.font = fontSize + " " + fontFamily;
// renderer
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
labelRenderer = new THREE.CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0';
labelRenderer.domElement.style.pointerEvents = 'none';
document.body.appendChild(labelRenderer.domElement);
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(20, 20, 20);
// controls
controls = new THREE.OrbitControls(camera);
// ambient
scene.add(new THREE.AmbientLight(0x222222));
// light
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(20, 20, 0);
scene.add(light);
// axes
scene.add(new THREE.AxisHelper(20));
var size = 5;
var step = 5;
var gridHelper = new THREE.GridHelper(size, step);
gridHelper.translateX(5);
gridHelper.translateZ(5);
scene.add(gridHelper);
var geometry, material, text, label;
planes = new Array(5);
var texts = ["one", "two", "three", "four", "five"];
for (var i = 0; i < 5; i++) {
geometry = new THREE.PlaneGeometry(2, 2);
material = new THREE.MeshBasicMaterial({
transparent: true,
opacity: 0
});
planes[i] = new THREE.Mesh(geometry, material);
planes[i].position.set(10 + 1, 1, i * 2 + 1)
planes[i].lookAt(camera.position)
scene.add(planes[i]);
scene.add(new THREE.EdgesHelper(planes[i]))
text = document.createElement('div');
text.className = 'label';
text.style.color = "white";
text.style["font-family"] = fontFamily;
text.style["font-size"] = fontSize;
text.textContent = texts[i];
var textWidth = ctx.measureText(texts[i]).width;
console.log("textWidth", textWidth);
label = new THREE.CSS2DObject(text);
label.position.copy(planes[i].position);
scene.add(label);
console.log("label", label);
}
}
function randomPos(scale) {
return scale * Math.random();
}
function render() {
renderer.render(scene, camera);
labelRenderer.render(scene, camera);
var x = camera.position.x;
var z = camera.position.z;
camera.position.x = x * Math.cos(rot) + z * Math.sin(rot);
camera.position.z = z * Math.cos(rot) - x * Math.sin(rot);
camera.lookAt(scene.position);
requestAnimationFrame(render);
planes.forEach(function(plane) {
plane.lookAt(camera.position);
});
stats.update();
}
function animate() {
requestAnimationFrame(animate);
//controls.update();
renderer.render(scene, camera);
stats.update();
}
body {
background-color: #000;
margin: 0px;
overflow: hidden;
}
<script src="https://rawgit.com/mrdoob/three.js/dev/build/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/controls/OrbitControls.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/renderers/CSS2DRenderer.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/libs/stats.min.js"></script>

Pixel Width isn't your issue here. It's origin. You're offsetting the position (10 + 1, i, i*2+1)... https://jsfiddle.net/7j4jypfL/1/
label = new THREE.CSS2DObject(text);
label.position.set(10+(0.5),0, (i * 2)+0.5);
scene.add(label);
You need to keep in mind that in OpenGL, things like billboards and the like are origin centered (i.e. -1,-1 to 1,1) and therefore (0,0) would be center.
YOU need you measure at scale 1 and when you zoom and the like it will line up correctly because of perspective math. Look at my fiddle where I change your positions to just pure (10, i, i*2) and look at how the text lines up. If you want to move it down from there, (10 + (0.5),0,(i*2)+0.5)

Related

three is - how to limit pan in OrbitControls for OrthographicCamera so that object (texture image) is always in the scene

I am using OrbitControls to control an Orthographic camera. The scene has a 2d texture image.
I want to limit the pan of the camera, when reaching the edge of the image.
For example, when the camera is panned to the left, and the image is shifted to the right in the view window, when the left edge of the image is to the right of the visible window, stop the left panning (see the attached diagram)
Here and here the pan limit is hard coded, but in my case the limit depends on the zoom (and I assume that also on the size of the image). For example, when the image is shifted all the way to left,
when zoomed-in, scope.target.x ~= ~100
when zoomed-out, scope.target.x ~= ~800
How can I disable panning to the left when the left side of the image reaches the left edge of the visible window?
Thanks,
Avner
EDIT:
#Rabbid76 thanks for your suggestions. With some modifications to the example code, I solved the problem, i.e. the image always covers the view window.
See here for details
You can manually limit the pan.
Consider you have an OrthographicCamera, which looks onto the xy-plane.
e.g.
camera = new THREE.OrthographicCamera(-5*aspect, 5*aspect, -5, 5, -100, 100);
camera.position.set(0, 0, -1);
And you have a mesh (object), from which you can get the bounding box (THREE.Box3):
var bbox = new THREE.Box3().setFromObject(object);
With this information the minimum and maximum x and y coordinates of the object can be calculated:
var min_x = camera.left - bbox.min.x;
var max_x = camera.right - bbox.max.x;
var min_y = camera.top - bbox.min.y;
var max_y = camera.bottom - bbox.max.y;
The current camera position and target can be clamped to the limiting range:
let pos_x = Math.min(max_x, Math.max(min_x, camera.position.x));
let pos_y = Math.min(max_y, Math.max(min_y, camera.position.y));
Update the OrthographicCamera and the OrbitControls:
camera.position.set(pos_x, pos_y, camera.position.z);
camera.lookAt(pos_x, pos_y, orbitControls.target.z);
orbitControls.target.x = pos_x;
orbitControls.target.y = pos_y;
orbitControls.update();
See the example:
(function onLoad() {
var container, loader, camera, scene, renderer, orbitControls, object, bbox;
init();
animate();
function init() {
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
aspect = window.innerWidth / window.innerHeight;
camera = new THREE.OrthographicCamera(-5*aspect, 5*aspect, -5, 5, -100, 100);
camera.position.set(0, 0, -1);
loader = new THREE.TextureLoader();
loader.setCrossOrigin("");
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
scene.add(camera);
window.onresize = resize;
orbitControls = new THREE.OrbitControls(camera);
orbitControls.enabled = true;
orbitControls.enableRotate = false;
orbitControls.screenSpacePanning = true;
orbitControls.mouseButtons = {
LEFT: THREE.MOUSE.RIGHT,
MIDDLE: THREE.MOUSE.MIDDLE,
RIGHT: THREE.MOUSE.LEFT
}
addGridHelper();
createModel();
}
function createModel() {
var material = new THREE.MeshBasicMaterial({color:'#ff4040'});
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
object = new THREE.Mesh(geometry, material);
bbox = new THREE.Box3().setFromObject(object);
scene.add(object);
}
function addGridHelper() {
var helper = new THREE.GridHelper(100, 100);
helper.rotation.x = Math.PI / 2;
helper.material.opacity = 0.25;
helper.material.transparent = true;
scene.add(helper);
var axis = new THREE.AxesHelper(1000);
scene.add(axis);
}
function resize() {
var aspect = window.innerWidth / window.innerHeight;
renderer.setSize(window.innerWidth, window.innerHeight);
camera.left = -5*aspect;
camera.right = 5*aspect;
camera.updateProjectionMatrix();
}
function animate() {
requestAnimationFrame(animate);
var min_x = camera.left - bbox.min.x;
var max_x = camera.right - bbox.max.x;
var min_y = camera.top - bbox.min.y;
var max_y = camera.bottom - bbox.max.y;
let pos_x = Math.min(max_x, Math.max(min_x, camera.position.x));
let pos_y = Math.min(max_y, Math.max(min_y, camera.position.y));
camera.position.set(pos_x, pos_y, camera.position.z);
camera.lookAt(pos_x, pos_y, orbitControls.target.z);
orbitControls.target.x = pos_x;
orbitControls.target.y = pos_y;
orbitControls.update();
render();
}
function render() {
renderer.render(scene, camera);
}
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/99/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div id="container"></div>

THREEJS - Make meshes perpendicular to the Sphere face it's sitting on

// THREEJS RELATED VARIABLES
var scene, camera, renderer, container, controls, raycaster, sphere_radius, HEIGHT, WIDTH;
//INIT THREE JS, SCREEN AND MOUSE EVENTS
function createScene() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
scene = new THREE.Scene();
aspectRatio = WIDTH / HEIGHT;
camera = new THREE.PerspectiveCamera(60, WIDTH / HEIGHT, 1, 10000);
camera.position.x = 0;
camera.position.z = 1500;
camera.position.y = 0;
// ORBIT CAMERA
controls = new THREE.OrbitControls( camera );
controls.update();
renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
renderer.setSize(WIDTH, HEIGHT);
container = document.getElementById('world');
container.appendChild(renderer.domElement);
}
function randomSpherePoint(x0,y0,z0,radius){
var u = Math.random();
var v = Math.random();
var theta = 2 * Math.PI * u;
var phi = Math.acos(2 * v - 1);
var x = x0 + (radius * Math.sin(phi) * Math.cos(theta));
var y = y0 + (radius * Math.sin(phi) * Math.sin(theta));
var z = z0 + (radius * Math.cos(phi));
return [x,y,z];
}
Island = function(){
this.mesh = new THREE.Object3D();
// number of cubes
this.nLands = 30;
this.lands = [];
for(var i = 0; i < this.nLands; i++){
var c = new Land();
this.lands.push(c);
var stepAngle = Math.PI*2 * Math.random();
var a = stepAngle*i;
var h = sphere_radius;
var randPos = randomSpherePoint(0,0,0,sphere_radius);
c.mesh.position.y = randPos[1];
c.mesh.position.x = randPos[0];
c.mesh.position.z = randPos[2];
this.mesh.add(c.mesh);
}
}
Land = function(){
this.mesh = new THREE.Object3D();
this.mesh.name = "land";
var geom = new THREE.CylinderGeometry( 2, 2, 50, 64 );
var mat = new THREE.MeshPhongMaterial({color:0x59332e});
var m = new THREE.Mesh(geom.clone(), mat);
m.position.x = 0;
m.position.y = Math.random()*2;
m.position.z = Math.random()*10;
this.mesh.add(m);
}
Sea = function(){
// radius top, radius bottom, height, number of segments on the radius, number of segments vertically
sphere_radius = 300;
var geom = new THREE.SphereGeometry(sphere_radius,sphere_radius,32,32);
var mat = new THREE.MeshNormalMaterial({
transparent:true,
opacity:.5,
flatShading:true,
});
this.mesh = new THREE.Mesh(geom, mat);
this.mesh.name = "sea";
}
// 3D Models
var sea;
function createSea(){
sea = new Sea();
sea.mesh.position.y = 0;
scene.add(sea.mesh);
}
function createIsland(){
island = new Island();
island.mesh.position.y = 0;
scene.add(island.mesh);
}
function loop(){
renderer.render(scene, camera);
requestAnimationFrame(loop);
}
function init(event){
createScene();
createSea();
createIsland();
loop();
}
window.addEventListener('load', init, false);
function handleWindowResize() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
}
window.addEventListener('resize', handleWindowResize, false);
html, body {
overflow: hidden;
margin:0;
padding:0;
}
<div id="world"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.min.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r94/js/controls/OrbitControls.js"></script>
Related codepen:
https://codepen.io/farisk/pen/zLymrz
On three.js, i have a bunch of cylinders added to random positions on the exterior of sphere.
The issue im having now is that they're all facing straight up to the z-axis.
Im thinking that what i should do is to make the cylinder lookAt the angle of where the cylinder intersects the sphere. But im not sure how to achieve this. Any help is appreciated.
Heres a image that describes the situation.

Three Js - How to fix the blurry images on the vertices of an icosahedron

I was trying to make a rotating icosahedorn with images on each vertex using three js, but the images look blurred. Can anyone please help me? js fiddle link here: https://jsfiddle.net/prisoner849/b2tncLh8/
<div id="container"></div>
var $container = $('#container');
var renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
var camera = new THREE.PerspectiveCamera(80, 1, 0.1, 10000);
var scene = new THREE.Scene();
var Ico;
scene.add(camera);
renderer.setSize(576, 576);
// Making the canvas responsive
function onWindowResize() {
var screenWidth = $(window).width();
if (screenWidth <= 479) {
renderer.setSize(300, 300);
} else if (screenWidth <= 767) {
renderer.setSize(400, 400);
} else if (screenWidth <= 991) {
renderer.setSize(500, 500);
} else if (screenWidth <= 1200) {
renderer.setSize(450, 450);
} else if (screenWidth <= 1366) {
renderer.setSize(550, 550);
}
camera.updateProjectionMatrix();
}
onWindowResize();
window.addEventListener('resize', onWindowResize, false);
$container.append(renderer.domElement);
// Camera
camera.position.z = 200;
// Material
var greyMat = new THREE.MeshPhongMaterial({
color: new THREE.Color("rgb(125,127,129)"),
emissive: new THREE.Color("rgb(125,127,129)"),
specular: new THREE.Color("rgb(125,127,129)"),
shininess: "100000000",
shading: THREE.FlatShading,
transparent: 1,
opacity: 1
});
var L2 = new THREE.PointLight();
L2.position.z = 1900;
L2.position.y = 1850;
L2.position.x = 1000;
scene.add(L2);
camera.add(L2);
var Ico = new THREE.Mesh(new THREE.IcosahedronGeometry(125, 1), greyMat);
Ico.rotation.z = 0.5;
scene.add(Ico);
var trackballControl = new THREE.TrackballControls(camera, renderer.domElement);
trackballControl.rotateSpeed = 1.0;
trackballControl.noZoom = true;
// sprites
var txtLoader = new THREE.TextureLoader();
txtLoader.setCrossOrigin("");
var textures = [
"https://threejs.org/examples/textures/UV_Grid_Sm.jpg",
"https://threejs.org/examples/textures/colors.png",
"https://threejs.org/examples/textures/metal.jpg"
];
var direction = new THREE.Vector3();
console.log(Ico.geometry.vertices.length);
Ico.geometry.vertices.forEach(function(vertex, index){
var texture = txtLoader.load(textures[index % 3]);
var spriteMaterial = new THREE.SpriteMaterial({map: texture});
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.setScalar(10);
direction.copy(vertex).normalize();
sprite.position.copy(vertex).addScaledVector(direction, 10);
Ico.add(sprite);
});
function update() {
Ico.rotation.x += 2 / 500;
Ico.rotation.y += 2 / 500;
}
// Render
function render() {
trackballControl.update();
requestAnimationFrame(render);
renderer.render(scene, camera);
update();
}
render();
so i'm guessing because you scale the textures a lot, you're wondering how to get it more blocky and less blurry? If that's the case, with each loaded texture you should set texture.magFilter = THREE.NearestFilter.
magFilter specifies the behavior when a portion of a texture occupies more pixels than the texture's native resolution.
NearestFilter basically returns colors for the UV coordinates for pixel at Math.floor(UV.x*width). So if you have a resolution of 64 pixels, it'll color in 64 blocks across and 64 down. Nice and pixelated.
With the default, linearfilter - it will lerp in between pixel perfect values, giving you the blurring effect. The documentation for THREE.Texture can give you more info on things to try if you get stuck.
See in action.

Three JS: How to add images on each vertices of icosahedron

I'm new to Three js, i was trying to create a rotating icosahedron with small icon kind of images on each vertex using three js, i could create the icosahedron and make it rotate but I'm not able to attach images on each vertex of it. Can anyone help me do this?
Please check the js fiddle link of what i could acheive so far:
<div id="container"></div>
var $container = $('#container');
var renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
var camera = new THREE.PerspectiveCamera(80, 1, 0.1, 10000);
var scene = new THREE.Scene();
var Ico;
scene.add(camera);
renderer.setSize(576, 576);
// Making the canvas responsive
function onWindowResize() {
var screenWidth = $(window).width();
if (screenWidth <= 479) {
renderer.setSize(300, 300);
} else if (screenWidth <= 767) {
renderer.setSize(400, 400);
} else if (screenWidth <= 991) {
renderer.setSize(500, 500);
} else if (screenWidth <= 1200) {
renderer.setSize(450, 450);
} else if (screenWidth <= 1366) {
renderer.setSize(550, 550);
}
camera.updateProjectionMatrix();
}
onWindowResize();
window.addEventListener('resize', onWindowResize, false);
$container.append(renderer.domElement);
// Camera
camera.position.z = 200;
// Material
var greyMat = new THREE.MeshPhongMaterial({
color: new THREE.Color("rgb(125,127,129)"),
emissive: new THREE.Color("rgb(125,127,129)"),
specular: new THREE.Color("rgb(125,127,129)"),
shininess: "100000000",
shading: THREE.FlatShading,
transparent: 1,
opacity: 1
});
var L2 = new THREE.PointLight();
L2.position.z = 1900;
L2.position.y = 1850;
L2.position.x = 1000;
scene.add(L2);
camera.add(L2);
var Ico = new THREE.Mesh(new THREE.IcosahedronGeometry(125, 1), greyMat);
Ico.rotation.z = 0.5;
scene.add(Ico);
var trackballControl = new THREE.TrackballControls(camera, renderer.domElement);
trackballControl.rotateSpeed = 1.0;
trackballControl.noZoom = true;
function update() {
Ico.rotation.x += 2 / 500;
Ico.rotation.y += 2 / 500;
}
// Render
function render() {
trackballControl.update();
requestAnimationFrame(render);
renderer.render(scene, camera);
update();
}
render();
https://jsfiddle.net/arunvenugopal11/uoxtmtnr/
Thanks in advance :)
You can use THREE.Sprite(), like this:
var txtLoader = new THREE.TextureLoader();
txtLoader.setCrossOrigin(""); // you don't need it, if you get images from your web site
var textures = [ // you can have a full set of 42 images, I used just 2
"https://threejs.org/examples/textures/UV_Grid_Sm.jpg",
"https://threejs.org/examples/textures/colors.png"
];
var direction = new THREE.Vector3(); // we'll re-use it in the loop
Ico.geometry.vertices.forEach(function(vertex, index){
var texture = txtLoader.load(textures[index % 2]); // when you have a full set of images, you don't need that operation with modulus '%'
var spriteMaterial = new THREE.SpriteMaterial({map: texture});
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.setScalar(10); // the size is up to you
direction.copy(vertex).normalize(); // direction is just a normalized vertex
sprite.position.copy(vertex).addScaledVector(direction, 10); // add scaled direction to the position of a sprite
Ico.add(sprite);
});
jsfiddle example. r85

Three.js mouseover mesh with ray intersection, no reaction

I'm trying to set up a website that runs in a single WebGL element. I'm trying to get it to tell when the mouse is over an object. I'm using a couple of planes with a with transparent textures on them as links, but it won't pick up on any intersections at all. It does absolutely nothing. I've even added a cube and used the same code as the interactive cubes example (http://mrdoob.github.com/three.js/examples/webgl_interactive_cubes.html) and it does absolutely nothing. No changing the color, absolutely nothing.
I've gone through and tried about 8 different examples online having to do with this and not a single one has worked for me.
Here is my code:
<meta charset="utf-8">
<style type="text/css">
body {
margin: 0px;
overflow: hidden;
background: #000000;
}
div {
margin: 0px;
}
</style>
</head>
<div>
<script src="http://www.html5canvastutorials.com/libraries/Three.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
//Variable Declarations
var camera, scene, renderer, aspect, projector;
var INTERSECTED;
var mouseX = 0, mouseY = 0;
init();
//Method Declarations
function init() {
aspect = window.innerWidth / window.innerHeight;
//aspect = 1.25;
//Sets the camera variable to a new Perspective Camera with a field of view of 45 degrees, an aspect ratio
//of the window width divided by the window height, the near culling distance of 1 and the far culling distance of 2000
camera = new THREE.PerspectiveCamera(45, aspect, 1, 2000);
//Sets the height of the camera to 400
camera.position.z = 700;
//Sets a variable "lookat" to a new 3d vector with a position of 0, 0, 0,
//or the center of the scene/center of the menu plane
var lookat = new THREE.Vector3(0, 0, 0);
//Uses a function built in to every camera object to make it look at a given coordinate
camera.lookAt(lookat);
//Makes a new scene object to add everything to
scene = new THREE.Scene();
//Adds the camera object to the scene
scene.add(camera);
//Sets the renderer varialbe to a new WebGL renderer object
//Change "WebGLRenderer" to "CanvasRenderer" to use canvas renderer instead
renderer = new THREE.WebGLRenderer({antialias:true});
//renderer.sortObjects = false;
//Sets the size of the renderer object to the size of the browser's window
//renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setSize(window.innerWidth, window.innerHeight);
//Adds an event listener to the webpage that "listens" for mouse movements and when the mouse does move, it runs the
//"onMouseMove" function
document.addEventListener('mousemove', onMouseMove, false);
//Force canvas to stay proportional to window size
window.addEventListener('resize', onWindowResize, false);
document.addEventListener('mousedown', onDocumentMouseDown, false);
//Sets the update frequency of the webpage in milliseconds
setInterval(update, 1000/60);
//Makes a variable "texture" and sets it to the returned value of the method "loadTexture"
//supplied by the THREE.js library
var texture = THREE.ImageUtils.loadTexture('imgs/backgrounds.png');
//Makes a variable "geometry" and sets it to a "PlaneGeometry" object with a width of 645 and a height of 300
var geometry = new THREE.PlaneGeometry(645, 300);
//Makes a variable "material" and sets it to a "MeshBasicMaterial" object with it's map set to
//the "texture" object, it also makes it transparent
var material = new THREE.MeshBasicMaterial({map: texture, transparent: true});
//Makes a variable "plane" and sets it to a "Mesh" object with its geometry set to the "geometry" object
//and it's material set to the "material" object
var plane = new THREE.Mesh(geometry, material);
//Background Texture
var backgroundTexture = THREE.ImageUtils.loadTexture('imgs/gears.png');
var backgroundGeo = new THREE.PlaneGeometry(3500, 2500);
var backgroundMat = new THREE.MeshBasicMaterial({map: backgroundTexture});
var backgroundPlane = new THREE.Mesh(backgroundGeo, backgroundMat);
backgroundPlane.position.z = -1000;
backgroundPlane.overdraw = true;
//Home Button
//Makes a "homeTexture" variable and sets it to the returned value of the makeTextTexture function when
//the text passed in is set to "Home", the width is set to 300, height of 150, font set to 80pt Arial,
//fillStyle set to white, textAlign set to center, textBaseLine set to middle, and the color of the
//background set to red = 0, green = 0, blue = 0 and alpha = 0
var homeTexture = makeTextTexture("Home", 300, 150, '80pt Arial', 'white', "center", "middle", "rgba(0,0,0,0)");
var homeGeom = new THREE.PlaneGeometry(50, 25);
var homeMaterial = new THREE.MeshBasicMaterial({map: homeTexture, transparent: true});
var homeTest = new THREE.Mesh(homeGeom, homeMaterial);
homeTest.position.x -= 270;
homeTest.position.y += 120;
homeTest.position.z = 40;
homeTest.castShadow = true;
//Gallery Button
var galleryTexture = makeTextTexture("Gallery", 340, 150, '80pt Arial', 'white', "center", "middle", "rgba(0,0,0,0)");
var galleryGeom = new THREE.PlaneGeometry(50, 25);
var galleryMaterial = new THREE.MeshBasicMaterial({map: galleryTexture, transparent: true});
var galleryTest = new THREE.Mesh(galleryGeom, galleryMaterial);
galleryTest.position.x -= 270;
galleryTest.position.y += 90;
galleryTest.position.z = 40;
galleryTest.castShadow = true;
//The Team Button
var theTeamTexture = makeTextTexture("Company", 510, 150, '80pt Arial', 'white', "center", "middle", "rgba(0,0,0,0)");
var theTeamGeom = new THREE.PlaneGeometry(80, 25);
var theTeamMaterial = new THREE.MeshBasicMaterial({map: theTeamTexture, transparent: true});
var theTeamTest = new THREE.Mesh(theTeamGeom, theTeamMaterial);
theTeamTest.position.x -= 260;
theTeamTest.position.y += 60;
theTeamTest.position.z = 40;
theTeamTest.castShadow = true;
projector = new THREE.Projector();
var cubeGeom = new THREE.CubeGeometry(20, 20, 20);
var cubeMat = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var cubeMesh = new THREE.Mesh(cubeGeom, cubeMat);
cubeMesh.position.z = 15;
//scene.add(cubeMesh);
//Adds all of the previously created objects to the scene
scene.add(plane);
scene.add(backgroundPlane);
scene.add(homeTest);
scene.add(theTeamTest);
scene.add(galleryTest);
//Adds the renderer to the webpage
document.body.appendChild(renderer.domElement);
}
function update() {
camera.position.x = (mouseX - (window.innerWidth / 2)) * 0.1;
camera.position.y = -((mouseY - (window.innerHeight / 2)) * 0.15);
camera.lookAt(new THREE.Vector3(0, 0, 0));
render();
}
function render() {
renderer.render(scene, camera);
}
function onMouseMove(event) {
mouseX = event.clientX;
mouseY = event.clientY;
}
function onDocumentMouseDown(event) {
event.preventDefault();
var vector = new THREE.Vector3(
( event.clientX / window.innerWidth ) * 2 - 1,
- ( event.clientY / window.innerHeight ) * 2 + 1,
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 ) {
intersects[ 0 ].object.materials[ 0 ].color.setHex( Math.random() * 0xffffff );
}
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function makeTextTexture(text, width, height, font, fillStyle, textAlign, textBaseline, backgroundColor)
{
//Makes a new canvas element
var bitmap = document.createElement('canvas');
//Gets its 2d css element
var g = bitmap.getContext('2d');
//Sets it's width and height
bitmap.width = width;
bitmap.height = height;
//Takes "g", it's 2d css context and set's all of the following
g.font = font;
g.fillStyle = backgroundColor;
g.fillRect(0, 0, width, height);
g.textAlign = "center";
g.textBaseline = "middle";
g.fillStyle = fillStyle;
g.fillText(text, width / 2, height / 2);
//Rendered the contents of the canvas to a texture and then returns it
var texture = new THREE.Texture(bitmap);
texture.needsUpdate = true;
return texture;
}
</script>
</div>
</html>
Thanks to anyone that can help out. I wish I could figure out what's going on myself, it seems like I'm using StackOverflow to answer my questions way too much.
You have not declared the variable objects. Do this:
var objects = [];
Then populate it:
objects.push( plane );
objects.push( backgroundPlane );
Now, this line will work:
var intersects = ray.intersectObjects( objects );

Resources