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…
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.
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.
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...
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]
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
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?
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…
Hello TIG, I’ve already examined all your Descaler code, but I’m quite a beginner in the subject, I tried to undo the locks on DC, as I understand it, you put such restrictions because of the error in the textures, correct? but my DCs don’t use textures or Sub-Components, I would love to add a “Scale Definitition” after executing my code.
I was trying to follow up TIG work around, but some how I managed to do another work around without knowing it. Inside the DC I put a tiny face “Swatch” like TIG susgested, But I made it a component (a component inside a component) and force it’s Size attributes to a fixed size, so whe the parent atributes scales the “son” DC will resizes to it original sizes, and magical it did the trick, I dont know how but it works. Here is the file for you to see.
The child DC forces the parent to become unique (if not already) and “scale definition”. A process you can preform manually via the right click context menu.
The use of a child to force the parent is also required in making a swap and retaining the size (lenx,y,z) in conjunction with the CURRENT formula in the parent
There are quite a few tricks, I am glad you discovered this one for yourself. SketchUp has many of these “Easter eggs”