Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ambiguity with texture transformation and texture cloning #12788

Closed
2 tasks done
pailhead opened this issue Dec 2, 2017 · 8 comments
Closed
2 tasks done

Ambiguity with texture transformation and texture cloning #12788

pailhead opened this issue Dec 2, 2017 · 8 comments

Comments

@pailhead
Copy link
Contributor

pailhead commented Dec 2, 2017

One of the more recent threads on stack overflow suggests modifying geometry to index into a texture atlas. . I believe i've seen the same answer before though.

I also remember three.js had an issue when cloning the texture, they would get duplicated on the gpu.

This conversation happened a while ago:
#5876

This PR more recent:
#11863

Docs say:

var texture = new THREE.TextureLoader().load( "textures/water.jpg" );
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 4, 4 );

if i add:

var texFoo = texture.clone()
texFoo.repeat.set(2,2)

var texBar = texture.clone()
texBar.repeat.set(6,6)

What should the expectation be here? Mine is that some UV attribute (call it channel0 for example) would get scaled by the .repeat value of the texture, and display all the textures with their appropriate values?

var myMaterial = new THREE.MeshPhongMaterial({
  map: texture,
  specularMap: texFoo,
  normalMap: texBar,
}) 

And will this still upload only one image to the gpu?

var oneGeometry = new BoxGeom()
var squares_5x5_units_in_world_space = loadTexture()

for ( var i = 0 ; i < 1000 ; i ++ ){
   var mesh = new THREE.Mesh( oneGeometry , new Material())
   var meshScale = Math.random()
   mesh.scale.multiplyScalar(meshScale)
   mesh.position.set(Math.random(),Math.random(),Math.random())

   mesh.material.map = squares_5x5_units_in_world_space.clone() //should still use one image?
   mesh.material.map.repeat(meshScale, meshScale)
}

I guess I can test both.

Three.js version
  • Dev
  • r88
@pailhead
Copy link
Contributor Author

pailhead commented Dec 2, 2017

t1.wrapS = THREE.RepeatWrapping
t1.wrapT = THREE.RepeatWrapping

t1.repeat.set(10,10)

mesh.material.map = t1
const t2 = t1.clone()
t2.repeat.set(5,5)
t2.rotation = Math.PI / 2
t2.needsUpdate = true;
mesh.material.specularMap = t2
mesh.material.needsUpdate = true

with material.map, only that transformation is honored

tdiffuse

with material.map === null, the transformation from specularMap is used

tspecular

I'd maybe edit thus note from the docs for more clarity:

Note: The repeat property is a convenience modifier and only affects the Texture's application to the first set of UVs on a model. If the Texture is used as a map requiring additional UV sets (e.g. the aoMap or lightMap of most stock materials), those UVs must be manually assigned to achieve the desired repetiton.

@pailhead
Copy link
Contributor Author

pailhead commented Dec 2, 2017

On the second question:

for ( let i = 0 ; i < 100 ; i++ ){
  const m = new THREE.Mesh(mesh.geometry, new THREE.MeshBasicMaterial({map:t1.clone()}))
  m.material.map.repeat.set(Math.random(),Math.random())
  m.material.map.needsUpdate = true
  m.position.set(Math.random(),Math.random(),Math.random()).multiplyScalar(100)
  scene.add(m)
}	

Yields:

memory:
   geometries: 1
   textures: 101

However, this code:


for ( let i = 0 ; i < 100 ; i++ ){
  const m = mesh.clone()
  m.material = new THREE.MeshBasicMaterial({map:t2.clone()})
  m.material.map.repeat.set(Math.random(),Math.random())
  m.material.map.needsUpdate = true
  m.position.set(-Math.random(),-Math.random(),-Math.random()).multiplyScalar(100)
  scene.add(m)
}	

Also yields:

memory:
   geometries: 1
   textures: 101

Which is interesting. I see the texture.image and mesh.geometry more or less the same, they are wrappers around some data, that needs to be put on the gpu.
Mesh is the wrapper that manages how that data is being used, taking care of how the draw calls are set up. It has a transformation matrix, the same as Texture does now. I kinda expect the image to be 1:1 to texture, because it's a bunch of pixels, the rest of the stuff is about how webgl interprets it?

All i did here is define how this data (image) is being interpreted (texture), i still want to use the same data, the same as i do the geometry.

Also might be worth visiting why is this transformation on a texture at all? The material seems like it will always honor only one texture's transformation. The transformation is thus one to one with the material. The material also does most of the draw call management, where this uniform ends up being used.

This would make more sense:


for ( let i = 0 ; i < 100 ; i++ ){
  const m = mesh.clone()
  m.material = new THREE.MeshBasicMaterial({map:t2})
  m.material.mapTransform.repeat.set(Math.random(),Math.random())
  m.position.set(-Math.random(),-Math.random(),-Math.random()).multiplyScalar(100)
  scene.add(m)
}	

Expect:

memory:
   geometries: 1
   textures: 1

With the transform achieved.

material.map 
material.mapTransform
material.specularMap
material.specularMapTransform
...

or

material.uv0transform

or maybe even

for ( let i = 0 ; i < 100 ; i++ ){
  const m = mesh.clone()
  m.material = new THREE.MeshBasicMaterial({map: new THREE.TextureTransform(t2)})
  m.material.map.repeat.set(foo,bar)
  m.position.set(-Math.random(),-Math.random(),-Math.random()).multiplyScalar(100)
  scene.add(m)
}	

@pailhead pailhead changed the title Texture transformation, what state is it in currently? Ambiguity with texture transformation and texture cloning Dec 4, 2017
@pailhead
Copy link
Contributor Author

pailhead commented Jan 19, 2018

Thanks to @usefulthink for pointing this out:
https://github.com/mrdoob/three.js/blob/dev/src/renderers/WebGLRenderer.js#L1991-L2061

While i'm not a huge fan of this, perhaps all that's needed is to document it.

Texture classes have a transform property. Materials can use multiple textures, but also have a single transform property. Three does voodoo magic under the hood to chose which texture's transform to honor. This is the list...

@pailhead
Copy link
Contributor Author

pailhead commented Feb 2, 2018

#8278

@pailhead
Copy link
Contributor Author

pailhead commented May 30, 2018

Same issue i think:

#12608

Textures are probably not the best place to have the transform ${name}Map slots might be better.

Can easily be solved / prototyped with onBeforeCompile.

http://dusanbosnjak.com/test/webGL/three-materials-extended/webgl_materials_extended_multiple_uvs_props.html

@pailhead
Copy link
Contributor Author

An example for an interface that treats textures independently:
#14174

@Mugen87
Copy link
Collaborator

Mugen87 commented Mar 24, 2020

Closing since this issue is essentially a duplicate of existing ones.

@mrdoob
Copy link
Owner

mrdoob commented Mar 30, 2023

Took just a bit too long but #25721 finishes all the work solving this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants