Threejs - Maintain aspect ratio while adding texture map to threejs object - javascript

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

Related

three.js map mesh.geometry.attributes.uv

I am currently working on a 3D configurator.
So I should be able to import a logo on a FBX object, which normally already have UV coordinates.
The problem is : I am struggling since 3 days ago, trying to import a texture on a mesh but I can't map it using his UVs coordinates.
So, I have a texture with a logo.
When I map it on a simple Cube, no problem, it is working :
But when I try to apply the same texture to my mesh :
The texture is cropped.
So I've been looking inside the mesh json tree and I found it :
So there are uv coordinates, but it seems different from my cube because, when I look to his json, I don't find the same tree which is (on the cube) :
And finally, this is my code :
if(myMesh.name == 'Logo'){
// Texture
var texture = new THREE.TextureLoader().load('img/logoTesla_Verre_green.jpg', function(){
texture.needUpdate = true;
// Material
var material = new THREE.MeshLambertMaterial( {map: texture, morphTargets: true} );
material.needUpdate = true;
// Geometry Cube
var geometry = new THREE.BoxGeometry( 40, 40, 40 );
// Cube
var cube = new THREE.Mesh( geometry, material);
scene.add(cube);
// Duplicate logo mesh for testing
var newGeometry = myMesh.geometry;
var newMesh = new THREE.Mesh( newGeometry, material);
newMesh.position.y = 100;
newMesh.geometry.uvsNeedUpdate = true;
scene.add(newMesh);
});
}
My question is : Should I use the geometry.attributes.uv object to map my texture ? If yes, how to do that ?
Or should I convert these UV coordinates to a geometry.faceVertexUvs ???
Please, help me, I am totally lost :)
Nevermind, it has been solved by exporting the .fbx again.
Now the mapping is working fine !
But I don't know why...
Thank you for your question and answer. I was having the same problem where my custom FBX I imported was only taking the bottom left pixel of the canvas as the color for the whole mesh. (I was using texture = new THREE.CanvasTexture(ctx.canvas); to get my texture).
The issue for me was that the FBX had no UV mapping! How I solved it was I imported the fbx to maya, opened up the UV editor (under the modeling menu mode got to UV->UV editor ) then in the UV editor there was a Create section and I hit one of those options (i chose cylinder) and then exported it with the default fbx settings. I am very grateful this worked.
You can see the result of using a canvas context as a custom FBX texture here:
www.algorat.club/sweater

Texture on Sphere fuzzy after version upgrade

After upgrading from r67 to r86, our footballs are not very sexy anymore. Did anyone have similar issues in the past?
The code that used to render the spheres nicely, messes up the texture (and some lighting, but I can live with that) in version r86.
The part that creates the spheres:
const material = new THREE.MeshPhongMaterial({ map: texture, transparent: false });
material.alphaTest = 0.5;
const geometry = new THREE.SphereGeometry(radius, res, res);
const mesh = new THREE.Mesh(geometry, material);
Fiddle using r86.
In my comment, I suggested checking the UVs. My suggestion to try different min/mag filter values (http://threejs.org/docs/#api/constants/Textures) was more to correct the image quality, than the texture mapping its self.
What I didn't notice was that your texture was already spherical. The standard linear filter mapped the texture, well, linearly. The weighting/averaging of the linear filter caused the mapping to become compressed toward the top (and bottom, though it wasn't noticeable).
Setting texture.minFilter = THREE.NearestFilter; ditched the weighting/averaging of the texture coordinates, instead mapping to the nearest pixel, which was perfect because of your spherical texture.

Making a 3d Earth, made up of particles with Three.js

I am trying to replicate this effect: http://www.hys-inc.jp/ The only difference is that I want the particles to be positioned in such a way, that they resemble the Earth - a 'textured face' if you will.
Browsing through their code, this is what they use to set up the particles group:
var map = THREE.ImageUtils.loadTexture('/admin/wp-content/themes/hys/assets/img/particle.png');
var m = new THREE.ParticleSystemMaterial({
color: 0x000000,
size: 1.5,
map: map,
//blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true
});
var p = new THREE.ParticleSystem(g, m);
scene.add(p);
This is all great, but how do I position them along a sphere to resemble the planet? I know how to do it in 2d rendering context, using a picture and pixels scanning to get the right coordinates for the particles' position, but I am clueless how to do it in 3d...
Any help is more then welcome
If you have a grid of pixels that represents color values showing the surface of the earth in 2 dimensions as particles, to project it to 3 dimensions requires a sphere projection method. You can take a look at this question for the implementation of mercator projection.
how map 2d grid points (x,y) onto sphere as 3d points (x,y,z)
There are many methods for accomplishing this with a good deal of variation. Stereographic is another common approach : http://en.wikipedia.org/wiki/List_of_map_projections

Three.js: Combine materials on a single face of cube (that uses multiple materials)

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

How to get rid of tile outlines when tiling textures to a mesh?

I'm creating a sphere and attaching images to each face of the sphere. In my code I have sphere 12 sections by 6 sections high. I've managed to tile the textures by setting the wrap to repeating and setting the repeat size like so:
var texture = new THREE.ImageUtils.loadTexture( path );
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( geo_width, geo_height );
return new THREE.MeshBasicMaterial({ map: texture, side: THREE.BackSide, overdraw: true });
It works but now I have these lines between each texture. Is there a way to get rid of them or is there another technique for face-tiling that I should be using?
The lines are the opposite edge of each texture tile appearing at the edges of the geometry. This is what repeating textures do, which is not appropriate in this case.
You don't say what happens when you don't use repeating, but it sounds like what you need to do is adjust the texture coordinate generation so that the coordinates are 0...1 on each tile rather than only on the “0th tile” of the entire sphere.
I don't know Three.js so I can't advise you specifically on its API, sorry.

Categories