I have been following this tutorial, creating a Cube with a texture.
The problem is, the texture repeats on every face of the cube.
I would like to use a single texture that 'wraps' around the cube. Is this possible?
// material
var material = new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('http://www.html5canvastutorials.com/demos/assets/crate.jpg')
});
// this has no effect!
material.wrapAround = true;
// cube
var cube = new THREE.Mesh(new THREE.CubeGeometry(200, 200, 200), material);
cube.overdraw = true;
cube.rotation.x = Math.PI * 0.1;
scene.add(cube);
Typically, with a THREE.CubeGeometry, you can either:
(1) Choose a single texture that repeats on each side of the cube, or
(2) Have a different texture for each of the six sides
You can also use repeat the number of times a texture is displayed on each side.
For examples of each of these, check out the source code of the demos at:
http://stemkoski.github.io/Three.js/Textures.html
and
http://stemkoski.github.io/Three.js/Texture-Repeat.html
Hope this helps!
Related
We want to create a 3d shoe designing tool, where you can design patterns and upload them to the shoe.
I am trying to place an image on a Threejs material. I am able to update the map, but the texture is blurry. I am new to Threejs, so I do not have concepts clear. I don't understand if aspect ratio is the issue or something else.
This how I am loading texture:
var texture_loader = new THREE.TextureLoader();
var texture = texture_loader.load( 'https://ik.imagekit.io/toesmith/pexels-photo-414612_D4wydSedY.jpg', function ( texture ) {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.offset.set( 0, 0 );
texture.repeat.set( 1, 1 );
vamp.material = new THREE.MeshPhongMaterial({
map: texture,
color: new THREE.Color('#f2f2f2'),
shininess: 20,
});
});
This is what I am getting
But the expected behavior should be
If anyone could help, that would be great. Thanks
Here is the link to the Codepen code
The problem is that your UVs are occupying a very small area in texture coordinates. As they are now, it looks like your UVs are taking up this much room (see red area):
And that's why it gives the impression that your texture is blurry. What you need to do is make your UVs take up more space, like this:
There are 2 ways to achieve this.
Scale UVs up: Import your model into Blender, and change the UV mapping of the mesh to occupy more of the [0, 1] range.
Scale texture down: You could get creative with the texture.repeat property and use it to scale down your texture to match your existing UVs. Then you'd need to offset it so it's centered correctly. Something like:
texture.repeat = new THREE.Vector2(10, 10);
texture.offset = new THREE.Vector2(xx, yy);
I'm trying to use Three.js to generate some points with Three.Points, and then make the points themselves revolve around a single point (or mesh). I've generated the points randomly in a cylinder region as mentioned in this answer and reviewed posts such as this one, which doesn't seem to work as it's rotating a mesh around a mesh.
Here's what I've got so far:
//Mesh that is to be revolved around
const blackHoleGeometry = new THREE.SphereGeometry(10, 64, 64);
const blackHoleMaterial = new THREE.MeshBasicMaterial({
color: 0x000000
});
const blackHole = new THREE.Mesh(blackHoleGeometry, blackHoleMaterial);
scene.add(blackHole);
//Points that are supposed to revolve around the mesh
const particles = new THREE.PointsMaterial({
color: 0xffffff
});
const geometry = new THREE.Geometry();
// [...] code to generate random points
const pointCloud = new THREE.Points(geometry, particles);
pointCloud.rotation.x = Math.PI / 2; //to rotate it 90*
You can see a full demo here. How can I have the points all revolve around the sphere mesh, as in each vertex of the point "cloud"'s geometry revolving around a center point, or the mesh like a planet and a star?
Couple problems with you code, but here is an updated fiddle for you: https://jsfiddle.net/pwwkght0/2/
So when you create your Three.js scene you want to keep all of your code in the init function. So I moved everything in there and then I called init outside of the variable. When you do this, init will create you scene until it reaches the last line and call animate. You want to call animate instead of render because animate will request animation frames and call render on each.
function init() {
//do all the things to make the scene
function animate() {
requestAnimationFrame(animate);
orbit();
controls.update();
render();
}
function render() {
renderer.render(scene, camera);
}
animate();
}
init()
So now that you are requesting animation frames, it's time to make things orbit. I made a very simple function to grab your point cloud and rotate it on its z-axis, to simulate it rotating around the sphere. Notice how orbit is called in animate:
function orbit() {
pointCloud.rotation.z += 0.01;
}
You can take this a step further and have each point rotate at a different speed around the sphere by accessing pointCloud's children property.
I'm using a plugin that implements 360 / VR video into our video player. It does this by using Three.js to create a sphere and taking the video itself and making it the material the sphere is created out of. The viewport is then set inside of the sphere to give it the 360 view.
The problem I'm running into is that the material is placed on the sphere using THREE.DoubleSide (THREE.BackSide would also work since we're only viewing it from the inside of the sphere), but the image is inverted since we are viewing it from the inside.
Is there a way to invert the image material that is placed on the sphere?
One way to create a spherical panorama, that is not inverted, is to use this pattern:
var geometry = new THREE.SphereBufferGeometry( 100, 32, 16 );
var material = new THREE.MeshBasicMaterial( { map: texture } );
var mesh = new THREE.Mesh( geometry, material );
mesh.scale.set( - 1, 1, 1 );
scene.add( mesh );
It is generally not advisable to set negative scale values in three.js, but in this case, since you are using MeshBasicMaterial which does not utilize normals, it is OK to do so.
three.js r.75
I'm trying to build a simple game that shoots stuff out of a barrel of a gun. So far I have a simple group with a cube and a cylinder added as the barrel. When I rotate the group (90 degrees at a time) the barrel moves around facing different directions and that all fine.
My problem is that I cannot for the life of me figure out a way to determine which way the barrel of my gun is pointing. I need to know how to identify the face of the cube that the barrel is attached to and to what part of the 3D world it is facing..either X+, Y+, Z+, X-, Y-, Z-. Forgive me if my lexicon is all wrong in describing this. I have not posted any of my attempts because they are not working at all.
Please take a look at this CodePen for an example of what I'm trying to do...
... and here's some code just because I can't post this on SO w/o it.
var geometry = new THREE.BoxGeometry( 50, 50, 50 );
var material = new THREE.MeshNormalMaterial();
var cube = new THREE.Mesh( geometry, material );
var cylgeo = new THREE.CylinderGeometry( 10, 5, 100, 32 );
var cylmesh = new THREE.Mesh( cylgeo, material );
cylmesh.rotateZ(Math.PI/2);
cylmesh.translateY(35);
var group = new THREE.Group();
group.add( cube );
group.add( cylmesh );
scene.add(group);
First, construct your "gun" so the barrel, by default, points up the positive-z axis by modifying your code like so:
cylmesh.rotateX( Math.PI / 2 );
Add a helper axis to your scene so your can see what you are doing:
scene.add( new THREE.AxisHelper( 100 ) );
In this configuration, when the parent group has rotation zero, the barrel of the gun points up the positive-z axis.
If the parent group is rotated, you can get the direction the group (and hence the barrel) is looking like so:
var vector = new THREE.Vector3(); // create once an reuse
...
group.getWorldDirection( vector );
The returned value of vector will be unit-length vector pointing in the same direction as the barrel.
three.js r.75
I have created a cube (skybox) that uses different materials for each side. There is no problem with that using MeshFaceMaterial:
var imagePrefix = "images-nissan/pano_";
var imageDirections = ["xpos", "xneg", "ypos", "yneg", "zpos", "zneg"];
var imageSuffix = ".png";
var skyGeometry = new THREE.BoxGeometry(1, 1, 1);
var materialArray = [];
for (var i = 0; i < 6; i++) {
materialArray.push(new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture(imagePrefix + imageDirections[i] + imageSuffix),
side: THREE.BackSide
}));
}
var skyMaterial = new THREE.MeshFaceMaterial(materialArray);
var skyBox = new THREE.Mesh(skyGeometry, skyMaterial);
skyBox.name = "interiorMesh";
scene.add(skyBox);
However, now I would like to add a material to one of the faces of the cube and combine the materials on this face of the cube.
So basically I would have one material on 5 faces and 2 materials on 1 face of the cube - I want to overlay that 'original' texture with another transparent png so it covers only a specific part of the original image. Both images have the same dimensions, only the new one is partially transparent. Is it even possible to do with CubeGeometry? Or do I need to do it with planes? Any help greatly appreciated!
You can for sure change material of one of faces. You cannot use two materials for one face though.
I would recommend creating additional texture as combination of previous two, making it into separate material and assign it to sixth face of the cube when needed. If it is possible, merge those images beforehand in your graphic editor of choice. If you can only do it in runtime, you will either have to use canvas to merge them or shader as recommended by #beiller.
I wouldn't recommend transparent planes, transparency can be very tricky sometimes and render in a weird way.
something similar is discussed here - Multiple transparent textures on the same mesh face in Three.js