This will concerns only polygonals faces (object's faces with more than 4 edges)..
In 3DSMAX there are 3 exporting modes for .OBJ : Triangles, Quads and Polygons.
I've made many tests and get the same results with the two available workflows (importing .obj with OBJLoader and importing .js via convert_obj_three.py) :
polygons are not supported (see this image)
quads is ok for most polygonals objects, but three.js generates additionnals parasites faces onto some of them
The best result is obtained by setting export to Triangles mode (and thus to export heavier models), is it a known problem ?
I don't think it's a known problem, but rather something threejs just doesn't do. In 3d it's easier to deal with triangles than quads or polygons. I'm not 100% sure, you might want to check on github
Related
I am creating an HTML5 web adventure game and making tilemaps with Tiled.
Even with Texture Packer, I seem to be exceeding max cache of texture units as I'm getting error
Texture cache overflow: 16 texture units available
WebGL Stats shows the limit is 16 for ~70% of devices. My browser, as shown here, supports 16 texture units:
In game, I opened Chrome console to check WebGL specs:
WebGL2RenderingContext.MAX_TEXTURE_IMAGE_UNITS = 34930
WebGL2RenderingContext.MAX_VERTEX_TEXTURE_IMAGE_UNITS = 35660
WebGL2RenderingContext.MAX_COMBINED_TEXTURE_IMAGE_UNITS = 35661
This is a bit confusing as this article shows output should be more in the 0-10 range, not 30,000 range:
maxTextureUnits = 8
maxVertexShaderTextureUnits = 4
maxFragmentShaderTextureUnits = 8
My question(s):
How can I determine which images in my packed texture atlas are causing the issues? I.e., how can I check the total textures?
Is it possible to force a higher cache limit?
The way to check those values is
const maxFragmentShaderTextureUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
const maxVertexShaderTextureUnits = gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS);
const maxTextureUnits = gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS);
Further, those values have to do with how many textures you can access in a single shader not how many textures you can have in total.
They also have nothing to do with a "cache"
In your case you probably want to combine your textures into a single texture atlas (one texture that contains all your tiles).
Here's some code that does that.
It loads a tiled json file, then loads all the referenced images, it then creates a 2D canvas and copies the tiles from each image into the canvas, remapping the tiles in the maps to match. When it's finished it uses the canvas as the source of the tile texture. Normally I'd do this offline but it was nice to just be able to hit "reload" to see a new map that I left it at runtime.
In that same library is a shader that draws tilemaps including flipped and rotated tiles. In other words, to draw a tiled map it's one draw call per layer and only 2 textures are used. One texture holds the tile images (the texture created above). Another texture holds a layer of a tiled map. The shader reads the tiled map texture and uses that to draw the correct tile from the tile image texture. You can see an explanation of this technique in this article
BTW: The library with the tiled loader also has a shader that can selectively adjust the hue of a sprite. The library was used with a few games, for example this game
How can I determine which images in my packed texture atlas are causing the issues? I.e., how can I check the total textures?
You manage the textures, not WebGL, so if you want to know how many you're using add some code to count them.
Is it possible to force a higher cache limit?
No, but like I said above this has nothing to do with any cache.
My guess is you're using some library or your own code is generating a shader and that you're adding more and more textures to it and the shader generator therefore generating a shader that uses too many textures. The question is why are you using so many textures in the same draw. No 2D game I know of uses more then 2 to 6 textures at in one draw call. The game might use 10000 textures but to draw a single sprite or a layer of tilemap it only needs 1 or 2 textures.
To put it another way. A typical game would do
for each layer of tilemap
bind texture atlas for layer (assming it's different than other layers)
draw layer
for each sprite
bind texture for sprite
draw sprite
In the example above, even if you had 10000 textures only 1 texture is ever in use at a time so you're hitting no limits.
EDIT:
I had a question about exporting to obj and mtl but discovered that I could export from three.js using GLTFExporter.js and had success getting the geometry and texture out of three.js from that.
The issue I'm having with the GLTF Exporter is that I have textures that have offset and repeat settings that seem to not be exported from three.js when I open the file in Blender. In Blender the whole texture takes up the MeshPlane that used to only have a small part of the texture showing in Three.js scene.
Might anyone know what I could add to the GLTF Exporter to be able to record and keep the repeat and offset texture settings?
Many Thanks :)
I've hit this myself.. and as far as I know, the answer is No.
Offset and Repeat are THREE.js specific features. Some other libraries have equivalents.. some engines use direct texture matrix manipulation to achieve the same effect.
One workaround is to modify your models UV coordinates before exporting to reflect the settings of texture.offset and texture.repeat.
You would basically multiply each vertex UV by the texture.repeat, and then add texture.offset. That would effectively "bake" those parameters into the model UV's, but then would require you to reset .repeat and .offset back to 1,1 and 0,0 respectively, in order to render the model correctly again in THREE.js.
Here's a slightly relevant thread from the GLTF working group:
https://github.com/KhronosGroup/glTF/issues/107
Is there a way to map an image onto the side of a cylinder with threejs? Would I have to map individual portions of the image onto each face on the side of the cylinder, or is there a faster way to do this? Thanks!
For all texture allocation and mapping you probably want to know about UV Mapping which you typically do before importing into Threejs. All 3D modeling programs have that functionality, Blender is the most popular and arguably the best among the free ones.
I'm trying to load with three.js the same image in a large number (~ 1000) of bidimensional shapes but with different offsets in every shape.
I've taken this demo from the official website and customized it into this other demo, with all my shapes and a random background texture.
The problem is that if I clone the texture once per shape the page eats a lot of RAM and it ends up crashing.
You can see this in action by going in the javascript and changing the comments in the addShape function (you'll find the instructions in the code).
I've done some research and found some results, like this open issue or this older question where it's recommended to clone the texture; anyway nothing seems to work in my example.
Am I doing something wrong? It's changed something since these last posts about this problem?
Maybe I´m misunderstanding the problem, but why don´t you change the UV coordinates of the individual shapes to align the texture and use just one texture?
From documentation:
Geometry.faceVertexUvs
Array of face UV layers, used for mapping textures onto the geometry.
Each UV layer is an array of UVs matching the order and number of
vertices in faces.
To signal an update in this array, Geometry.uvsNeedUpdate needs to be
set to true.
I'm finally understanding the performance impact of merged geometries. I've noticed the GPU has draw calls for all shared geometries combined with materials (or perhaps its just the material count). My question is why are developers forced to figure out how to merge geometries when its clear that the three.js will just divide everything out of your merged geometry anyways?
I'm probably missing something.
It is difficult to make general statements about WebGLRenderer performance, because each use case is different.
But typically, performance will improve if the number of draw calls is reduced. If you have multiple meshes, and they all share the same material, then by merging the mesh geometries into a single geometry, you reduce the number of draw calls to one.
Remember, this approach makes sense only if your multiple meshes are static relative to each other, because once merged, they cannot be transformed independently.
And yes, it is true, that if your mesh has multiple materials, the the renderer will break the geometry up into smaller geometries -- one for each material -- prior to rendering.
Here is a useful tip: In the console, type renderer.info and inspect the resulting object returned. This will give you insight into what is going on behind the scenes.
You can also display renderer.info live on your screen by using this utility.
three.js r.68