Controlling ratio of Material/Texture with different face's area


Hi guys,

I’m with this issue:

All three drawers use the same material to his faces. But the ratio become different when the area is different.
Is there a way to mantain the same aspect ratio to all drawers?

My code to add/set texture:

File.write "wood.jpg", open("#{IMAGE_URL}/#{texture_id.to_s}/600/3/1").read, {mode:'wb'}

materials = Sketchup.active_model.materials
material = materials.add(texture_id.to_s)
material.texture = "#{TEXTURES_PATH + texture_id.to_s}.jpg"
material.texture.size = [10, 15]

And applying, just:

face.material= texture_id.to_s


face.material= texture_id.to_s

this seems rather odd to me. you’re not applying a material here but a string or…?
I would rather expect something like:

my_material = materials.add(texture_id.to_s)
face.material= my_material


Actually I’m applying the material by the name. The string “texture_id” it’s the name of my material on model.materials.


In your code, you only give material a texture.size, so it is what you need to apply

face.material = material


@john_drivenupthewall It’s applying in the line below:

@maxB even if I put:

face.material = material

the result it’s the same.


If I do for each face:

face.position_material(material, [[0,0,0],[0,0,0]], true)

then all the texture become equals, but it only works in Ruby Console, in the script code doesn’t.


The API docs say:

The first point in each pair is a 3D point in the model. It should be a point on the Face.

It isn’t clear what “should” means, especially since the example in the docs uses a point off the Face, but could that be the difference between your console test and script?


Maybe could be. Then I’ve tryied that:

material_selected = {|mat| == api_id.to_s}.first
material_selected.texture = "#{TEXTURES_PATH +}.jpg"
material_selected.texture.size = [10, 15]
face.material= material_selected
face.position_material(material_selected, [face.bounds.corner(0),face.bounds.corner(1)], true)

but without success.


how are you finding your faces?
the loop code is missing…


This way (api_id.to_s it’s the name of the material):

[EDIT] ooh sorry, I read face as material.


faces.each { |face|
face.material= material_selected
face.position_material(material_selected, [face.bounds.corner(0),face.bounds.corner(1)], true)


Oh, sorry,

all my code is inside a loop with the faces I need to paint.



material_selected = {|mat| == api_id.to_s}.first
material_selected.texture = "#{TEXTURES_PATH +}.jpg"
material_selected.texture.size = [10, 15]
faces.each do |face|    
  if not material_selected.nil?
    face.material= material_selected
    face.position_material(material_selected, [face.bounds.corner(0),face.bounds.corner(1)], true)

The faces I get the biggest areas.


here’s an example from one of my scripts…
it’s not adding texture but maybe it can give some help…
floors is an existing array of groups…
the main idea is to keep as much as possible outside the loop…

faces = {}
tally = 0{|e| tally += 1; faces[e[0].name.concat(tally)] = e[0].definition.entities.grep( Sketchup::Face)}
flr_tile = model.materials.add('flr_white_tile')
flr_tile.color =, 255, 255, 255)
flr_tile.alpha = 1.0
flr_wood = model.materials.add('flr_shiny_wood')
flr_wood.color =, 70, 15, 255)
flr_wood.alpha = 1.0
flr_slab = model.materials.add('flr_matte_slab')
flr_slab.color =, 125, 125, 0)
flr_slab.alpha = 1.0
count = 0
floor_faces = 0{|v| floor_faces += v.length}
model.start_operation("Paint floors")
                      Sketchup::set_status_text(("Painting #{count} faces of #{floor_faces} floor faces" ),SB_PROMPT)
                      next unless f.valid?
                      if k.include? 'Wood'
                        f.material = flr_wood
                      elsif k.include? 'Ceramic'
                        f.material = flr_tile
                        f.material = flr_slab
                      f.back_material = f.material

I do have some that add and position textures, but I need to dig them out…



Thanks for example john, I’m doing that, but somehow the texture become different…


in another part of my script, for the doors, i just added a texture [without adding .size] and it painted all 1204 faces correctly…

but my original image is the correct size for anything at 1:1…

is your model scaled?


If the faces have the same size, everthing works fine, I added the size just for a test.

Sorry, what do you mean with model?


The second element of the array argument to position_material should be the uv location in the texture to map to the Point3d given by the first element. I really doubt face.bounds.corner[1] is generally a valid uv location! Try something like [0,0,0].


some cabinet making plugins make one full height door component and the use scaled copies for all other size…
when they apply texture, it also gets scaled and can lead to confusion…

I also checked some of my other scripts and I seem to use [0,0,0] for all face material positioning…



I’m looking the whole script and seems to be something in onElementModified observer, there’s a lot of code executing before and after applying material. I’ll look for it and return with a position later.

Thanks a lot for help.