I created a cube using the canvas renderer with r59 of Three.js. The cube has different textures on different sides. This renders okay. I can also TWEEN this cube's position and rotation, so it's fine.
Here's what I want to do:
A) The cube has an image texture on it's front side.
B) I move this cube out of the camera's view.
C) I change the image texture on the cube.
D) I move the cube back to its original coordinates so it becomes visible again.
So far, steps A, B and D are working. But when I try to implement step C, it stops working.
Here are the relevant code parts...
<body>
<script src="build/three.min.js"></script>
<script src="js/libs/tween.min.js"></script>
<script>
var container;
var camera, scene, renderer, group, particle;
var cubeMesh;
var MatCollection = [];
var Materials = [];
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 3000 );
camera.position.z = 1000;
scene = new THREE.Scene();
var cubeGeometry = new THREE.CubeGeometry(800, 600, 30, 8, 8, 8);
cubeGeometry.dynamic = true;
// creating three textures
var neheTextureSMALL = new THREE.ImageUtils.loadTexture("test3.jpg");
var neheTextureBIG1 = new THREE.ImageUtils.loadTexture("break01.jpg");
var neheTextureBIG2 = new THREE.ImageUtils.loadTexture("break02.jpg");
// putting two different sets of Materials to a material collection array
Materials = [
new THREE.MeshBasicMaterial({
map:neheTextureBIG1,
side: THREE.DoubleSide
}),
new THREE.MeshBasicMaterial({
map:neheTextureSMALL,
side: THREE.DoubleSide
}),
new THREE.MeshBasicMaterial({
map:neheTextureSMALL,
side: THREE.DoubleSide
}),
new THREE.MeshBasicMaterial({
map:neheTextureSMALL,
side: THREE.DoubleSide
}),
new THREE.MeshBasicMaterial({
map:neheTextureBIG1,
side: THREE.DoubleSide
}),
new THREE.MeshBasicMaterial({
map:neheTextureBIG1,
side: THREE.DoubleSide
})
];
MatCollection.push( Materials );
Materials = [
new THREE.MeshBasicMaterial({
map:neheTextureBIG2,
side: THREE.DoubleSide
}),
new THREE.MeshBasicMaterial({
map:neheTextureSMALL,
side: THREE.DoubleSide
}),
new THREE.MeshBasicMaterial({
map:neheTextureSMALL,
side: THREE.DoubleSide
}),
new THREE.MeshBasicMaterial({
map:neheTextureSMALL,
side: THREE.DoubleSide
}),
new THREE.MeshBasicMaterial({
map:neheTextureBIG2,
side: THREE.DoubleSide
}),
new THREE.MeshBasicMaterial({
map:neheTextureBIG2,
side: THREE.DoubleSide
})
];
MatCollection.push( Materials );
cubeMesh = new THREE.Mesh(cubeGeometry, new THREE.MeshFaceMaterial( MatCollection[0] ));
cubeMesh.dynamic = true;
cubeMesh.position.set(0, 0, 500);
// Applying the first set of materials on cubeMesh creation works good
renderer = new THREE.CanvasRenderer();
renderer.setClearColor(0x000000, 1);
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
TWEEN.update();
camera.lookAt( scene.position );
// rotate the cube - dropped value manipulation
cubeMesh.rotation.set(xRotation, yRotation, zRotation);
renderer.render( scene, camera );
}
// this is NOT WORKING
function changetexture() {
currentMat++;
if (currentMat >= MatCollection.length) {
currentMat = 0;
}
cubeMesh.material = MatCollection[currentMat];
cubeMesh.material.needsUpdate = true;
}
</script>
</body>
In my project, I am doing a lot more TWEENING (moving and rotating a lot of objects) and I am calling changetexture() from there...
When leaving out the line...
cubeMesh.material = MatCollection[currentMat];
from that function, everything works fine. The cube moves out and comes back into view showing always the same texture.
What should I change?
Thank you in advance for sharing your expertise.
Oliver
Done.
Instead of trying to preload the Material into an array of materials, I created an array of individual textures called MyTextures and applied a newly created material (using the textures from the MyTextures array) to each side of the cube mesh.
...
var MyTextures = [];
... then, in the init() function:
neheTextureSMALL = new THREE.ImageUtils.loadTexture("test3.jpg");
MyTextures.push( neheTextureSMALL );
for (var myy = 0; myy<imgNameArray.length;myy++) {
neheTexture = new THREE.ImageUtils.loadTexture(imgNameArray[myy]);
MyTextures.push( neheTexture );
}
... then in the changetexture() function:
cubeMesh.material.materials[0] = new THREE.MeshBasicMaterial({map: MyTextures[currentMat+1], side: THREE.DoubleSide });
cubeMesh.material.materials[1] = new THREE.MeshBasicMaterial({map: MyTextures[0], side: THREE.DoubleSide });
cubeMesh.material.materials[2] = new THREE.MeshBasicMaterial({map: MyTextures[0], side: THREE.DoubleSide });
cubeMesh.material.materials[3] = new THREE.MeshBasicMaterial({map: MyTextures[0], side: THREE.DoubleSide });
cubeMesh.material.materials[4] = new THREE.MeshBasicMaterial({map: MyTextures[currentMat+1], side: THREE.DoubleSide });
cubeMesh.material.materials[5] = new THREE.MeshBasicMaterial({map: MyTextures[currentMat+1], side: THREE.DoubleSide });
That works pretty well.
But it does not look good (the image seems to be split into many triangles which is another problem...). :-(
Related
I'm trying to make a plane in three.js that one side is a texture and the other side is a color. I tried:
var material = new THREE.MeshBasicMaterial({color: 0xff0000, side: THREE.FrontSide, map: texture});
var geometry = new THREE.PlaneGeometry(width, height);
plane = new THREE.Mesh(geometry, material);
However this makes a plane that only one side has the texture and the other side is completely transparent. If I go:
var material = new THREE.MeshBasicMaterial({color: 0xff0000});
Then both sides have the color. Is there a way to make it so one side has a texture and the other side has the color?
Here is one patten you can follow if you want a different material on the front and back of a mesh:
var group = new THREE.Group();
scene.add( group );
group.add( new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { map: texture } ) ) );
group.add( new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.BackSide } ) ) );
Another approach is to write your own custom ShaderMaterial, but the above is the easiest if you are just getting started with three.js
three.js r.104
I'm trying to build a gallery wall via three.js. So far I succeeded rendering an image on each side like this:
I've put paintings on left and right. However, I want to render more images on each wall rather than filling the entire wall with a single image. Something like this:
How can I set arbitrary positions?
Here's my code:
var scene = new THREE.Scene()
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1,1000)
console.log(window.innerWidth, window.innerHeight)
var renderer = new THREE.WebGLRenderer()
renderer.setSize( window.innerWidth,window.innerHeight)
document.body.appendChild(renderer.domElement)
//keep object in view when resize window
window.addEventListener('resize', () => {
let width = window.innerWidth
let height = window.innerHeight
renderer.setSize(width, height)
camera.aspect = width / height
camera.updateProjectionMatrix()
})
controls = new THREE.OrbitControls(camera, renderer.domElement)
controls.enableZoom = false
controls.enableRotate = true
controls.enablePan = false
var geometry = new THREE.BoxGeometry( 2.5, 2, 4 )
var cubeDice = [
new THREE.MeshBasicMaterial({ color: 0x666666, side: THREE.DoubleSide }),
new THREE.MeshBasicMaterial({ color: 0x666666, side: THREE.DoubleSide }),
new THREE.MeshBasicMaterial({ color: 0x999999, side: THREE.DoubleSide }),
new THREE.MeshBasicMaterial({ color: 0x999999, side: THREE.DoubleSide }),
new THREE.MeshPhongMaterial({ map: new THREE.TextureLoader().load('img/h5_1993.132.jpg'), side: THREE.DoubleSide }),
new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load('img/unnamed.png'), side: THREE.DoubleSide }),
]
// var material = new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: true } )
var material = new THREE.MeshFaceMaterial(cubeDice)
var cube = new THREE.Mesh( geometry,material )
scene.add( cube )
// //set camera closer
camera.position.z = 1
var update = function(){
cube.rotation.y += .005
}
var render = function(){ renderer.render(scene, camera) }
var GameLoop = () => {
requestAnimationFrame(GameLoop)
update()
render()
}
GameLoop()
MeshFaceMaterial does not do what you want. It makes each image fill up an entire face (an entire wall).
To make separate, movable images on the wall, it would be better to make an individual smaller mesh for each image, and then position them very close to the wall. That way the image can cover the entire mesh, but not cover the entire wall:
I'm trying to create the effect similar to hula hoop covered in tape using three.js.
The 3d model should end up looking something like below.
I can create the hoop in 3d space using TorusGeometry with the ability to pan around, but I have not managed to work out how to get a 2nd TorusGeometry to break into sections.
What is the best way of creating this effect?
// hoop
hoop = new THREE.TorusGeometry(20, .5, 100, 50);
var hoopMaterial = new THREE.MeshPhongMaterial({
ambient: 0xffffff,
color: 0x028fde,
specular: 0x555555,
shininess: 0
});
hoopMesh = new THREE.Mesh(hoop, hoopMaterial);
hoopMesh.position.z = 0;
scene.add(hoopMesh);
hoopTape1 = new THREE.TorusGeometry(20.1, .6, 0, 50);
var hoopTapeMaterial = new THREE.MeshPhongMaterial({
ambient: 0xffffff,
color: 0xDE5102,
specular: 0x555555,
shininess: 0
});
hoopTape1Mesh = new THREE.Mesh(hoopTape1, hoopTapeMaterial);
hoopMesh.position.z = 0;
scene.add(hoopTape1Mesh);
jsfiddle with current working code.
You will have to apply a texture to your torus that is seamless to achieve that effect. The texture should be similar to this one:
Then use this code pattern:
var geometry = new THREE.TorusBufferGeometry( 6, 0.4, 16, 64 );
var loader = new THREE.TextureLoader();
var texture = loader.load( 'stripe.jpg', function ( texture ) {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 16, 0.5 ); // or whatever you like
render();
} );
var material = new THREE.MeshPhongMaterial( {
color: 0x998877,
specular: 0x050505,
shininess: 50,
map: texture
} );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
three.js r.77
I have some generated geometries, where I want to see the faces from 2 sides.
So when looking from the front of one of the face's in the geometry, it is using material1 but viewed from the back you see material2.
I have experimentet with THREE.FrontSide, THREE.BackSide & THREE.DoubleSide, but none of them seem to give the wanted result. DoubleSide will just mirror the material on front and back.
Should I clone my geometry and create to meshes with two different materials ( mat1 = front & mat2 = back ) or what would you guys do?
Yes, two meshes with different materials should do the trick:.....
var material1 = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var material2 = new THREE.MeshBasicMaterial( { color: 0x0000ff, side: THREE.BackSide } );
var object1 = new THREE.Mesh( geometry, material1 );
var object2 = new THREE.Mesh( geometry, material2 );
I've recently started to play with three.js, and I am using terrain.js demo as a start for a design project I am working on.
I will like to add a hybrid shader "wireframe/lambert"
the default comes with wire shader only.
This is the code from the demo, using basic material:
var matrix = new THREE.MeshBasicMaterial({
color:0x10ce58,
wireframe:true
});
var geometry = new THREE.PlaneGeometry(width, height, modelWidth, modelHeight);
mesh = new THREE.Mesh(geometry, matrix);
mesh.doubleSided = false;
and I tried something like this but I only get the "lambert" rendering and not the lambert and wire combined, any ideas?
var darkMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff , shading: THREE.FlatShading, overdraw: true} );
var wireframeMaterial = new THREE.MeshBasicMaterial( { color: 0x10ce58, wireframe: true, transparent: true } );
var multiMaterial = [ darkMaterial, wireframeMaterial ];
var geometry = new THREE.PlaneGeometry(width, height, modelWidth, modelHeight);
mesh = new THREE.Mesh(geometry, multiMaterial);
mesh.doubleSided = false;
Thanks for your time in advanced,
Regards
-Manuel
This is the code I am using in my non working example for materials (http://jsfiddle.net/xnqUb/3/)
var geometry = new THREE.PlaneGeometry(width, height, model.length - 1, model.length - 1, materials);
materials = [
new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.FlatShading, overdraw: true } ),
new THREE.MeshLambertMaterial({ color: 0x10ce58, wireframe: true,})
];
var mesh = new THREE.Mesh(geometry);
object = THREE.SceneUtils.createMultiMaterialObject(geometry, materials);