4
$\begingroup$

I've got a mesh representing my living room. I built the mesh using Meshroom. I ended up with a few things around the bit of my living room I'm interested in.

I want to scale the entire mesh to the real world dimensions, but I do not know the exact dimensions of the bounding box of the mesh. I only know the distance between two points in the mesh. Is there a way to say "I know a distance between these two points in the mesh, scale the rest of the mesh accordingly to have real world measurements"?

Here's how the mesh looks (it's only one mesh) and the measurement I know:

Enter image description here

Because the mesh was built using Meshroom, you can see the points cloud, and I don't have one edge that I can easily select, so I shall be able to define the length between two points, at the start and end of my red line above. Here's the mesh in edit mode to get an idea:

Enter image description here

$\endgroup$
3
  • $\begingroup$ Could you please explain what exactly you have there? In Blender, meshes are usually the vertices that build the edges and faces of a mesh object. A living room can have several objects and each object has its own mesh. So, do you have "a mesh" = 1 mesh object, or do you just call the sum of all objects together "a mesh" = a scene filled with several mesh objects? $\endgroup$ Jan 31, 2023 at 14:57
  • $\begingroup$ But anyway, I will assume the scene is filled with many objects. Let's say you have one single edge and you know it's 1 m in real life. Click to select the object containing that edge. Then press Tab to go into Edit Mode, select that 1 m edge. Activate Edge Length in the Overlays. If the length in the model is for example 0.25 m, then Tab again to go back to Object Mode, select all objects with A, then scale them by factor 4 (because 1 m / 0.25 m = 4) by pressing S, 4, Return. Of course this works with other factors as well, also with decimals. $\endgroup$ Jan 31, 2023 at 15:02
  • $\begingroup$ I just added some more details, hopefully it helps! $\endgroup$
    – maxime1992
    Jan 31, 2023 at 18:48

5 Answers 5

6
$\begingroup$

Since we now know that you are talking about a single mesh with a lot of vertices, you can do it a bit different as I explained in the comments on my other answer.

Let's say you have a dense mesh and you know the distance between two of those points (I'll take a generated landscape because I have no other dense mesh right now). First make sure the Scale of the mesh object is 1 on all axes in Object Mode:

scale at 1

Then Tab into Edit Mode, select the two points of which you know the distance:

select known distance

Hit F to create a new edge between them. Activate Edge Length in the Overlays for the viewport. In my case it shows the length of the edge as 1.2 m:

display edge length

This value might not be precise enough for scaling the object to its real world measurements, depending on how precise you want it. You can go to Scene Properties > Units and change the unit for Length to Millimeters or Micrometers instead of Meters. Now the length shows 1196469 μm = 1.196469 m which is a bit more precise.

change units for precision

If you have noted the value somewhere, you don't need the edge any longer and can delete it with X > Delete > Edges (not Vertices!). But you can do it after the scaling as well. If you keep it now, you can use it for checking the distance afterwards.

Tab back into Object Mode. With the known real distance between the vertices and the measured length of the edge, you can calculate the scaling factor by dividing them:

$$\frac{\text{real distance}}{\text{measured length}}=\frac{\text{5 m}}{\text{1.196469 m}}\approx4.178963$$

Now in Object Mode simply enter the value into the Scale for the object, you can do it separately for X, Y and Z or drag over the three fields to enter the same value in all fields at once, then hit Return to confirm the new scale:

set new scale

The last thing to do is applying the scale with Ctrl+A > Apply > Scale or else the measurement in Edit Mode would still show 1.2 m:

apply scale

But with the scale applied it now shows 5000001 μm which is almost perfect. By now you can definitely delete the edge and set the length unit back to Meters, Millimeters or whatever you want.

new edge length

Bonus tip:

In a very dense mesh it can be very hard to see the newly created edge and the displayed length:

dense crowded mesh

To make it easier to see them, you can - with the vertices needed for measurement selected (even before creating the new edge) - press Shift+H to hide all unselected vertices and you can now see the edge and the length better (or you create the edge now with F if you haven't done before):

hide all unselected vertices

To get the hidden vertices back, you can press Alt+H. If you disable the checkbox Select in the Reveal Hidden option at the bottom left, you avoid having all other vertices now selected so that only the new edge will be selected still (helps with deleting it afterwards). Although there is no need to reveal the vertices before scaling and deleting the new edge, since hiding them does not affect the scale operation in Object Mode.

reveal hidden vertcies

$\endgroup$
1
  • $\begingroup$ Thanks for the very detailed explanation, that's brilliant $\endgroup$
    – maxime1992
    Feb 1, 2023 at 9:32
4
$\begingroup$

Here's a Geometry Nodes solution (for a single mesh):

Enter into Edit Mode, select two vertices you know the distance between, and hit Ctrl + G to create a vertex group out of them. By default, the name of the vertex group will be "Group". In the Geometry Nodes modifier we use two Sample Index nodes, one set to index $0$ and the other $1$ to get the positions of those two vertices. A Vector Math gets the Distance between them, then the whole geometry gets scaled (Transform Geometry) by the ratio of the real measurement to the current. Finally, a Remove Named Attribute makes sure the vertex group we only created for this purpose gets deleted when you apply the modifier:

enter image description here

$\endgroup$
3
$\begingroup$

You could duplicate one of the vertices you know distance between and force it to be the correct distance, then scale everything from the first vertex snapping the second one to the new one you just made:

enter image description here

You would need to set up the snapping to work for that. I use 3d Cursor snapped to the first vertex as pivot point for the transformation. It needs to be set appropriately:

enter image description here

I snapped it to the vertex with the snap menu - Shift + S.

Since my points are on the same X axis, I could simply move my duplicate constraining the transform operation in X axis, however if it's not the case, you might need to make a custom transform orientation from the selected vertices:

enter image description here

If you make a custom transform orientation from an edge(that happens if unconnected 2 vertices are selected as well), Y is the axis along the edge(or the imaginary edge that would connect the 2 vertices), so you hit Y to constrain transform operations in that direction. This is only for moving the vert, you probably want the object scaled in all direction, so no need to do anything for scaling.

Snapping can be turned on temporarily holding ctrl key down while in transform operation, but you could just turn it on fully as well:

enter image description here

In my example the transform operation uses 3d Cursor as its pivot point, but the snap target is set to active element that is the vertex I made sure to select last. Snapping options are set here:

enter image description here

$\endgroup$
5
  • $\begingroup$ This is done using 2 vertices that seem to be on the bounding box, could you do the same from let say the 2 eyes. If you know the distance between the 2 eyes is 1m. Would the same apply? And how did you get the measurement initially? When it starts it already displays 70 $\endgroup$
    – maxime1992
    Jan 31, 2023 at 18:36
  • $\begingroup$ I've edit my original post to add more info in case it's of any help! $\endgroup$
    – maxime1992
    Jan 31, 2023 at 18:49
  • 1
    $\begingroup$ It doesn't matter where the vertices are. $\endgroup$ Jan 31, 2023 at 22:56
  • $\begingroup$ @maxime1992 He didn't get any measurements there. That is simply a mesh in the shape of "70 cm" as you can see from the vertices in the third screenshot. He wanted to illustrate that this edge is supposed to have a length of 70 cm in reality. Or when you import a CAD drawing it could be that you have the written measurements as mesh in there, too. $\endgroup$ Feb 1, 2023 at 10:21
  • $\begingroup$ facepalm yup makes sense, cheers! Newbie with blender, I think you figured it out! But nevertheless you guys helped me achieve what I needed, thanks a lot for your patience! $\endgroup$
    – maxime1992
    Feb 1, 2023 at 10:30
3
$\begingroup$

Let's say I have a room like this, consisting of several objects. But I know it has not the original size.

room overview

But I know for example how high the edge of the wall is from floor to ceiling. It doesn't matter which edge size you know, this is just an example that can be used for other parts of the room as well. So, I select the wall object, press Tab to go into Edit Mode, select the wall edge and enable the Edge Length in the Overlays. This shows a height of 1.24 m:

room height edge length

But I don't think this value is precise enough for my taste, as a little trick I go to Scene Properties > Units and set the Length from Meters to Micrometers. Now the edge shows a length of 1237205 μm:

length in micrometers

Now I know that the height of the room is 2.5 m so with 1237205 μm or 1.237205 m I get a scaling factor of around

$$\frac{2.5 m}{1.237205 m}=2.0206837...$$

So I hit Tab to go back into Object Mode, select all objects with A. Now it is important that the Pivot Point for the transformation is not set to Individual Origins. Any other will be okay and depends on if you want the room to stay in place with one of its corners for example, then you could set the 3D cursor there and use it as pivot point. In this example I just use the Median Point.

pivot point

Now I'm scaling all objects at once by the calculated factor by pressing the scale shortcut followed by the numbers: S 2.0206837 Return.

scaling by factor

To make the new size the original size of the objects, apply the scale while all objects are still selected with Ctrl+A > Apply > Scale.

apply scale

Switching the wall object back into Edit Mode the selected edge now shows a length of 2500 mm (I've switched to Millimeters because I don't need the Micrometers precision anymore).

new edge length

$\endgroup$
11
  • $\begingroup$ Thanks! This looks like the simpler answer so far, I'll go with that! $\endgroup$
    – maxime1992
    Jan 31, 2023 at 18:33
  • $\begingroup$ Actually sorry, I mark as answered too quickly. In my case the mesh ic composed of plenty of points, I don't have a single edge I can select. But I'll remember that, still super interesting thanks! $\endgroup$
    – maxime1992
    Jan 31, 2023 at 18:41
  • $\begingroup$ @maxime1992 Oh I see. You could also create a temporary edge. Select the first and last vertex of the distance you know and hit F. This connects them with an edge and you have the length. Then hit X > Delete > Edges to get rid of it afterwards. $\endgroup$ Jan 31, 2023 at 18:49
  • $\begingroup$ I just edited my post with more info, I think it'll make more sense why I said that in my case your solution wouldn't work :) $\endgroup$
    – maxime1992
    Jan 31, 2023 at 18:49
  • $\begingroup$ @maxime1992 Maybe the comment I gave while you edited the answer helps 😁 $\endgroup$ Jan 31, 2023 at 18:52
2
$\begingroup$

I do this quite a lot for reference images and imported vector drawings, so I wrote a little add-on to make my life easier. Since I already made it, I thought I could share it here.

It's in Transform sub menu in Object and Mesh(in Edit mode) menus in the 3d viewport header or you can just search for it with F3. You have to have 2 vertices selected(doesn't matter if you leave edit mode). It scales the object all selected objects without applying scale.

enter image description here

bl_info = {
    "name": "Scale By Known Distance",
    "author": "Martynas Žiemys",
    "version": (1, 0),
    "blender": (3, 5, 1),
    "location": "View3D search -> Scale By Known Distance, View3D -> Object -> Transform / Mesh -> Mransform",
    "description": "Scales mesh by known distance between 2 vertices",
    "warning": "",
    "doc_url": "",
    "category": "Object",
}

import bpy, math
from bpy.props import FloatProperty

class OBJECT_OT_scale_by_known_distance(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.scale_by_known_distance"
    bl_label = "Scale By Known Distance "
    bl_options = {'REGISTER', 'UNDO'}
    l : FloatProperty(name = "Distance between vertices: ", default = 0)
    current_distance = 0
    
    @classmethod
    def poll(cls, context):
        return context.active_object.type == 'MESH'

    def execute(self, context):
        o = bpy.context.object
#        sel = [v for v in o.data.vertices if v.select]
#        o.scale = o.scale * self.l / self.current_distance 
#        o.update_from_editmode()

# Probably more usefull to scale all selected objects
        scale = self.l / self.current_distance 
        bpy.ops.object.mode_set(mode = 'OBJECT')
        saved_pivot = bpy.context.scene.tool_settings.transform_pivot_point
        bpy.context.scene.tool_settings.transform_pivot_point = 'ACTIVE_ELEMENT'
        bpy.ops.transform.resize(value = (scale,scale,scale))
        bpy.context.scene.tool_settings.transform_pivot_point = saved_pivot
        self.report({"INFO"}, str(scale))
        self.report({"INFO"},"Scaled from " + str(self.current_distance) + " to " + str(self.current_distance*scale) + " ( " + str(scale) + " ) ")
        return {'FINISHED'}
    
    def invoke(self, context, event):
        o = bpy.context.object
        o.update_from_editmode()
        sel = [v for v in o.data.vertices if v.select]
        if len(sel) == 2:
            self.current_distance = self.l = math.dist(o.matrix_world @ sel[0].co, o.matrix_world @ sel[1].co)
            return context.window_manager.invoke_props_dialog(self, width = 450)
        else:
            self.report({"WARNING"}, "Select 2 vertices!")
            return {'CANCELLED'}
        
def add_scale_by_known_distance_button(self, context):
    self.layout.operator(OBJECT_OT_scale_by_known_distance.bl_idname, icon='PLUGIN')
        

def register():
    bpy.utils.register_class(OBJECT_OT_scale_by_known_distance)
    bpy.types.VIEW3D_MT_transform_object.append(add_scale_by_known_distance_button)
    bpy.types.VIEW3D_MT_transform.append(add_scale_by_known_distance_button)

def unregister():
    bpy.utils.unregister_class(OBJECT_OT_scale_by_known_distance)
    bpy.types.VIEW3D_MT_transform_object.remove(add_scale_by_known_distance_button)
    bpy.types.VIEW3D_MT_transform.remove(add_scale_by_known_distance_button)

if __name__ == "__main__":
    register()

So that's to be pasted into a text document(just use Blender's Editor to be sure about correct encoding) and saved to a file with .py extension. It can then be installed as any add-on from User Preferences(F4 -> P -> Add-ons tab)

$\endgroup$
1
  • $\begingroup$ This looks awesome! Thanks for sharing! $\endgroup$
    – maxime1992
    Mar 21, 2023 at 16:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .