Three.js tile which has multiple textures using plane geometry - javascript

So I am trying to build a 3D based world consisting of tiles.
I have successfully managed to do this using the plane geometry and height values etc. But now I have come to a point where I possibly have to change everything.
The problem is that I want a tile to have multiple textures (using a shader because I want to blend them). I was able to do this globally (so each tile would have same textures + using some uv mapping).
However I fail to understand how I would be able to specify which tile has which textures (and I have about a 100 textures), since the plane geometry has only 1 shader material. And I am also not sure if it is a good idea to send 100 textures through a shader?
So my questions basically boil down to this:
Is there a decent/performant way to link the tile/vertices to the textures, so I can keep the plane geometry.
- If yes: how?
- if no: Should I create each tile separately (so a plane of 1x1) and merge them somehow together (performance/vertex blending?) so it acts as a single plane (in this case the merged plane consists of many 1x1 planes) and use the shader per tile (a 1x1 plane)?
How are these things generally done?
Edit:
Some extra information because it seems that my question is not really clear:
What I want is that a tile (2 faces) has multiple "materialIndexes" to say so. Currently I need to have 1 tile to have 3 textures, so I can blend them in a shader with a specific algorithm.
For example I want to have a heart shape (red heart/black background) as texture and than based on the colors I want to blend/change the other 2 textures so I can get for example wooden heart and a blue background. Or for example I should be able to blend 4 textures evenly on the square, each take 1/4 of the square. But the point here is not what has to be done with the textures, but how that i can specify such 3, 4, or more textures for my faces/tiles.

I think you have to take a look at what is called a multi material object.
THREE.SceneUtils.createMultiMaterialObject( geometry, materials );
If you google for those you find several examples. Like this answer on a similar question.
Or take a look at THREE.MeshFaceMaterial. You can use it to assign multiple materials for the same geometry.
var mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
Where materials is an array of materials and the faces use a materialIndex paramater to get appointed the right material
Similar questions here and here
EDIT:
Here is a fiddle to demonstrate that it is possible. I used the code from one of the links.

If your textures have all the same size, you can do the following:
Create a texture 10x the size of an individual texture (you can do that automatically, create a canvas, draw the texture file on the canvas at the correct coordinates, get the texture from the canvas). This allows for 100 (10x10) textures.
Assign to the tiles a base uv coordinates in the range 0 - 0.1 (since a single texture occupies 1/10th of the global texture),
Add to the previous uv values the offset of the individual texture (for the second texture, offset of 0.1 in u and 0 in v, for the 3rd texture 0.2 and 0; for the 10th 0 and 0.1.

Related

efficient way to render large scale terrestrial map in three.js

I need some guidance and help. I am new to three.js and want to make a terrain with given terrestrial map image for texture and given heightmap data.
For this, i have to deal with large scale terrestial map image like 4104x1856
If i create a plane mesh with such a large number of vertices and use height map in those vertices and map terrestian texture in that elevated surface, it becomes so slow.
For this, i created mesh of segments 4104x1856, but i am sure it is very oldschool and not optimum way of doing this.
I have two concern
can i do such a big scale in three.js ?
if yes, what are things that i should do in order to make it not only renderable but also efficiently interactivable.
Thank you in advance !!!

Creating lines with thickness and shadows in three.js for visualising 3D printing layers

I have been trying to figure out a way of adding thickness to lines that can receive shadows and look like solid objects using Three.js but the best result I managed to get so far is just thicker lines that do not look like 3D geometry.
The application is for an online 3D printing platform so I am trying to visualise the sliced geometry that is comprised of lines, similar to how other slicing software handles this, such as cura, as shown in the image below.
Generating mesh geometry from these lines would be most probably problematic as in some cases there are thousands of a lines in a single model so it will be too heavy.
Any suggestions on how to achieve the desired result in either three.js or another javascript library would be greatly appreciated!
So the idea is to render primitive covering your thick line area and in fragment decide if fragment is inside or outside the thick line compute 3D position and normal and render or discard; if not.
The idea is to pass polyline geometry for rendering to OpenGL that would produce just thin lines and use shaders to do the rest.
Vertex shader
will just pass stuff into geometry shader
Geometry shader
will take in 2 vertexes (line) and output 2 triangles (quad) covering line BBOX (line enlarged by line half thickness). This is relatively easy. Simply shift the line endpoints by perpendicular vector to the line of size equal to the half thickness. This must be done in plane parallel with camera screen plane (using basis vectors extracted from direct camera matrix). Do not forget to pass both vertexes in world and camera coordinates.
Fragment shader
simply from world coordinates test if point is inside your thick line:
so simply compute P' and compute distance between P,P'. That is called perpendicular distance between point and line. Its doable exploiting dot product IIRC:
t = dot(P-P0,P1-P0)
P' = P0 + t*(P1-P0)
d = |P'-P0|
from that you just compute the 3D coordinate (depth of the fragment), normal and either render with some directional light or discard;...
Take a look at full example of this technique for 2D cubic curves:
rendering thick 2D Cubics in GLSL

Texture cache overflow for WebGL HTML5 game

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.

Transforming plane to fit user-defined points

I'm trying to create a plane to fit four user-specified points. I tried creating the vertices and faces of a geometry manually, but while the geometry is created just fine, the mapped texture is warped at the boundary of the geometry’s faces.
What's the proper way to transform a plane given four coordinates?

WebGL triangles in a cube

In this tutorial author displays a cube by defining its 6 faces (6*4 vertices) and then telling webgl about triangles in each face.
Isn't this wasteful? Wouldn't it be better to define just 8 vertices and tell webgl how to connect them to get triangles? Are colors shared by multiple vertices a problem?
To make my concern evident: if the author defines triangles with indices array, why does he need so many vertices? He could specify all triangles with just 8 vertices in the vertex array.
Author of the example here. The issue is, as you suspected, to do with the colouring of the cube.
The way to understand this kind of code most easily is to think of WebGL's "vertices" as being not just simple points in space, but instead bundles of attributes. A particular vertex might be be the bundle <(1, -1, 1), red>. A different vertex that was at the same point in space but had a different colour (eg. <(1, -1, 1), green>) would be a different vertex entirely as far as WebGL is concerned.
So while a cube has only 8 vertices in the mathematical sense of points in space, if you want to have a different colour per face, each of those points must be occupied by three different vertices, one per colour -- which makes 8x3=24 vertices in the WebGL sense.
It's not hugely efficient in terms of memory, but memory's cheap compared to the CPU power that a more normalised representation would require for efficient processing.
Hope that clarifies things.
You can use Vertex Buffer Objects (VBO). See this example. They create a list of Vertices and and a list of Indexes "pointing" to the vertices (no duplication of vertices).

Categories