Projected Texture (and Google Earth)
-
Hi all,
I'm trying to Ruby-ize the excellent tutorial found here:
http://www.go-2-school.com/media/view/1This tutorial shows how to manually replace the B&W terrain images that are pulled from google earth with color ones.
I was hoping to eliminate the manual material "line-up" process with an automatic one.
I have it working with the 2D plane...but can't for the life of me figureout how to do it with the 3D terrain...and am hoping someone more talented than I can kick me in the right direction.
So, my steps for the 2D piece of the puzzle are in the attached code..to see it in action, fire up Google Earth, zoom into the required terrain. Switch to sketchup and "Get Current View" to import the google terrain. Go back into Google Earth and SAVE IMAGE (for the higher res color image). Edit the script to the image file you just saved and let it rip. You will see the 2D terrain is perfect. The 3d terrain needs resizing - but I can't figure out how to do it (and alter the aspect ratio!). HELP!
` # Grab a handle to the currently active model (aka the one the user is looking at in SketchUp.)
model = Sketchup.active_modeldef flattenUVQ(uvq)
uvq.x = uvq.x / uvq.z
uvq.y = uvq.y / uvq.z
uvq.z = 1.0
return uvq
endGrab other handles to commonly used collections inside the model.
entities = model.entities
layers = model.layers
materials = model.materials
component_definitions = model.definitions
selection = model.selectionNow that we have our handles, we can start pulling objects and making
method calls that are useful.
ge_entity = entities[0]
ge_snapshot = entities[0]
ge_terrain = entities[0]UI.messagebox("First thing in your model is a " + first_entity.typename)
number_objects = entities.length
puts "\nnumber entities:" + number_objects.to_s
puts "=================\n"for k in 1..number_objects
if entities[k-1].typename.to_s == "Group"
ge_entity = entities[k-1]
if ge_entity.name == "Google Earth Snapshot"
ge_snapshot = ge_entity
elsif ge_entity.name == "Google Earth Terrain"
ge_terrain = ge_entity
end
end
endbounds = ge_snapshot.local_bounds #get the bounds of the image
puts "processing google earth snapshot..."
puts "---bounds [height:" + bounds.height.to_s + "] width:" + bounds.width.to_s
puts "---sub-entities:" + ge_snapshot.entities.length.to_s + " found. looking for face."ge_snapshot.locked=false #unlock the entity
ge_terrain.locked = falsefor h in 1..ge_snapshot.entities.length
face_entity = ge_snapshot.entities[h-1]
if face_entity.typename.to_s == "Face" # we've found our face
break
end
endmat = face_entity.material # grab the material
texture = mat.texture #Assign the textureputs "---face found. processing face."
puts "------[material:" + mat.display_name + "]\n------[texture:" + texture.filename + "]"
puts " height: " + texture.height.to_s
puts " width: " + texture.width.to_s
puts " image_height: " + texture.image_height.to_s
puts " image_width: " + texture.image_width.to_stw = Sketchup.create_texture_writer
uv_helper = face_entity.get_UVHelper true, false, twsamples = [] #Create a set of samples
samples << face_entity.vertices[0].position # 0,0 | Origin
samples << samples[0].offset(face_entity.normal.axes.x) # 1,0 | Offset Origin in X
samples << samples[0].offset(face_entity.normal.axes.y) # 0,1 | Offset Origin in Y
samples << samples[1].offset(face_entity.normal.axes.y) # 1,1 | Offset X in YArrays containing 3D and UV points.
xyz = []
uv = []samples.each { |position|
# XYZ 3D coordinates
xyz << position
# UV 2D coordinates
uvq = uv_helper.get_front_UVQ(position)
uv << self.flattenUVQ(uvq)
}
print "\nxyz: " + xyz.to_s
print "\nuv : " + uv.to_s
print "\n"Position texture.
pts = []
(0..3).each { |i|
pts << xyz[i]
pts << uv[i]
}puts "------Setting size to " + bounds.width.to_s
mat.texture = "G:\Test Image 01.JPG" # Grab our hi-res image
mat.texture.size = bounds.width # Resize the thing
face_entity.position_material mat, pts, true # Apply the coordinatesputs "------Reapplying co-ordinates"
puts "=================\nend of run"`
-
Hi Suresh,
The whole process shown in the video is overcomplicated and useless.
What you can simply do is skip the whole resizing and positioning phase and follow these steps:
- go to the edit mode of the B&W image
- without any kind of fiddling around with the tape measure and image resizing steps, simply reload it with the colur version.
The size and positioning will be perfectly as that of the colour version (as by reloading the imayge, it will NOT affect its previous UV mapping at all) - now enter the flat terrain group, right click on the face, go to Texture > Projected (don't even touch the positioning tool - no need at all).
- Now sample this projected material, open the terrain and paint it with the projected material
You can also use this projected texture to paint the roofs of your models per Google's "preference" - at least where the GE imagery is good enough (and positioned correctly)
You may use these steps to write a plugin but IMO it is so simple and speedy procedure that you wouldn't really need it. Can be done within like half a minute.
-
Gaieus,
Thanks for the comments. As you'll see from the code, I'm not re-creating the useless steps in the video - however simply loading an image DOES NOT work as the aspect ratio gets reset. Therefore, positioning and sizingthe map IS required. Hence the code. As for the terrain bit (where I'm stuck), yes - it can be done manually-but since I want to repeat this exercise 50+ times (I'm cutting a range of terrain from GE).
So - how can one do your steps 3 and 4 programattically? I can't figure it out for the life of me!
s.
-
Reload a texture via Ruby?
Before you replace the old texture - read and store the width and height of it.
Then when you have loaded the new one - apply the width and height. -
thomthom,
ok - I'm sure I'm being very dense...but a couple of points/questions:
-
How does one set the width and height of the texture in code? One can read texture.height and texture.width but not set them..and one only gets to SET texture.size....but that assumes the aspect ratio is the same as before. In this example, it's not...so the question is how does one set the width and height independently --- isn't it in the apply material position function?
-
by way of explanation, google earth in injects the terrain with a 1" square texture size that is then stretched as needed EVEN though the image is say, 1600x1200. As soon as one reloads/loads an image, this aspect is changed to match the incming image and the "ASPECT LOCK" is lost. So when one reapplies the texture.size =1", what happens is width becomes 1" and height becomes 5/8" to maintain aspect ratio. Manually, it's easy - click OFF the aspect lock button in the texture window and enter the 1" value in the width...but how to do that in code?
Thanks,
s.
-
-
Ah, yes: welcome to the SU API Manual - Don't trust it!
Texture.size=
http://code.google.com/apis/sketchup/docs/ourdoc/texture.html#size=Arguments:
- Number size
- Array(width, height) <-
Example:
Texture.size=[20,40]
We got a looooong thread going with reports of missing and incorrect info in the manual: http://forums.sketchucation.com/viewtopic.php?f=180&t=17047
-
awesome! thanks so much -- you have no idea how many hours I spent - bloody manual!
Anyway - one more, last part of the puzzle.
Loading the image and then setting a new mat.texture.size = [1,1] works fine.
The only thing is that the image isn't really a square aspect ratio and its applied size isn't really 1" x 1". It's actually a 4800x3600 image and an applied size of 4913' 5 1/4" and 3137' 8 1/2"!!! While the above 1x1 at aspect of 1 works...do you have any tips for how I then adjust the image so that its physically "right" even though its already visually "right"!Thanks.
s.
-
Not sure if I understand. You say it's visually right - it looks correct in SU? Then what is physically right?
There's two things that affects how a material is applied to a face.
The default size if the info in
material.texture
But if the user has positioned the material on the face, or you have usedface.position_texture
, then that also affects it. -
"visually right" = it looks good in sketchup..the texture is applied as it should be.
"physically wrong" = the size of the terrain is 4090' x 3250'. the texture size is 1"x1". The texture size has the wrong size and aspect ratio...but somehow sketchup knows how to transform this. Maybe I shouldn't worry about it since it's "visually right" - but it would be great for the physics to match the visual.
Best way of seeing this, if you have google earth, is to fire it up. click the Getr Current View in Sketchup and see the texture properties of the material that represents the ground terrain. it will say 1"x1", even though it's really not!
I'm guessing the trick is to use face.position_material -- and someshow pass in xyz and uv pairs -- but containing what is beyond me.
s.
Thanks again. -
Since GE places the original texture there in 1" x 1" and you want to replace it with a different colour version, then it's best to just leave it like that. It works.
It's visually correct because it has been Positioned like that, which override the default Texture size. But if you afterwards meddle with the Texture size you will affect the positioned material.But if you where creating a material from scratch, then you'd just calculate the aspect ratio of the texture's pixel size and use that for
texture.size=
-
Guys, I really don1t know coding - but totally without any texture positioning, I could simply reload the image in this file in less than a minute.
Now how you translate it into ruby code - is totally out of my knowledge
-
Gaieus --
are you sure it reloaded with EXACTLY the same positioning. If so, it's a fluke.
IF you pull the terrain from Google Earth, take a color snapshot from google earth and load the color image into the texture...the texture size (tiling is wrong) as it shifts from a 1:1 to the aspect ration of the incoming image.It only takes a few seconds, but one MUST reset the texture size.
If you are doing this for 50 pieces of a large terrain loaded from GE, tile by tile, then ruby saves a LOT of effort.
s,
-
Well, I did indeed play around quite a lot to see what's happening when I am doing this. My approach was to reload the image and then go to top view and toggle undo/redo to see the difference between the B&W and the colour version.
To be honest, I didn1t see any difference so I basically trust the method - true that when I go quite close in my area, the imagery is not the best as well as in those rare cases when I use this technique (to paint some small scale, artificial terrain for GE), any subtle difference would be rather unnoticeable.
Advertisement