• Login
sketchucation logo sketchucation
  • Login
⚠️ Libfredo 15.4b | Minor release with bugfixes and improvements Update

Issues with a simple material copy raycast script

Scheduled Pinned Locked Moved Developers' Forum
25 Posts 2 Posters 7.0k Views 2 Watching
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    chanz
    last edited by 9 Sept 2018, 19:57

    @tig said:

    In my earlier version, if I make the to textured and project it onto a lower surface the top one's UV mapping is repeated on the lower surface.
    So I know it works.
    You just need to swap top/bottom properly to apply to you own chosen set up...

    If you use a blank face's UV mapping you won't get what's on the UV-mapped face...

    Try it with just a few facets first...

    Maybe I'm having trouble understanding. I'll use the script you posted and the test model I posted. What was your exact process to get the UVs on the top model looking like the original on the bottom? Maybe our process is just different. I assumed you used the test model I uploaded?

    1 Reply Last reply Reply Quote 0
    • T Offline
      TIG Moderator
      last edited by 9 Sept 2018, 20:18

      I can see some issues, BUT you need to clarify what face's texture you are copying with UVs and onto which face you apply them...

      TIG

      1 Reply Last reply Reply Quote 0
      • C Offline
        chanz
        last edited by 9 Sept 2018, 20:30

        @tig said:

        I can see some issues, BUT you need to clarify what face's texture you are copying with UVs and onto which face you apply them...

        Maybe I'm just explaining it wrong, but I don't know how to be more clear about what I'm after. I have uploaded a few pictures about what I'm after as well as a model which allows me to test.

        In the model I have the original on the bottom and the recreated mesh on the top. I want the textures and UVs of the faces on the bottom to be copied to the untextured model above.

        Sorry. Maybe I'm just misunderstanding what you're asking.

        Thanks for being patient.

        1 Reply Last reply Reply Quote 0
        • T Offline
          TIG Moderator
          last edited by 10 Sept 2018, 12:09

          I think this code does what you want.

          I have used your original conventions...
          The upper faces are the un-textured ones and the lower faces are textured.
          Each of the upper faces centroids now casts a ray downwards, and if it hits a lower face then the material from the lower face is applied onto the upper face, using the lower face's UV mapping.
          We can't be 100% sure that the ray will always hit a face below, because the upper and lower faces are different shapes etc, so if the ray hits a lower edge rather than a lower face, then there's no face to get a material from - so in that case a lower face belonging to that lower edge is found and used in lieu - that way we never have a 'blank' face in the upper set.
          Because the faces differ in some places the UV mapping can look a little odd on occasion...

          ### CopyBelowMaterials.rb
          ### by Chanz
          require 'sketchup.rb'
          ###
          module DAN
            ###
            def self.copymaterials()
              model=Sketchup.active_model
              ents=model.active_entities
              #ss=model.selection ### use selected UNtextured [upper] faces to speed it up
              faces = ents.grep(Sketchup;;Face)
              #faces = ss.grep(Sketchup;;Face) ### use selected UNtextured faces to speed it up
              ###
              return nil unless faces[0]
              ###
              begin
                model.start_operation("DAN.copymaterials", true)
              rescue
                model.start_operation("DAN.copymaterials")
              end
              ###
              faces.each {|face|
                rayt = model.raytest(c=self.find_centroid(face), Z_AXIS.reverse)
          			### UPPER >>> LOWER
                if rayt
                  f = rayt[1].grep(Sketchup;;Face)[0]
          				unless f
          				  f = nil
          				  e = rayt[1].grep(Sketchup;;Edge)
          					f = e[0].faces[0] if e
          				end
          				self.process_face(face, f) if f ### UPPER >>> LOWER
                end
              }
              ###
              model.commit_operation
              ###
            end
          
            # Finds an adjusted point, so we won't raycast down to an edge ;) HOPEFULLY
            ### OK if triangulated...
            ### BUT IF the face is L shaped the centroid might not fall on it !!!
            def self.find_centroid(face)
              vertices=face.vertices
              vertices[vertices.length]=vertices[0]
              centroid=Geom;;Point3d.new()
              a_sum=0.0
              y_sum=0.0
              x_sum=0.0
              for i in (0...vertices.length-1)
                temp=(vertices[i].position.x*vertices[i+1].position.y)-(vertices[i+1].position.x*vertices[i].position.y)
                a_sum+=temp
                x_sum+=(vertices[i+1].position.x+vertices[i].position.x)*temp
                y_sum+=(vertices[i+1].position.y+vertices[i].position.y)*temp
              end###for
              centroid.x=x_sum/(3*a_sum)
              centroid.y=y_sum/(3*a_sum)
              centroid.z=face.bounds.min.z
              return centroid
            end
           
            # NOTE; face_upper is in the model.ents||selection, face_lower is the TEXTURED face the raytest hit
            def self.process_face(face_upper, face_lower)
              ###
              texture_writer=Sketchup.create_texture_writer
              ###
              if face_lower.material && ! face_lower.material.texture
                ### paint the plain material if it exists but it has no texture
                face_upper.material=face_lower.material
              elsif face_lower.material ### A material and it has a texture...
                # Sample the UVs from LOWER face
                samples = []
                samples << face_lower.vertices[0].position             ### 0,0 | Origin
                samples << samples[0].offset(face_lower.normal.axes.x) ### 1,0 | Offset Origin in X
                samples << samples[0].offset(face_lower.normal.axes.y) ### 0,1 | Offset Origin in Y
                samples << samples[1].offset(face_lower.normal.axes.y) ### 1,1 | Offset X in Y
                xyz = [];uv = [] ### Arrays containing 3D and UV points.
                uvh = face_lower.get_UVHelper(true, true, texture_writer)
                samples.each { |position|
                  xyz << position ### XYZ 3D coordinates
                  uvq = uvh.get_front_UVQ(position) ### UV 2D coordinates
                  uv << self.flattenUVQ(uvq)
                }
                pts = [] ### Position texture.
                (0..3).each { |i|
                  pts << xyz[i]
                  pts << uv[i]
                }
                # Set the position for textured material from face_upper onto face_lower front
                face_upper.position_material(face_lower.material, pts, true)
              end
              ###
            end
           
            ### Get UV coordinates from UVQ matrix.
            def self.flattenUVQ(uvq)
              return Geom;;Point3d.new(uvq.x / uvq.z, uvq.y / uvq.z, 1.0)
            end
           
            ###
            ### menu
            unless file_loaded?(__FILE__)
              menu=UI.menu("Plugins").add_submenu("Copy Materials...")
              menu.add_item("To Nearest Below"){self.copymaterials()}
            end
            file_loaded(__FILE__)
          	
          end
          

          TIG

          1 Reply Last reply Reply Quote 0
          • C Offline
            chanz
            last edited by 10 Sept 2018, 19:38

            Thanks again for the reply TIG. Unfortunately, I see the same issues. To verify it wasn't the small differences in faces from DropVertices, I made a copy of the bottom textured model and moved it directly above. I removed the top materials and then ran the script. UV issue is still there. Have you actually downloaded the file and run this script with the top mesh faces selected? Have you seen the UV issues or did it look okay for you? Honestly, I guess I will just give up at this point.

            I have figured out another sort of workaround where I make a sandbox mesh above the original, run this script we wrote (which does perfectly with the texture and UVs when the raycast is from a flat surface), then use UVToolkit to save the UVs, then drop the vertices and then restore the UVs. It works. A few extra steps but this script has been enough of a headache.

            Regardless, thanks for your help.

            1 Reply Last reply Reply Quote 0
            • 1
            • 2
            • 2 / 2
            2 / 2
            • First post
              25/25
              Last post
            Buy SketchPlus
            Buy SUbD
            Buy WrapR
            Buy eBook
            Buy Modelur
            Buy Vertex Tools
            Buy SketchCuisine
            Buy FormFonts

            Advertisement