I have a problem with this warning I'm getting from three.js. The warning is: THREE.WebGLRenderer: image is not power of two (600x480). Resized to 512x512
I have tried adding THREE.LinearFilter, but it does nothing.
var texture = new THREE.TextureLoader().load(data[i]['image']);
texture.minFilter = THREE.LinearFilter;
var paintingGeometry = new THREE.BoxGeometry(1, 1, 1);
var paintingMaterial = new THREE.MeshPhongMaterial({
map: texture
});
var painting = new THREE.Mesh(paintingGeometry, paintingMaterial);
What are your suggestions? Thanks.
There isn't a problem here - all textures need power of two images. If you're having issues with how the texture is scaled and applied to your geometry you should check out the docs for THREE.Texture, specifically the wrap and repeat properties.
Related
I'm currently learning three.js. I wanna display a 16x9 photo in my scene.
This is the code for adding an Array of images to my scene:
const material = new MeshBasicMaterial({
map: loader.load(images[i]),
transparent: true,
opacity: 1,
});
const plane = new Mesh(new PlaneGeometry(imageWidth, 45), material);
plane.overdraw = true;
plane.position.x = i * (imageWidth + imageOffset);
plane.position.y = 0;
this.introImages.push({
obj: plane,
round: 1,
});
this.introImagesGroup.add(this.introImages[i].obj);
Now I'm getting the console warning:
THREE.WebGLRenderer: image is not power of two (1600x900). Resized to 1024x512
I have read that texture dimensions should be the power of two so it can be put into memory in an optimized way which makes me think if the way I'm putting my images in the scene is the correct way or if there is another way of putting images that don't follow this in three.js?
You probably don't want THREE.js to scale down your image, because you'd be losing resolution, so you want to scale it up to the next ^2. You have two options:
You could scale up your image and export it at a ^2 resolution 2048 x 1024 in your favorite photo editor.
You could dynamically generate a 2048 x 1024 canvas, draw the image onto it scaled up, and use that canvas as your texture source:
var imgURL = "path/to/whatever.jpg";
// Create image element
const image = document.createElement('img');
image.src = imgURL;
// Once image is loaded
image.onload = () => {
// Create canvas, size it to ^2 dimensions
var canvas = document.createElement('canvas');
canvas.width = 2048;
canvas.height = 1024;
// Draw image on canvas, scaled to fit
var ctx = canvas.getContext('2d');
var ctx.drawImage(image, 0, 0, 2048, 1024);
// Create texture
var texture = new THREE.Texture(canvas);
};
Then you can assign that texture variable to whatever material you want, and Three.js won't complain.
Edit:
If you want to avoid texture re-sizing, you could just change your texture.minFilter to THREE.NearestFilter or THREE.LinearFilter, and the engine won't give you warnings. The problem with doing this is that your textures could look grainy or aliased when scaled down, since they won't be Mipmapped
This could be the result you like, or it could look bad, depending on your project. You could see the effects of using NearestFilter in this example: https://threejs.org/examples/?q=filter#webgl_materials_texture_filters
I have read that texture dimensions should be the power of two so it can be put into memory in an optimized way which makes me think if the way I'm putting my images in the scene is the correct way or if there is another way of putting images that don't follow this in three.js?
In WebGL 1 you need POT textures for mipmapping. The mentioned warning disappears if you set the .minFilter property of your canvas texture to THREE.LinearFilter. Keep in mind that using mipmaps is not necessary for all scenarios.
Possibly dumb question but here goes. Three.js geometries have 'parameter' feilds associated with them, see the box geometry here...
box Geometry parameters
I am trying to update these parameters like this...
var nodeSize = 10;
var geometry = new THREE.CubeGeometry(nodeSize, nodeSize, nodeSize);
mesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial({side:THREE.DoubleSide}));
scene.add(mesh);
mesh.geometry.parameters.depth=20;
But of course, the geometry remains unchanged. Is there a way of updating the geometry by editing these parameters?
fiddle here https://jsfiddle.net/kn3owveg/2/
Any help appreciated!
parameters.depth is only used at geometry construction time. it has no effect when modifying it. you can think of it as read only.
Use the example at BoxGeometry and the gui on the right to see how to achieve what you want.
Gaitat is totally right, you can't change geometry with changing of parameters.
And there can be another solution. With scaling of your cube.
function setSize( myMesh, xSize, ySize, zSize){
scaleFactorX = xSize / myMesh.geometry.parameters.width;
scaleFactorY = ySize / myMesh.geometry.parameters.height;
scaleFactorZ = zSize / myMesh.geometry.parameters.depth;
myMesh.scale.set( scaleFactorX, scaleFactorY, scaleFactorZ );
}
...
setSize(mesh, 10, 10, 20);
jsfiddle example
Technically, scaling only creates the illusion of an updated geometry. I would say a better approach would be to reassign the geometry value of your mesh to a new geometry.
mesh.geometry = new THREE.CubeGeometry(newSize, newSize, newSize)
With this approach you can update any aspect of the geometry including depth segments for example. This is especially useful when working with non cube geometries like cylinders or spheres.
Here is a full rework of your original code using this approach, really only the last line has changed:
var nodeSize = 10;
var geometry = new THREE.CubeGeometry(nodeSize, nodeSize, nodeSize);
mesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial({side:THREE.DoubleSide}));
scene.add(mesh);
mesh.geometry = new THREE.CubeGeometry(nodeSize, nodeSize, 20);
I'm looking for an efficient method of overlaying a texture to cover a mesh. I'm not an expert, more a novice, when it comes to 3 dimensional mapping/objects. Below shows how I would like the end product to look.
When attempting to apply texture with the following code, the end result looks similar to below. I have not done any UV mapping, I believe my answer may be lay here. As you can see from the below image it roughly takes the general shade of the picture but I get the impression that the texture is being drawn between each vertice of the model rather than across the entirity.
var textureLoader = new THREE.TextureLoader();
var texture = textureLoader.load('resource/images/materials/Mahogany.jpg');
var STLLoader = new THREE.STLLoader();
STLLoader.load( 'test.stl', function ( geometry1 ) {
var meshMaterial = new THREE.MeshBasicMaterial({map:texture});
var mesh = new THREE.Mesh( geometry1, meshMaterial );
mesh.scale.set(1, 1, 1);
mesh.position.set(5, 20, 80);
scene.add(mesh);
});
The cube has the correct texturing, whereas my STL loaded mesh does not.
Please ignore the rotation of the object in the above picture, I will move to unioning my objects together once I have fixed my texturing issues.
Fairly new at asking questions on here so please do comment to help me expand my question if it's too general or not percise enough. Thank you.
You may use
THREE.MeshPhongMaterial()
instead of
THREE.MeshBasicMaterial()
THREE.MeshPhongMaterial() will wrap the material outside the object and we can get curved material as per the object.
I am using Three.js to generate a polyhedron with differing colors and text on each face, generated from a canvas element. For now, I'm sticking with polyhedra for which Three.js includes native classes, but at some point, I'd like to branch out into more irregular shapes.
There are a number of examples available online (including StackOverflow posts, like Three.js cube with different texture on each face) that explain how to do this with cubes. I haven't succeeded in finding any samples that show the same technique applied to non-cubes, but for the most part, the same process that works for CubeGeometry also works for TetrahedronGeometry and so forth.
Here's a simplified version of the code I'm using to generate the polyhedron:
switch (shape) {
case "ICOSAHEDRON" :
// Step 1: Create the appropriate geometry.
geometry = new THREE.IcosahedronGeometry(PolyHeatMap.GEOMETRY_CIRCUMRADIUS);
// Step 2: Create one material for each face, and combine them into one big
// MeshFaceMaterial.
material = new THREE.MeshFaceMaterial(createMaterials(20, textArray));
// Step 3: Pair each face with one of the materials.
for (x = 0; face = geometry.faces[x]; x++)
{
face.materialIndex = x;
}
break;
// And so on, for other shapes.
}
function createTexture (title, color) {
var canvas = document.createElement("canvas");
// Magical canvas generation happens here.
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
return new THREE.MeshLambertMaterial({ map : texture });
}
function createMaterials (numFacets, textArray)
{
var materialsArray = [],
material;
for (var x = 0, xl = numFacets; x < xl; x++)
{
material = createTexture(textArray[x], generateColor(textArray[x]));
material.side = THREE.DoubleSide;
materials.push(oMaterial);
}
return materials;
}
Cubes render perfectly using this technique, but with other polyhedra, the textures do not behave as expected:
It's hard to explain precisely what's happening here. Essentially, each face is displaying the correct texture, but the texture itself has been stretched and shifted as if to cover the entire polyhedron. In other words - looking at the shape dead-on - the upper-left face is only showing the upper-left portion of its texture, the upper-right face is only showing the upper-right portion, and so on.
The faces on the opposite side of the polyhedron shows no texture detail at all; only colors.
I had no experience with 3D rendering prior to experimenting with Three.js, so I imagine that there's some step I'm missing that is handled automatically by CubeGeometry but not its sister classes. I'd refer to other examples that have been posted, but most examples are rendering cubes, and those that don't are usually using solid colors.
What needs to happen for the textures on the non-cube shapes to be scaled and centered properly?
You need to set new UVs.
I made a simple example how to do it, don't know if it's the best way.
jsFiddle example
Update
geometry.faceVertexUvs[0] = [];
for(var i = 0; i < geometry.faces.length; i++){
// set new coordinates, all faces will have same mapping.
geometry.faceVertexUvs[0].push([
new THREE.Vector2( 0,0 ),
new THREE.Vector2( 0,1 ),
new THREE.Vector2( 1,1),
]);
}
I'm trying to apply a texture to a plane. I am using and image that is 256x256. Currently it just renders black. Can someone tell me where I'm going wrong?
//create the floor
var floorTexture = new THREE.ImageUtils.loadTexture( 'carpet.jpg' ); //256x256
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set( 10, 10 );
var floorMaterial = new THREE.MeshBasicMaterial( { map: floorTexture, side: THREE.DoubleSide } );
var floorGeometry = new THREE.PlaneGeometry(1000, 1000, 10, 10);
var floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.position.y = -0.5;
floor.rotation.x = Math.PI / 2;
scene.add(floor);
I can add more of my code if needed.
Thanks!
Can it be because you texture gets scaled down(so it can be repeated 100 times on the surface) and you just can't see the details of it? If the texture is dark itself this could be the matter. Maybe you try it with floorTexture.repeat.set(1, 1); to see if it actually gets applied.
Also you may consider to include your texture, so that anyone can test against it. I just ran your code in r.58 with a custom texture and it worked fine for me.
I just struggled with this myself for a while. Check the image's filesystem permissions. Mine were set to 640. When I changed them to 664, the image rendered as it should.
Your problem may be lack of ambient light in the scene, try adding a white ambient light to see if it solves your problem