For some reason this was an hour long ordeal to figure out to do this, mostly due to my inexperience with 3d software but also because I think the material node could be more powerful to make this easier.
After you add material to some part of your model, sometimes the texture is just too small/big or you would like it offset or rotated.
To do this you need to manipulate the texture coordinates that are attached to the area you are texturing.
Add a ‘uv texture’ node. This will add some uv vertex attributes to your model. Materials work out of the box without UVs, but adding them manually allows you to manipulate things like scale/offset/angle.
It would have been super nice if the material node itself had an option to transform uv coordinates that it receives. Allowing this would make it possible to scale/rotate/offset the default input uvs without having to drop in a UV node myself and make it easier to create things. Perhaps later I will find out a good counter argument for not having this feature, but right now it feels like a painpoint.
I recently upgraded to Houdini Indie. Unforuntately, I was not able to open my work that I originally created through Houdini Apprentice.
The file format supported by Houdini Indie is hiplc (lc stands for limited commercial). If you open a hipnc file (non-commercial) inside of Houdini Indie, it will just instead open it through Houdini Apprentice and you will not be allowed to use any of the Indie features.
Thankfully, there is a way to convert between hipnc and hiplc.
When creating curve I ran into a problem when trying to make a copy of the curve that would run parallel to my existing curve. Sometimes you can not simply scale the curve up. For example:
Just applying a scale & translate transform does not work. You’d get a result like this, which does not keep an equal distance between the 2nd curve and the 1st curve. You could manually adjust the points using the move tool, but it will not nearly be as nice as doing this procedurally.
Specifically what we want to do to get the desired effect is we want to move the 2nd curve to have its point positions moved away exactly in the direction of its ‘bitangent’. The bitangent for a point in this case is the direction which is perpendicular to both the tangent and the normal. The normal here for each point is in the direction of the plane which the curve is being drawn on (pointing out of your screen).
The PolyFrame node has the ability to add normals, tangents, and bitangents for each point in our curve, as well it can add each attribute under any attribute name we want! The Peak node has the ability to move each point along its normal. Using a combination of both the PolyFrame node and the Peak node we can create a 2nd curve which runs parallel to the first, while maintaining an equal distance between the 2 curves.
FYI: All screenshots here are taken while I’m using Houdini 15.5
1) Draw the first curve
This is up to you of course. I’ll be drawing my simple curve through the ‘top view’.
2) Place down a PolyFrame node
This will allow us to add the bitangents to each point. The important idea here is to actually add the bitangents with the attribute name ‘N’, so that we can simply use the peak node (Which operates using the N attribute). Once again, the original name for bitangents was ‘tangentv’, I renamed it to N so that it is compatible with the Peak node we will use later on.
optional) Turn on display normals
This will help you see that the ‘normals’ are in fact pointing in the correct direction. Note: Remember, our normals in this case are actually bitangents but we named them with N so this means that the viewport is tricked into displayed these as normals!
3) Use the Peak node to move the line along its ‘Normals’
Note: It doesn’t matter that ‘Recompute Point Normals’ is checked here, as we won’t be using the normals anymore after node, though it will wipe out the bitangents that we added.
4) Merge the original curve with this new curve
5) Housekeeping: Delete the extra attribute from the 2nd curve
As you can see, there’s a warning on the merge node saying that there’s an attribute mismatch. This is because one of the inputs has normals and the other does not. We can either delete the attribute using an attribute delete node, or simply merge from the polyframe instead of the the original curve node. I will add an attribute delete node to delete ‘N’.
Please comment if you know of a different approach or if something is unclear!
EDIT: I ran into a different type of approach to this problem, check that out here: https://vimeo.com/188571086
How to create a spring using Houdini’s ‘For’ loop node
I recently wanted to create a spring model in houdini and found that neither the copy node, nor the poly extrude tool in themselves made this easy.
In the end, using a combination of the copy node, poly bridge, and most imporatantly the ‘for’ node does the job well.
What didn’t work
The copy node lets us specify how many copies we want to make, as well as how to translate and rotate each new copy. If we were to simply place down a circle and then use the copy node to create a spring pattern, but we would need to be able to connect each individual circle to form a solid spring shape. I.e. something like this:
Unfortunately, the copy node in itself does not have a way to connect the faces together. If it did, we could just check that box and call it a day.
I also considered an approach where I created a circle, copied it with a translation and rotated it so that I have 2 along the path of a spring, then use PolyBridge to create the first bit of the spring. Then tried to use a copy node to simply create many copies of this spring with translation and rotation. Unfortunately, the copy node in this case would create a bunch of disjoint pieces since the rotation between the copied pieces was off. I would get something like this:
In the end, what worked for me was using polybridge once for every pair of adjacent circles (opposed to using just 1 polybridge and copying that). It’s not feasible to do this by hand (Though i’m certain someone out there has done it).
What we’re going to do is this:
Create a copy node which creates exactly 1 more circle based off the original circle.
Use a PolyBridge node to connect the original circle to the new copied circle.
Repeat step 1, except this time we set the ‘original’ circle to be the newly copied circle.
We will use the ‘For’ node to have the ability to repeat ourselves.
Using the for node in this case will involve some management of groups to determine what the current circle is.
I will start from the top now that I have given an overview of how this is done. Also note that I’m using Houdini 15.5 for this.
Place a circle down
Add this single circle to a group
This group will at all times represent our ‘newest’ circle.
Let’s call this thing ‘copyGroup1’.
The copy node we use later can be configured to output groups for the copied primitive, we will make sure that it outputs the group name as ‘copyGroup1’. We will use this group to represent the newest circle primitive. At first we create it manually, but every time after the copy node will augment our group to contain the newest circle primitive.
Add in the ‘For’ node
Doesn’t need any special configuration. The end node of the for contains the number of iterations to do. I recommend you keep this at 10 at first. If there’s a mistake in your loop, you can quickly put yourself in a loop that makes houdini do some serious cooking.
We will be adding all further nodes in between the ‘start’ and the ‘end nodes of the For.
Add a copy node in the For loop.
There are a few things we need to do to configure this copy node.
Add a bit of translation away from the current circle, both in the x and the y.
Add a bit of rotation to cause the circles to eventually spiral. Make sure to set your pivot as well (That will represent the center of the spring).
Set the source group to be copyGroup1. Think of this as meaning we want to copy the ‘newest’ circle primitive. We will make sure that copyGroup1 at all times refers to the newest circle.
Set the copy node to make ‘2’ copies. (This means make 1 actual copy…)
Check the ‘create output groups box’ and uncheck the ‘preserve groups’ box.
Make the group naming template to be: copyGroup`$CY`
This will make sure that the newly created circle will be placed into copyGroup1.
Adjust copyGroup1 to contain *only* the newest circle
After the copy node the new circle primitive is added into copyGroup1. Let’s just add a group node which adjusts copyGroup1 to just contain everything that’s not in copyGroup0. This will make copyGroup1 *just* contain the newest circle, and copyGroup0 will be the previous circle. This will make using the PolyBridge node easier.
Add a group node (i’ll name this name copyGroup_adjust), disable ‘creating’ of a group since this group node will just be editing an existing group.
To remove everything from copyGroup1 that is in copyGroup0, it would look like this:
Add a PolyBridge node
Let’s set the source group to copyGroup0 and the destination group to copyGroup1.
As well, I prefer using divisions = 1 here.
Also, uncheck ‘Reverse winding’.
Add the circle primitives back into the feedback loop
If you notice, the PolyBridge node actually gets rid of the primitives inside of copyGroup0 and copyGroup1. We want to add those back. We’ll at least need the contents of copyGroup1 for every next iteration of the loop. We can add these back into the feedback loop by simply feeding the output of my ‘copyGroup_adjust’ node into ‘repeat_end1’. We’ll need to use a merge node though since we can only have 1 input directly into the end block node.
Add all the PolyBridges back into the feedback loop as well
When we create a PolyBridge we’re passing it into the feedback (end block), but the first thing we’re doing in the loop is the ‘copy’ node which uses copyGroup0 and copyGroup1. This node is immediately erasing the PolyBridge primitives. If we pass the feedback from the input directly into the output, we can keep all our poly bridge primitives between every iteration.
I’m just going to add a connection between the start of the loop and the end of the loop (through the merge node).
There is 1 huge problem though, our connection directly from the input to the output that we just added is augmenting the new value of copyGroup1 with the previous iteration’s copyGroup1.
Let’s wipe out the previous iterations copyGroups before passing that feedback forward. Without this, copyGroup1 will actually grow exponentially as the copy node will be copying multiple circles at a time.
Let’s add a group node which just deletes copyGroup0 and copyGroup1, between the start of a our For begin node and our merge node.
Increase the end node’s iteration count
I recommend increasing this very slowly to make sure that a bug in your loop doesn’t cause Houdini to hang.
After this I have a nice spring that can wind as many times as I like:
If you happen to know of a better way to do this, please let me know in the comments.
Earlier this year I decided to finally invest time into learning about all things graphics.
I started by learning opengl fundamentals and all the basic graphics techniques used for real time rendering. I basically whet through all the tutorials that exist over here: http://learnopengl.com/
The most important thing I feel I learned was the limitations of a rasterization based render. Everything feels like a hack to me since it doesn’t really model real life.
I created a couple basic things with the opengl skills I learned.
Creating both took a total of 3 weeks while learning opengl (Lots of time spent debugging).
I have moved on to reading about physically based rendering. I’ve purchased this book:
It’s a 1000+ page book which reminds me of college.
At the same time I’m also investing in learning how to use Houdini. I’ve started with the basics, which would be learning how to model.
I’ve watched an 8 hour course in Houdini basics and have spent probably 15+ hours already on project where I want to create a pinball table model.
I started my journey to learn more about computer graphics about 48 days ago on August 14th. In just 48 days I’m fairly happy with the progress I’ve made. I’ve created this blog to reflect back on when I started and to track my progress.