Scaled/Nonscaled Textures in Components


#1

Hey Devs,

I have the following (abstract) problem in the plugin I’m writing: I’m defining a material, with a texture, which has a specific size. This size is important, as it represents a feature in real-world dimensions. The problem is, that if this material is assigned to a group/component, which is scaled/transformed, the texture is getting scaled, too, and therefore looses it’s proper dimensions. Because the material can be assigned to differently scaled drawingelements, it is important, that I find a way to prevent the texture from getting scaled (or scale it back, like it would be possible with the Face.position_material method, which is not avaliable for components/groups).

Does anyone see a solution for this problem? I would rather like not to use a workaround like exploding the component or assigning the material only to faces or something like that…

Thanks in advance for your ideas!


#2

I see a problem with the problem. The concept of a component definition is that its contents are completely isolated from the surroundings of its instances (like information hiding in software architecture). If different instances could affect the definition in various ways (have all textures at this/that scale, have all nested entities on this/that layer etc.), then there could not exist one common definition. It would contradict or lead to bad software design.

For your problem it would be ideal if one could choose to use the component concept (like inheritance from a definition) only for selected properties, say, I want my instances to inherit the same geometry from the definition, but not UV coordinates. But in SketchUp, all properties are together in the definition.

You could either make each component unique (groups) or work on raw (exploded) entities instead of components. For manual modelling, I often used a family of related components definitions for different scales (short, medium, long, very long), of which I chose an approximately fitting one and adjusted the instance to the exact scale. Then the texture stretching was barely noticeable.


#3

Thanks for your answer! I wonder why this problem hasn’t been adressed before. I understand the connection with the design concept of component definitions. But even in the non-api world, this concept has significant drawbacks for very simple use cases: If you have e.g. a simple wall component, add a brick texture to it and want to reuse it, scale it to a different length for example, it won’t work nicely. I think it is a design flaw, that there isn’t an api/nonapi way to prevent textures which are applied to a group/definition/instance from getting transformed/scaled with the component instance.


#4

There’s a work around trick using DCs…
In outline…
Make a tiny face ‘swatch’ using the desired textured-material, put it inside a DC - inside a 3d object, so it’s never seen.
This preserves the original texture size for later…
Now you have attributes/functions in the DC which spot its [re]scaling and that in turn runs a DC referring RB that scales texture of the material [copied] as it’s applied to the group within the DC…
You have the originally scaled material on the tiny face to fall back on each time.
E.G.

class DCFunctionsV1
###
...
###
def resize_material(vars)
    ### Usage as DC function: "Material"
    ###    =resize_material(oriMaterial,oriX,oriY,LenX,LenY)
    ### the 1st 3 arguments passed are custom - 'material-name' of small nested 
    ### group's material, and then that material's x/y size AND 
    ### the main DC's x/y size, in cm - e.g 100,100.
...

There's also my "DeScaler" tool... http://sketchucation.com/pluginstore?pln=TIG_Descaler If a selected group or component-instance has been scaled this 'descales' it, keeping it the same size, but now unscaled, whilst readjusting the textures to suit. Usage: Context-menu > TIG.Descaler [if suitable selection]

How to Scale Dynamic Components Material?
Dynamic "chevron" component. Dynamic panel made of diagonal planks
#5

Hey TIG,

I’m a newby regards to Ruby and DC. I’m also trying to make my component whereby the materials scale to the correct size. So I was trying your ‘DeScaler’. Nice tool, But the thing is… I kind of need the materials to adjust scale automatically (Because I’m not the end user of my model)

So I was trying to insert your work around into my model but I just can’t figure it all out :frowning:

The first steps i can handle, but than…

So if I understand correctly, there are DC attributes that do those think… Can you please help me to get a bit more into the good direction by telling which attributes I need tot us.

I pasted your ruby script into my ruby and assigned a material to it. And it pastes that material to my complete component. Only the scale isn’t correct. So my second question is…

Could you please explain this a little bit more?
For example: The first step is to make a surface inside a component. Do I make a component of that surface so I can easy change the scale and give those dimensions to the ruby?

Hope to here from you.

Kind regards,

Frank


#6

For anyone reading this thread, there is a lot more discussion of it over here:


#7

Hi @TIG, where can i download the resize_material function source code? i search the whole internet and found nothing. :disappointed_relieved:


#8

It’s there if you look !

require('sketchup.rb')
require('dynamiccomponents.rb')

if defined?($dc_observers)
  # Open SketchUp's Dynamic Component Functions (V1) class.
  # only if DC extension is active...
  
  class DCFunctionsV1
 
    protected

    def resize_material(vars)
    
      ### Usage as DC function: "Material"
      ###	=resize_material(oriMaterial,oriX,oriY,LenX,LenY)
      ### the 1st 3 arguments passed are custom - 'material-name' of small nested 
      ### group's material, and then that material's x/y size AND 
      ### the main DC's x/y size, in cm - e.g 100,100.

      oriMat = vars[0].to_s
      oriX = vars[1].to_f 
      oriY = vars[2].to_f
      newX = vars[3].to_f 
      newY = vars[4].to_f 

      x = oriX * oriX / newX
      y = oriY * oriY / newY

      xin = x / 2.54 ### cm to inches
      yin = y / 2.54 ### cm to inches

      tmp = ENV["TEMP"] ### it's a PC == 'TEMP' or 'TMP'
      tmp = ENV["TMPDIR"] unless tmp ### it's a Mac
      temp= tmp.tr("\\", "/")

      model = Sketchup.active_model
      materials = model.materials
        
      mat=materials[oriMat]
      
      return oriMat if not mat or not mat.texture
      
      mat_resized = materials.add(mat.name) ### increments mat to mat1, mat2 etc
        
      tw = Sketchup.create_texture_writer
      gr = model.entities.add_group()
      gr.material = mat
      tw.load(gr)
      tw.write_all(temp, false)
      texture = File.join(temp, File.basename(mat.texture.filename))
      mat_resized.texture = texture 
      mat_resized.texture.size = [xin, yin]
      mat_resized.alpha = mat.alpha
      ###
      mat_resized.color = mat.texture.average_color if mat.materialType == 2
      ### i.e. it's colorized
      
      ### tidy up
      gr.erase! if gr.valid?
      File.delete(texture) if File.exist?(texture)
      
      UI.start_timer(2, false){
        materials.current=nil
        materials.purge_unused
      }
      ### tidy up after 3 second...
      
      return mat_resized.name
    
    end#def
  
  end#class
  
end#if

Read the Usage rems…
i.e. you DC needs to include a small nested unseen group that is using the named “material”, and the function is:

=resize_material(oriMaterial,oriX,oriY,LenX,LenY)

passing references to that material’s name, that material’s size and the DC’s size…

The DC function returns the resized material’s name…


#9

I truly appreciate your repley.
Best wishes