Three.js mouseover mesh with ray intersection, no reaction - three.js

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 );

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>

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.

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

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)

camera inside a sphere

I want to create a skydome and made the shpere, texture loading also fine but I cannot move the camera inside the sphere.
The sphere disappears. I know it is an amateur issue but cannot see the inside of the sphere.
Is it some kind of cutting or Z-buffer issue?
How can I fix it?
My code:
<html>
<head>
<script src="js/jquery-1.8.3.min.js"></script>
<script src="js/three.min.js"></script>
</head>
<body>
<div id="container">
</div>
<script>
function addSpaceSphere( ){
// set up the sphere vars
var radius = 200,
segments = 16,
rings = 16;
var material = new THREE.MeshPhongMaterial({
color:0xFFFFFF,
map: THREE.ImageUtils.loadTexture( 'textures/SPACE014SX.png' )
});
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(
radius,
segments,
rings
),
material
);
// add the sphere to the scene
scene.add(sphere);
}
function addLights(){
// create a point light
var ambient = new THREE.AmbientLight( 0xFFFFFF );
scene.add( ambient );
}
function render() {
camera.lookAt( focus );
camera.updateProjectionMatrix();
renderer.render( scene, camera );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function createScene(){
// add the camera to the scene
scene.add(camera);
// the camera starts at 0,0,0
// so pull it back
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 300;
// start the renderer
renderer.setSize(WIDTH, HEIGHT);
$container.append(renderer.domElement);
addSpaceSphere( );
addLights();
animate();
}
var WIDTH = window.innerWidth;
var HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.01,
FAR = 10000;
var focus = new THREE.Vector3( 0, 0, 0 );
var isUserInteracting = false,
onPointerDownPointerX = 0, onPointerDownPointerY = 0,
lon = 0, onPointerDownLon = 0,
lat = 0, onPointerDownLat = 0,
phi = 0, theta = 0;
var $container = $('#container');
// create a WebGL renderer, camera
// and a scene
//var renderer = new THREE.CanvasRenderer();
var renderer = new THREE.WebGLRenderer();
var camera = new THREE.PerspectiveCamera(
VIEW_ANGLE, ASPECT, NEAR, FAR
);
var scene = new THREE.Scene();
createScene();
</script>
</body>
make the skydome material double-sided -- it's being culled. Set the 'side' attribute to THREE.DoubleSide
(or THREE.BackSide should work too, if the camera is ONLY inside the sphere)

Animating canvas billboard in Three.js

I'm trying to animate a Canvas-based texture that is mapped onto a plane, like a billboard. I've made a point of including material.needsUpdate & texture.needsUpdate, but I'm still unable to get the texture to come to life. I've also included a rotating cube just so I know the animation routine is functioning on some level.
Here is the code:
<body>
<script src="http://mrdoob.github.com/three.js/build/three.min.js"></script>
<script>
if (window.innerWidth === 0) {
window.innerWidth = parent.innerWidth;
window.innerHeight = parent.innerHeight;
}
var camera, scene, renderer;
var mesh, geometry, material;
var light, sign, animTex;
var canvas, context;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 1200);
camera.position.z = 700;
scene = new THREE.Scene();
material = new THREE.MeshLambertMaterial(
{
color: 0x885522,
wireframe: false,
overdraw: false
});
geometry = new THREE.CubeGeometry(80, 120, 100, 1, 1, 1);
mesh = new THREE.Mesh(geometry, material);
sign = createSign();
light = new THREE.DirectionalLight(0xFFFFFF, 3.0);
light.position = new THREE.Vector3(5, 10, 7);
light.target = new THREE.Vector3(0, 0, 0);
scene.add(mesh);
scene.add(sign);
scene.add(light);
renderer = new THREE.CanvasRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function createSign() {
canvas = document.createElement("canvas");
context = canvas.getContext("2d");
canvas.width = 200;
canvas.height = 200;
context = canvas.getContext("2d");
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
var material = new THREE.MeshBasicMaterial({ map : texture, overdraw: true });
material.needsUpdate = true;
var mesh = new THREE.Mesh(new THREE.PlaneGeometry(200, 200), material);
mesh.doubleSided = true;
return mesh;
}
function animate() {
var time = Date.now()*0.01;
var sinTime = Math.sin(time * 0.05) * 100;
var cosTime = Math.cos(time * 0.05) * 100;
mesh.rotation.y = sinTime*0.01;
requestAnimationFrame(animate);
context.fillStyle = "black";
context.fillRect(0, 0, canvas.width, canvas.height);
context.fillStyle = "white";
context.fillRect((canvas.width/2) + sinTime, (canvas.height/2) + cosTime, 20, 20)
renderer.render(scene, camera);
}
This runs, but I can't seem to get the Canvas texture material to update. What have I overlooked?
Place this right before your render() call:
sign.material.map.needsUpdate = true;
The needsUpdate flag is reset (to false) every time the texture is used (every render loop), so it needs to be set to true in the render loop (before the render call, or it'll be a frame off). So in your example, put sign.material.map.needsUpdate = true before renderer.render( scene, camera ). texture.needsUpdate = true and material.needsUpdate = true are not needed.
Also, you only need to set the needsUpdate flag on the texture, as the material properties are not changing.

Resources