Greetings. I’ve been trying for some time to make a shader that bends “flat/ortogonal” geometry into a cylindrical shape, but I couldn’t make it to work perfectly. After many trial and errors I managed to make the shader script work as I intended, but only for objects that don’t contain any form of rotation or scale. One workaround was to make a C# script that completely resets any rotated or scaled mesh vertices to origin, using a transform matrix, but this seemed inefficient to do all the time with all scene gameObjects. I understand how object space and world space work, I just don’t understand why my shader is using the local transform of the object’s mesh, when I am ‘clearly’ using a world position based vertex transformations.
Shader "Custom/CylinderBendShader"
{
Properties
{
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Texture", 2D) = "white" {}
_CurveOrigin ("Curve Origin", Vector) = (0,0,0)
_Length ("Length", Float) = 36.0 //// Length in X coord, to completely wrap around
_RadiusMultiplier ("Radius Multiplier", Float) = 1.0
//_Toggle ("OFF/ON", Range(0, 1)) = 0
}
SubShader
{
Tags {"Queue"="Transparent" "RenderType"="Transparent"}
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 normal : TEXTCOORD1;
};
float4 _Color;
float3 _CurveOrigin;
float _Length;
float _RadiusMultiplier;
uniform float _Toggle;
v2f vert(appdata v)
{
v2f o;
float4 wpos = mul(unity_ObjectToWorld, v.vertex);
half Ydist = wpos.y - _CurveOrigin.y;
float x,y,z;
// MAIN CYLINDER WRAPPING PART, I'm not very good at math/trig, I just found this on the web
x = _RadiusMultiplier * Ydist *_Length/(2 * UNITY_PI) * sin(2 * UNITY_PI * (wpos.x/_Length));
y = _RadiusMultiplier * Ydist *_Length/(2 * UNITY_PI) * cos(2 * UNITY_PI * (wpos.x/_Length));
z = wpos.z;
// I added this by mistake with trial and error, but it's needed to put the geometry in proper place, not sure why
x += (v.vertex.x - wpos.x);
y += (v.vertex.y - wpos.y);
z += (v.vertex.z - wpos.z);
// just lerping for visual purposes
float lerpX = lerp(v.vertex.x, x, _Toggle);
float lerpY = lerp(v.vertex.y, y, _Toggle);
float lerpZ = lerp(v.vertex.z, z, _Toggle);
o.pos = UnityObjectToClipPos(float3(lerpX, lerpY, lerpZ));
o.uv = v.uv;
o.normal = v.normal;
o.Ydistance = wpos.y;
o.Zdistance = wpos.z;
return o;
}
sampler2D _MainTex;
fixed4 frag(v2f i) : SV_Target
{
///////FRAG SHADER
}
ENDCG
}
}
}
4iixrt
I attached the video showing the shader in action. I am lerping between normal state and bended state. Every geometry behaves good, except for the blue cylinder which is rotated and scaled. Doesn’t work properly even if it’s only rotated or only scaled. Only translation seems to work fine.
Thanks for any help in advance. @bgolus