1

Question updates at the bottom....

I'm writing a custom SketchUp export plugin in Ruby. I then recreate the geometry in Three.js using the exported data.

I'm having troubles with some component/group transformations, and tracked it down to mirroring, or geometry that has "flip along" applied for some axis. Simply put, the flip along is not respected. I can not find any SU Ruby method to find out whether any given entity has this flip along applied.

I can get a transformation matrix, and convert it (see this question of mine how), however it does not work for these flipped objects. Here's an example result; the rest of the model is fine, but the boat is obviously created using flipped boat halves, and in this picture they appear all over the place:

messy boat

How can I properly take these flipped geometries into account? Do they have some kind of separate matrix, or entity flag in SU Ruby?

Note 1) I have observed similar buggy behaviour in the built-in SketchUp Collada exporter (when loading them with Three.js ColladaLoader).

Note 2) Although I believe this to be a SketchUp Ruby API issue, I tagged this with Three.js just in case there is something obvious I'm missing in regards to mirroring and Matrixes..

Note 3) If the geometries are flipped / mirrored using the scale tool instead of flip along tool (effectively the same result), they work correctly.

UPDATE:

Still struggling to apply this information, but getting closer based on this information: http://sketchucation.com/forums/viewtopic.php?f=6&t=3083

UPDATE #2:

Thanks to Thomthom, I was able to detect and apply correct flipping for objects that are not rotated. For a plain unrotated/unscaled/unflipped component the matrix is:

 1.0, 0.0, 0.0
 0.0, 1.0, 0.0
 0.0, 0.0, 1.0

For a flipped (mirrored) component the matrix can be:

-1.0, 0.0, 0.0
 0.0, 1.0, 0.0
 0.0, 0.0, 1.0

So I can detect that flip easily and all is fine.

But if I arbitrarily rotate the same component (unflipped) an a couple of axes, the matrix looks like this:

 -0.33, -0.58,  0,74
  0.87, -0.50,  0,00
  0.37,  0.64,  0,67

This works correctly in my exporter/importer, I can reapply this matrix on Three.js side.

But when that already rotated component is also mirrored, the matrix looks like this:

  0.33,  0.58, -0.74
  0.87, -0.50,  0.00
  0.37,  0.64,  0.67

I can't get this matrix work correctly in Three.js, and the component is never mirrored, resulting in the behaviour that can be seen in the picture.

So, I'm not sure what to do. I was able to get correct results by detecting the simpler case (only flipped, not rotated or scaled), then setting for example object.scale.x = object.scale.x * -1; in Three.js for such components. But no solution for items that are both flipped and otherwise rotated or scaled :(

Community
  • 1
  • 1
yaku
  • 3,061
  • 2
  • 19
  • 38
  • One thing that puzzles me, can't the transformation matrix be fed to Three.js? – thomthom Aug 08 '13 at 02:51
  • Yeah, I am currently feeding the matrix to Three.js and it mostly works except for these flipped components. The model in the picture is very complex, all the palmtree leaves and stuff, also furniture inside is made of deep hierarchies of components and groups with their own transformations. Given that the rendering is not total mess, I must be doing something right.. puzzling indeed that it doesn't work with flipped stuff, as the data required for that apparently does exist in the matrix. – yaku Aug 08 '13 at 07:39
  • Considering that the built-in Three.js ColladaLoader shows the same problems with SketchUp exported DAE, makes me suspect the Matrix4 implementation in Three.js simply gets confused when there is negative scale involved. Or something like that. This is really out of my field of expertise :) – yaku Aug 08 '13 at 08:04
  • Three.js does not support negative scale. http://stackoverflow.com/questions/16469270/transforming-vertex-normals-in-three-js/16469913#16469913 – WestLangley Aug 08 '13 at 14:46
  • Ah, well that explains things. – thomthom Aug 08 '13 at 15:00
  • @WestLangley Currently I'm able _test_ geometry mirroring in Three.js in any axis by setting a negative scale. At least the shapes turn out correctly mirrored, although materials appear as black. But silhouette looks proper. I was planning to tackle the materials/uvs/normals/windingorder issues separately by creating a "proper" Three.js geometry flipping function after I get at least a proper silhouettes with the simpler placeholder method. I have your linked question and some other threads bookmarked for that. Does the "negative scale not supported" also apply to pure matrix calculations? – yaku Aug 08 '13 at 15:29
  • ...by pure matrix calculations I mean, currently I'm only concerned with getting the vertices at the right place. When that works I can worry about getting it to work nicely with the Three.js materials/lights/whatever issues it can bring. – yaku Aug 08 '13 at 15:36
  • Yes, vertex locations themselves, should be correct, regardless of the form of the matrix transform. You are going to have to be careful, however. – WestLangley Aug 08 '13 at 20:03

1 Answers1

3

Use my Transformation Inspector to visualize the SketchUp matrix in a 4x4 grid: http://extensions.sketchup.com/en/content/transformation-inspector

Using that I can tell which matrix entry changed as I flipped along any axis: * **Flip along X:** Index #1 * **Flip along Y:** Index #5 * **Flip along Z:** Index #10

Martin Rinehart has written a breakdown of the transformation in SketchUp: http://www.martinrinehart.com/models/tutorial/tutorial_t.html


Find flipped axis with orientation:

module TransformationHelper

  def flipped_x?
    dot_x, dot_y, dot_z = axes_dot_products()
    dot_x < 0 && flipped?(dot_x, dot_y, dot_z)
  end

  def flipped_y?
    dot_x, dot_y, dot_z = axes_dot_products()
    dot_y < 0 && flipped?(dot_x, dot_y, dot_z)
  end

  def flipped_z?
    dot_x, dot_y, dot_z = axes_dot_products()
    dot_z < 0 && flipped?(dot_x, dot_y, dot_z)
  end

  private

  def axes_dot_products
    [
      xaxis.dot(X_AXIS),
      yaxis.dot(Y_AXIS),
      zaxis.dot(Z_AXIS)
    ]
  end

  def flipped?(dot_x, dot_y, dot_z)
    dot_x * dot_y * dot_z < 0
  end

end


module Example

  def self.inspect_flipped
    tr = Sketchup.active_model.selection[0].transformation
    tr.extend(TransformationHelper)

    puts "X Flipped: #{tr.flipped_x?.inspect}"
    puts "Y Flipped: #{tr.flipped_y?.inspect}"
    puts "Z Flipped: #{tr.flipped_z?.inspect}"
  end

end
thomthom
  • 2,854
  • 1
  • 23
  • 53
  • Thanks a lot! This helps, although it's still not completely working. Using your transformation inspector I see, that applying a -1 transform on index 0, 5, or 10 will flip the geometry on the corresponding axis. So, for basic geometry, I can just check whether transform matrix 0, 5, or 10 is negative to see that it is flipped on that axis. If the component is first flipped, then arbitrarily rotated, that check does not work anymore. Or it can believe a component is flipped when it is only rotated. – yaku Aug 02 '13 at 17:39
  • Ah,yes, you're right. Found this article that describes conceptually what one would need to do: http://www.robertblum.com/articles/2005/02/14/decomposing-matrices – thomthom Aug 07 '13 at 15:55
  • Ok, try the new example. – thomthom Aug 08 '13 at 05:21
  • Thanks again, you rock! The new example does indeed seem to work as advertised :) It didn't immediately solve the more complex cases, but they are probably because separate minor issues - there's the matrix and flip axis conversion to three.js, nested transforms, and issues likely having to do with getting the matrix transform and this flipping stuff (negative scale) work together in Three.js. So I'll need a bit of time to try and adapt this into the code, test with various models and confirm it's the solution.. – yaku Aug 08 '13 at 07:59
  • I just tested against non-orthogonal transformations and it still worked, even with rotation in all three axis. – thomthom Aug 08 '13 at 14:58
  • This does seem to work pretty reliably and I think it's safe to say this answers the original question. I'll try to keep the thread updated with more complete information when I manage put this and all of the semi-related issues together into a fully working contraption :) – yaku Aug 08 '13 at 21:43
  • I checked the code with some of guys at the office (Trimble SketchUp) that understands the matrix better than me and they said the math was sound. – thomthom Aug 08 '13 at 23:56
  • I'm really struggleing with this but in the SDK instead. In your code, what is X_AXIS? World x axis? (1, 0,0) – Stefan Agartsson Oct 18 '17 at 09:23
  • 1
    @StefanAgartsson - yes, `X_AXIS` is a SketchUp defined constant for (1, 0, 0) – thomthom Oct 19 '17 at 09:15