Introduction
In Unity, I needed to convert polygon vertex coordinates from rectangular (Cartesian) coordinates to cylindrical coordinates in real time, so I created a Shader for that purpose.
The sample Unity project is available here:
https://github.com/segurvita/UnityCylindricalCoordinate
What It Does
The animation above shows the actual rendering result. Here is what it can do.
The mesh floating at the top is the original mesh shape, and the one rolling on the ground below is the result of converting it to cylindrical coordinates. (More precisely, it renders the coordinates obtained by converting from rectangular to cylindrical coordinates and then projecting them back into rectangular space.)
Everything except the Shader uses the same data.
In this animation the objects are stationary, which makes it hard to convey, but since the coordinate conversion happens in real time, any deformation of the original mesh via animation is properly reflected.
As a bonus, I also wrote the inverse conversion from cylindrical back to rectangular coordinates.
Axis Convention
In Unity, y represents the height axis rather than z. Therefore, this implementation assumes a cylindrical coordinate system with the y-axis as the central axis. In general conventions the z-axis is used as the central axis, so the formulas may differ from other references. Please keep this in mind.
Cylindrical Coordinate Values
The coordinate values used here consist of the following three components:
-
r: Radial distance from the central axis of the cylinder. -
θ: Circumferential angle. Unit: radians [rad] -
y: Position along the cylinder's axis.
Sample Code
Below is the Shader file I created.
Shader "Custom/CylindricalCoordinate"
{
Properties {
_MainTex ("Main Tex", 2D) = "white" {}
[MaterialToggle] _canR2C ("Enable Rectangular To Cylindrical", Float) = 1 // 0 is false, 1 is true
[MaterialToggle] _canC2R ("Enable Cylindrical To Rectangular", Float) = 1 // 0 is false, 1 is true
}
SubShader {
Tags {
"Queue"="Geometry"
}
Pass {
CGPROGRAM
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
half2 uv : TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
half2 uv : TEXCOORD0;
};
// Function to convert rectangular coordinates to cylindrical coordinates
float4 r2c (float4 rec){
float4 cyl;
// Calculate r in cylindrical coordinates
cyl.x = sqrt(rec.x * rec.x + rec.z * rec.z);
// Calculate θ in cylindrical coordinates
if(rec.x==0.0 && rec.z==0.0){
// At the singularity θ is undefined; set θ = 0 as a fallback
cyl.z = 0.0;
}else{
cyl.z = atan2(rec.z, rec.x);
}
// Pass through unchanged
cyl.y = rec.y;
cyl.w = rec.w;
return cyl;
}
// Function to convert cylindrical coordinates to rectangular coordinates
float4 c2r (float4 cyl){
float4 rec;
rec.x = cyl.x * cos(cyl.z);
rec.y = cyl.y;
rec.z = cyl.x * sin(cyl.z);
rec.w = cyl.w;
return rec;
}
uniform sampler2D _MainTex;
float _canR2C;
float _canC2R;
#pragma vertex vert
#pragma fragment frag
v2f vert (appdata v) {
v2f o;
// Convert rectangular coordinates to cylindrical coordinates
if(_canR2C){
v.vertex = r2c(v.vertex);
}
// Convert cylindrical coordinates to rectangular coordinates
if(_canC2R){
v.vertex = c2r(v.vertex);
}
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i): SV_Target {
return tex2D(_MainTex, i.uv);
}
ENDCG
}
}
}
How to Use
Create a new Shader file and paste the sample code above into it.
Create a new Material file and select Custom/CylindricalCoordinate from the Shader dropdown.
Assign the Material file to the Materials field of the object's Mesh Renderer.
Checking Enable Rectangular To Cylindrical converts from rectangular to cylindrical coordinates.
Checking Enable Cylindrical To Rectangular converts from cylindrical to rectangular coordinates.
When both are enabled, the mesh is converted from rectangular to cylindrical and then back to rectangular, so the visual appearance should not change.
About Properties
Parameters declared in Properties can be controlled from the Unity Editor.
_MainTex lets you specify a texture image.
_canR2C is a checkbox to enable or disable the rectangular-to-cylindrical conversion.
_canC2R is a checkbox to enable or disable the cylindrical-to-rectangular conversion.
Rectangular to Cylindrical Conversion
The formulas are as follows:
arctan is the arctangent. Because we need to preserve the sign, the actual Shader uses atan2.
In the Shader this is implemented in the r2c function. rec holds the rectangular coordinates and cyl holds the cylindrical coordinates. For coding convenience, cyl.x maps to r and cyl.z maps to θ.
When both x=0 and z=0, θ is undefined; we set θ=0 as a fallback. Such a point is called a singularity.
Cylindrical to Rectangular Conversion
The formulas are as follows:

In the Shader this is implemented in the c2r function.
Vertex Shader
The vert function is the vertex shader (also called the vertex program). The vertex shader can modify the coordinate values of polygon vertices. This is where r2c and c2r are called. Which function to execute can be toggled based on the checkbox inputs.
Fragment Shader
The frag function is the fragment shader (also called the pixel shader). It is not involved in the coordinate conversion itself, but it is the minimum required function for rendering, so it is included here. It simply renders the input texture using the same UV coordinates.
Closing
I confirmed that it runs in real time on Windows, Mac, and iOS. This was my first time working with shaders, and I was amazed at how fast the computation is. I plan to explore more shader techniques going forward.


Top comments (0)