Jump to content

Changing the uScale and vScale of the texture on an object-by-object basis


CeeJay
 Share

Recommended Posts

Hi there

I've spent a few hours trying to look into changing the uScale and vScale of the texture on an object-by-object and I'm totally stuck.

To give you a simplified example of what I'm trying to do:

  • Let's say I have lots of planes that are supposed to represent tiled walls.
  • The planes are all different sizes and shapes, e.g. one might be 1×1, another 1×2, another 4×3, ... and so on.
  • The same tiles are used on all of the walls, and I'd like to use the same repeating texture.
  • The texture needs to have the same relative size everywhere it is used; e.g. it would look weird if the tiles on a 1×2 wall had the same height but were twice as wide as the tiles on a 1×2 wall.
  • This means that I will need to use a different uScale and vScale on each plane.

However I have the problem that the uScale and vScale are set on the texture, not the planes they are applied to - changing the scale for one changes the scale for all.

After a few hours of Googling, as far as I can tell, if I want to achieve the effect I am going for I have three options, none of them very good:

  1. Build all of the bigger walls out of 1×1 walls.
  2. Create a different material and a different texture for each combination of uScale and vScale that I need in the scene.
  3. Write my own custom shader material that has the options to set uScale and vScale independently for each object.

(1) and (2) are doable but I'd worry they're inefficient.

(3) would be efficient but I'm struggling to make my own shader material that has all of the features of Babylon's default shader material, and work out how to pass custom variables to it. Googling has uncovered various forum posts and tutorials that cover some of the steps needed to do this, but I can't find all of the documentation I need for the whole process.

After being stuck for a few hours I thought I really ought to ask here to see if anyone knows something obvious I'm missing!

Thanks for your help!

Link to comment
Share on other sites

Hiya @CeeJay, welcome to the forum!  What a great challenge, well-researched, and a well-presented post here.  Nice job!  Well, I guess there's a few who would have wanted to see a playground example of the issue, but not a big deal, here.  You explained it perfectly. 

First, let's ping @NasimiAsl, the local God of Shaders... and see what he has to say.  (he saw me use his name in this post, so we've rattled his cage)

Yes, you want the tiling (all one texture) to be the same size-scale on ANY-sized wall, but the UV mapping on various sized walls... is stretching-to-fit... so big walls have bigger tile-squares, and little walls have little tile-squares (not-wanted).

Perhaps...  mesh.materialWrapPerMeshScale = true/false ?  Or maybe mesh.allowMaterialScaling = false ?  (neither exist, yet)

These are strange ideas, because, in this case, we are allowing the mesh to "have a say" in how materials are applied to it.  Interesting, perhaps not a good idea, and perhaps not possible.  (I am pretty good at thinking-up poor/impossible solutions.)  :)  I'll keep thinking, but, you may be right... custom shader.  I can't help much with that.  Others are nearby, though.  This seems to be a rather important issue for high-efficiency world-building.  It is almost imperative that the same texture CAN be used on MANY wall sizes, and the tiles look the same, no matter the wall size.

Something tells me we are missing something simple, here.  I can't hardly believe that we have not encountered this challenge, earlier.  Maybe it is only because I'm not into world-building very much.

Link to comment
Share on other sites

Ah, okay, that's a lot better!

So basically I've made this function:

	function setUVScale(mesh, uScale, vScale) {
		var i,
			UVs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind),
			len = UVs.length;
		
		if (uScale !== 1) {
			for (i = 0; i < len; i += 2) {
				UVs[i] *= uScale;
			}
		}
		if (vScale !== 1) {
			for (i = 1; i < len; i += 2) {
				UVs[i] *= vScale;
			}
		}
		
		mesh.setVerticesData(BABYLON.VertexBuffer.UVKind, UVs);
	}

Calling it on each mesh seems to work as intended - can you think of any side-effects or am I golden?

Link to comment
Share on other sites

i really disagree about change uv in engine Buffer it is my personal advise because i think  when we scale the uv we can not use correct texture we just use the Tiled texture.

we can scale that in shader with best performance and very flexible 

* it used from shader Builder 

see this :

http://www.babylonjs-playground.com/#1QQOJR#0 

http://www.babylonjs-playground.com/#1QQOJR#1

notic : you most scale uv per texture

more http://www.babylonjs-playground.com/#1QQOJR#2

how can you manage 2 or 3 texture in your floor or wall ?

http://www.babylonjs-playground.com/#1QQOJR#3

http://www.babylonjs-playground.com/#1QQOJR#4

other way for make uv use planar Mapping

http://www.babylonjs-playground.com/#2KMG5C#1   plan position.xy

http://www.babylonjs-playground.com/#2KMG5C#2   plan position.zy

 

 

 

 

Link to comment
Share on other sites

Hi NasimiAsl, thanks for your reply!

I'm still new at this, so I might not have understood them fully, but I did my best to read through some of the code examples you gave. 

I notice in your GLSL code, you have the uScale and VScale hard-coded rather than use variables. This was actually something I was stuck on when I was trying to get the shaders working.

I know it's possible to pass in variables to avoid having to hard-code them. I've managed to do that a few years ago when I was playing around with THREE. I've yet to figure out how to do it in Babylon but give me some time, I've only just started using the framework ^_^;;

However I think I am limited to two types of variable that I can pass in:

  • Uniforms are set on a per-shader basis. If I make the uScale and VScale uniforms, then I'll need a new shader material for each object.
  • Attributes are set on a per-vertex basis. If I make the uScale and VScale attributes, then I'll need to enter them in once for each vertex.

I think I'm no better off than I was before, unless I've missed something like a per-object variable that I can pass to the shader.

Link to comment
Share on other sites

@CeeJay -

perhaps I don't understand correctly, but if I do, then you might want to consider testing using the x and y scale of the plane meshes to generate the results you desire, then apply those values to the U and V scale of the textures. This might provide you with the flexability you're looking for, and also other benefits you haven't yet discovered. Again, I hope I understand the questions, and hope perhaps this might be an alternative to altering the U and V scale of the textures in the variables so that you aren't required to dispose of these once you find the desired UV scale values - as memory may become a huge issue depending on your scene.

Cheers,

DB

Link to comment
Share on other sites

Just a warning here: to set an UV scale per object through a specific shader, it will require writing a specific shader and thus you won't be able to use all the features provided for free by the StandardMaterial.

To your point:

Quote

Uniforms are set on a per-shader basis. If I make the uScale and VScale uniforms, then I'll need a new shader material for each object.

Nope they could be set on a per mesh basis as well.So this could work great in your case.

Link to comment
Share on other sites

 

34 minutes ago, Deltakosh said:

Just a warning here: to set an UV scale per object through a specific shader, it will require writing a specific shader and thus you won't be able to use all the features provided for free by the StandardMaterial.

I was looking through some of the source code and I found the code for the Pixel/Vertex shaders.

Yeap there's a lot there!

I was considering trying to copy it with some lines changed, but figured that was probably quite a complex thing to do...

34 minutes ago, Deltakosh said:

Nope they could be set on a per mesh basis as well.So this could work great in your case.

Arg, I'm sorry, I was looking but I couldn't find anything about that anywhere. :(

I don't suppose you know where I might find some documentation or an example? Or failing that, a few variable names I should be looking for in the babylon.2.4.max.js source code?

Link to comment
Share on other sites

My hint is here: you should stick with the function you wrote: This works perfectly as long as you change it from time to time (not every frame I mean)

Here is an example of mesh value updating the shader:

https://github.com/BabylonJS/Babylon.js/blob/master/src/Materials/babylon.standardMaterial.ts#L520

(But I must admit this is not something I suggest. Shader should only be controlled by material for caching sake).

Link to comment
Share on other sites

Hi again, guys.  I'm not sure where everyone is going, here, but if your objective is to make MANY sizes of wall, and have the pattern look the same, no matter the size...

...then you COULD try a reflection texture in coordinatesMode = 4.

http://www.babylonjs-playground.com/#1QQOJR#7

This SEEMED like a perfect solve... until I moved the camera around.  Then, all hope for my idea... was lost. :(  Wingnut - swing and a miss... strike 2.

Speaking of 2, coordinatesMode = 2 is interesting, too.  A little better than 4, but I don't know how it would look on room walls.

Link to comment
Share on other sites

  • 2 years later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...