I realize it might be hard to diagnose this from a distance, but maybe somebody witnessed a simular error. I progressed through the book and got to the point where patterns are introduced. I implemented the stripe and gradient pattern. When I assign them to objects, only the left half of the objects display them properly (I'm assuming everywhere where X < 0 ?). I went back through all the unit tests, but can spot where I made a mistake. Any ideas?
Also, if you look closely, only the middle sphere has a highlight. I tried to stick to Jamis' positioning, but somehow it looks slightly different.
Hi! I think you're probably on the right track, bibac. The fact that your plane is textured correctly gives me great hope! Here's what I think is happening:
1. The stripe and gradient patterns are each designed to alternate at whole number increments: x=0, 1, 2, 3, 4, etc.
2. Your spheres are each located (in object space) at the origin. The left side of each sphere is at x=-1, and the right side is at x=1. This means the pattern is repeating exactly once for each sphere, starting at x=-1, starting again at x=0, and ending at x=1.
If you want your gradient to transition smoothly exactly once across each sphere, and keeping in mind that your gradient texture repeats at every x=0, 1, 2, 3 etc, you need to add a transformation to your gradient. First, scale it by 2 in x (to change the frequency of the gradient, so it repeats on x=0, 2, 4, 6, etc.), and then translate it by -1 in x (to change the period, so it repeats on x=-1, 1, 3, 5, etc).
I hope that makes sense. This is a pretty common strategy when using these kinds of patterns: scale them to change the frequency, translate to change the period, and then rotate around y and/or z (if desired) to change the orientation.
I'll see if I can add a sidebar to the patterns chapter to be more explicit about this behavior.
Last Edit: Nov 22, 2018 15:20:37 GMT by Jamis: typos
Thanks! That seems to be it! The only odd thing was, that I had to translate X by -0.5 instead of -1. Maybe some oddness with my scene, I will dig into it. My code looks like this now, with "m" being the material used for the spheres:
Re: the transformation, I suspect it's an order of operations thing. What does "NewTransform().Scale(...).Translate(...)" do? Does it multiply the translation by the scaling, or the scaling by the translation?
The reason I ask is that if you perform the translation first (moving the pattern's period back by 0.5) and then scale, you'll get the same effect I described (scaling by 2 first, and then translating back by 1).
Either way, though -- it looks good! I'm glad it was simple to straighten out.
You're right. If I switch the translation and scaling in my code, then your values work. The code is supposed to create an identiy matrix, then multiply that with scale matrix, then multiply the result with the translation matrix, then return that result. I think I switched the multiplicators.
It works exactly as you're describing, but if you want X.Scale(...).Translate(...) to do the scale BEFORE the translate (which is what you'd intuitively expect) you need the Translate method to multiply the new translation matrix by "self", and not the other way around. In pseudocode, something like this:
class Matrix initialize() set self to identity matrix and
method Translate(x, y, z) // NOT self * TranslateMatrix(...)!! TranslateMatrix(x,y,z) * self end
method Scale(x, y, z) // NOT self * ScalingMatrix(...)!! ScalingMatrix(x, y, z) * self end
m = Matrix() // identity matrix
m = m.Translate(1, 2, 3).Scale(2, 2, 2)
// m is now the same as ScalingMatrix(2, 2, 2) * TranslateMatrix(1, 2, 3) * IdentityMatrix // which performs the translation FIRST and the scaling SECOND
Does that make sense? Matrix multiplication is weird.