[null, {"document_url": "https://blog.michelanders.nl/2017/08/", "unformatted_src": "https://1.bp.blogspot.com/-NuAHgqtd6zY/WaG0A8E2wQI/AAAAAAAAQAc/7CCmcsry4EAJKHRzp_UR9HdEN9i1qnX7gCLcBGAs/s200/Screenshot_2017-08-26_19-40-32.png", "src": "https://1.bp.blogspot.com/-NuAHgqtd6zY/WaG0A8E2wQI/AAAAAAAAQAc/7CCmcsry4EAJKHRzp_UR9HdEN9i1qnX7gCLcBGAs/s200/Screenshot_2017-08-26_19-40-32.png", "formatted_filename": "Screenshot", "rendered_width": 200, "rendered_height": 144}, null, {"document_url": "https://blog.michelanders.nl/2017/08/", "unformatted_src": "https://1.bp.blogspot.com/-cTOAt8kiA0s/WaG0ISED2cI/AAAAAAAAQAk/_Ln3TNXYcp8mQkP4BmZPWdxHmTQcN0EeACLcBGAs/s400/normalandbump.png", "src": "https://1.bp.blogspot.com/-cTOAt8kiA0s/WaG0ISED2cI/AAAAAAAAQAk/_Ln3TNXYcp8mQkP4BmZPWdxHmTQcN0EeACLcBGAs/s400/normalandbump.png", "formatted_filename": "normalandbump", "rendered_width": 400, "rendered_height": 183}, null, null, {"document_url": "https://blog.michelanders.nl/2017/08/", "unformatted_src": "https://1.bp.blogspot.com/-BNmFZS98odE/WY34Lv6BuDI/AAAAAAAAPtI/_7Rv4VkoCFUp5DBnZ9ZITBJqhaug3YhzACLcBGAs/s320/regular%2Btiling.png", "src": "https://1.bp.blogspot.com/-BNmFZS98odE/WY34Lv6BuDI/AAAAAAAAPtI/_7Rv4VkoCFUp5DBnZ9ZITBJqhaug3YhzACLcBGAs/s320/regular%2Btiling.png", "formatted_filename": "regular Btiling", "rendered_width": 320, "rendered_height": 317}, null, {"document_url": "https://blog.michelanders.nl/2017/08/", "unformatted_src": "https://2.bp.blogspot.com/-hDMxY1kdVG8/WY34Qn4JKPI/AAAAAAAAPtM/cPdw_qU4MWYtpjNaBfocnA2fPOHHQeAZgCLcBGAs/s320/chaos%2Bmosaic.png", "src": "https://2.bp.blogspot.com/-hDMxY1kdVG8/WY34Qn4JKPI/AAAAAAAAPtM/cPdw_qU4MWYtpjNaBfocnA2fPOHHQeAZgCLcBGAs/s320/chaos%2Bmosaic.png", "formatted_filename": "chaos Bmosaic", "rendered_width": 320, "rendered_height": 317}, null, {"document_url": "https://blog.michelanders.nl/2017/08/", "unformatted_src": "https://1.bp.blogspot.com/-pPO_VUAiX7g/WY34Y7pP2qI/AAAAAAAAPtQ/I634JRg_6CI2nWt0P-TwuMzQ2nfLGgAbwCLcBGAs/s400/choasmap%2Bnoodle.png", "src": "https://1.bp.blogspot.com/-pPO_VUAiX7g/WY34Y7pP2qI/AAAAAAAAPtQ/I634JRg_6CI2nWt0P-TwuMzQ2nfLGgAbwCLcBGAs/s400/choasmap%2Bnoodle.png", "formatted_filename": "choasmap Bnoodle", "rendered_width": 400, "rendered_height": 125}, null, {"document_url": "https://blog.michelanders.nl/2017/08/", "unformatted_src": "https://1.bp.blogspot.com/-_PQZ7Up4ZyM/WY6c-85TFUI/AAAAAAAAPu4/I90ONx8inuosrvT0GuVNhwC1Apzz4SSMgCLcBGAs/s400/two%2Bchaos%2Bmosaix%2Bmix.png", "src": "https://1.bp.blogspot.com/-_PQZ7Up4ZyM/WY6c-85TFUI/AAAAAAAAPu4/I90ONx8inuosrvT0GuVNhwC1Apzz4SSMgCLcBGAs/s400/two%2Bchaos%2Bmosaix%2Bmix.png", "formatted_filename": "two Bchaos Bmosaix Bmix", "rendered_width": 400, "rendered_height": 146}, null, {"document_url": "https://blog.michelanders.nl/2017/08/", "unformatted_src": "https://3.bp.blogspot.com/-iUmR_HcqzTo/WY6dibqMg5I/AAAAAAAAPvA/gBKQT_DzueMpaiy3LCGG1IHdwgyWyF4ZgCLcBGAs/s400/mosaix%2Bone%2Bvs%2Btwo.png", "src": "https://3.bp.blogspot.com/-iUmR_HcqzTo/WY6dibqMg5I/AAAAAAAAPvA/gBKQT_DzueMpaiy3LCGG1IHdwgyWyF4ZgCLcBGAs/s400/mosaix%2Bone%2Bvs%2Btwo.png", "formatted_filename": "mosaix Bone Bvs Btwo", "rendered_width": 400, "rendered_height": 192}, null, {"document_url": "https://blog.michelanders.nl/2017/08/", "unformatted_src": "https://2.bp.blogspot.com/-50I78_b0pE4/WY6eCI2hcpI/AAAAAAAAPvI/N6Gm4m1yJEENG-g-l6vHW7zYetthX4GCQCLcBGAs/s400/mosaic%2Bline%2Boverview.png", "src": "https://2.bp.blogspot.com/-50I78_b0pE4/WY6eCI2hcpI/AAAAAAAAPvI/N6Gm4m1yJEENG-g-l6vHW7zYetthX4GCQCLcBGAs/s400/mosaic%2Bline%2Boverview.png", "formatted_filename": "mosaic Bline Boverview", "rendered_width": 400, "rendered_height": 57}, null, {"document_url": "https://blog.michelanders.nl/2017/08/", "unformatted_src": "https://1.bp.blogspot.com/-PdWoWuZhIpY/WY6dqXvZX8I/AAAAAAAAPvE/wha-N3SsLL4hE3VQ5PxQj8kkISjgDz6NQCLcBGAs/s400/mosaic%2Bline.png", "src": "https://1.bp.blogspot.com/-PdWoWuZhIpY/WY6dqXvZX8I/AAAAAAAAPvE/wha-N3SsLL4hE3VQ5PxQj8kkISjgDz6NQCLcBGAs/s400/mosaic%2Bline.png", "formatted_filename": "mosaic Bline", "rendered_width": 400, "rendered_height": 50}, null, null, null, null, null, null, null, null, null, null, null, null]
Nodeset: additional features and clean-up

In a reply on a previous post monari suggested some additional functionality and in the true spirit of open source even supplied a new implementation.

So in this version I incorporated most of his new code: if you now import a texture set with an associated shader you get a height map correctly wired to a normal node with the help of a bump node.

In addition I added the option to create a nodeset that is suitable for use with microdisplacement, i.e. that wires the height map with a multiply to the displacement socket of the material output (the option is available on the left side of the fileselector). The two variants of the node setup are shown below: 

Posted by Michel 1 comments Labels: add-on, Blender, node, node wrangler, Substance Painter, textures

Avoiding repetition artifacts with chaos mosaic 

Node group The result has less visible seams but is also somewhat blurred: The highlighted area shows a visible seam: Especially at close range: Some details Posted by Michel 5 comments 

Tiny Blender Addon: Snap and transform

Enhancements available now: check the description

I was doing some arch-viz the other day and I was placing a lot of objects in a large scene. The objects where placeholders that I created on the spot and more often than not I needed to move the origin of the new mesh object to a selected vertex for easy positioning, scaling, rotating etc.

This is of course simple enough: select Snap cursor to selected in edit mode, switch to object mode and then select Transform → origin to 3d cursor.
But it is also a lot of actions for a simple operation, especially if you doing this a hundred times in a scene...

Another common scenario that I encounter is that I want to position the origin at the lowest point of a mesh. This is a little bit more involved as far as the code is concerned, a small explanation below for those who are interested in doing this on large meshes in a fast way.

Anyway, here is a small add-on: Edit mode origin tools. It does nothing fancy, it will just create two new menu entries in edit mode:
Mesh → Snap → Origin to selected,
Mesh → Snap → Origin to lowest vertex (along z-axis)
and save you some time :-)


Download it from my GitHub repository (right-click on the first link and select save as ...) and in Blender go to File → User preferences → Add-ons → install from file ... (don't forget to enable it after installation. Note that the downloaded file is called snapandtransform.py while the add-on will appear as Edit mode transform tools)

Finding the location of the lowest vertex (fast)

If we want to get all the vertex coordinates fast, we got to switch to object mode first (line 2), get the number of vertices present (line 4) and the allocate an empty numpy array to hold all coordinates (line 7). Then we can use the foreach_get() method to get all coords (the co attribute of the verts array) in one go (line 8). It will be a flattened array so we have to reshape it to an array of 3-vectors (line 9). Now all the coordinates will be in object space so we will want to convert all of them to world space. For this we need to multiply each of them with the matrix_world of the object. This is necessary because due to rotations the lowest vertex in object space need not be the lowest vertex in world space!

The world matrix is a 4x4 matrix (one that holds not only scale and rotation but translation as well) so we need to extend all our coordinate vectors with a fourth coordinate of 1 (lines 10,11). We also convert the matrix_world to a numpy array (line 12).

Line 14 is then where all the magic happens: we multiply our numpy world matrix M with our array of extend coordinates using the new @ operator. (new since Python 3.5 and especially added to allow numpy code to be better readable). The double transpose is to allow matrix multiplication of a 4x4 matrix with a list of 4-vectors and transform the result back again. The fourth coordinate of the result is dropped by the [:,:3] slice index.

Now that we have converted all coordinates to world space, all we have to do is the find the index of the coordinate with the lowest z-coordinate with argsort() and assign this to the position of the 3d-cursor before calling the origin-set() operator. Labels: add-on, Blender, edit mode, origin, snap, snap and transform