# UV partial derivatives of a cylinder shape primitive

I am new to rendering and I would like to calcualte UV partial derivatives of a cylinder shape, which is parameterized by radius $$R$$ and length $$L$$.

Using cylindrical coordinate mapping, for a surface point $$\mathbf{p}=(x,y,z)$$, the UV map (normalized to $$[0,1]$$) is: $$(u,v) = \Big(\frac{\phi}{2\pi}, \frac{z}{L}\Big)\qquad \text{where} \quad \phi = \arctan \frac{y}{x}$$ Then I compute the derivatives with respect to $$\mathbf{p}$$, that is: \begin{aligned} \frac{\partial u}{\partial \mathbf{p}} & = \frac{1}{2\pi R^2} \Big( -y, x, 0\Big) = \frac{1}{2\pi R} \Big( -\sin\phi, \cos\phi, 0\Big)\\ \frac{\partial v}{\partial \mathbf{p}} &= \Big( 0, 0, \frac{1}{L}\Big) \end{aligned} Or equivalently: \begin{aligned} \frac{\partial \mathbf{p}}{\partial u} & = 2\pi R \Big( -\frac{1}{\sin\phi}, \frac{1}{\cos\phi}, 0\Big)\\ \frac{\partial \mathbf{p}}{\partial v} &= \Big( 0, 0, L\Big) \end{aligned} Everything looks good until now.

Question

In pbrt-3, the relevant part of cylinder.cpp is: (i) UV same as above; (ii) $$\partial \mathbf{p}/\partial u$$ however is different:

Float u = phi / phiMax;
Float v = (pHit.z - zMin) / (zMax - zMin);

// Compute cylinder $$\dpdu$$ and $$\dpdv$$
Vector3f dpdu(-phiMax * pHit.y, phiMax * pHit.x, 0);
Vector3f dpdv(0, 0, zMax - zMin);


What am I missing here?

I think it's easiest to get the tangent frame by writing the forward mapping from $$(u,v)$$ to $$\mathbf{p}$$: $$\mathbf{p}(u,v) = \begin{bmatrix} R \, \cos (2\pi u) \\ R \, \sin (2\pi u) \\ vL \end{bmatrix}$$ Then you can see that the derivatives are: $$\frac{\partial\mathbf{p}}{\partial u} = \begin{bmatrix} -2\pi R \, \sin(2\pi u) \\ 2\pi R \, \cos(2\pi u) \\ 0\end{bmatrix} = \begin{bmatrix} -2\pi y \\ 2\pi x \\ 0\end{bmatrix}, \qquad \frac{\partial\mathbf{p}}{\partial v} = \begin{bmatrix} 0 \\ 0 \\ L \end{bmatrix}$$ which matches the pbrt code.
I think your derivation went wrong by assuming that $$\partial\mathbf{p}/\partial u$$ was the component-wise reciprocal of $$\partial u / \partial{\mathbf{p}}$$. It's not so simple, because the latter object is really the gradient of $$u$$, where $$u$$ is now considered as a scalar field defined over all space (not just on the cylinder). To invert this properly we really need another coordinate running perpendicular to $$u$$ in the $$xy$$ plane, so that we have a locally invertible mapping; then we can take its Jacobian matrix and invert that. We can use the radius $$R$$ as such a coordinate. Then we have the inverse mapping, \begin{aligned} u(x,y) &= \frac{1}{2\pi} \arctan(y,x) \\ R(x,y) &= \sqrt{x^2 + y^2} \end{aligned} whose Jacobian is: $$\frac{\partial(u,R)}{\partial(x,y)} = \begin{bmatrix} \tfrac{\partial u}{\partial x} & \tfrac{\partial u}{\partial y} \\ \tfrac{\partial R}{\partial x} & \tfrac{\partial R}{\partial y} \end{bmatrix} = \begin{bmatrix} -y/(2\pi R^2) & x/(2\pi R^2) \\ x/R & y/R \end{bmatrix}$$ and the inverse of that is: $$\frac{\partial(x,y)}{\partial(u,R)} = -2\pi R \begin{bmatrix} y/R & -x/(2\pi R^2) \\ -x/R & -y/(2\pi R^2) \end{bmatrix} = \begin{bmatrix} -2\pi y & x/R \\ 2\pi x & y/R \end{bmatrix}$$ from which you can then read off $$\partial{(x,y)}/\partial u$$ as the first column, which matches the result obtained for $$\partial\mathbf{p}/\partial u$$ above.