Unity shader find slope of vertex from center of object

Hello, I have been working on a custom shader script that blends textures based on distance from the center of the mesh object. What I am attempting to do now is to calculate the “slope” of the vertex. I’m new to shader scripting and matrix math so i figured I’d post a question and see if anyone can help me out.

What i think i need to do is first get a directional “vector” or float3 from the center of the mesh object to the vertex, then i should be able to find the dot product of the first direction against the normal direction of the vertex which should tell me the slope of said vertex. Any information as to if i am not thinking this through correctly and really how to find the directional vector from the center of the mesh to the vertex would be much appreciated.

Here is a copy of my shader script. which is currently non-functional due to the “planetdirection” not being correct. Thanks and have a great one!

Shader “Custom/FromCenter” {
Properties {
_CentrePoint (“Centre”, Vector) = (0, 0, 0, 0)

     _BlendThreshold ("Blend Distance", Float) = 0.5
     
     _WaterTex ("Water Texture", 2D) = "white" {}
     _DesertTex ("Desert Texture", 2D) = "white" {}
     _ForestTex ("Forest Texture", 2D) = "white" {}
     _MountainTex ("Mountain Texture", 2D) = "white" {}
     _SwampTex ("Swamp Texture", 2D) = "white" {}
     _ArcticTex ("Arctic Texture", 2D) = "white" {}
     _PlainsTex ("Plains Texture", 2D) = "white" {}
     
     _SwampHeight ("Swamp Height", Float) = 3
     _DesertHeight ("Desert Height", Float) = 3
     _PlainsHeight ("Plains Height", Float) = 3
     _ForestHeight ("Forest Height", Float) = 3
     _MountainHeight ("Mountain Height", Float) = 3
     _ArcticHeight ("Arctic Height", Float) = 3
 }
 SubShader {
     Tags { "RenderType"="Opaque" }
     LOD 200
     
     CGPROGRAM
     #pragma surface surf Lambert
     

     float4 _CentrePoint;
     float _BlendThreshold;
     float _SlopeLimt;

     sampler2D _WaterTex;
     sampler2D _SwampTex;
     sampler2D _DesertTex;
     sampler2D _PlainsTex;
     sampler2D _ForestTex;
     sampler2D _MountainTex;
     sampler2D _ArcticTex;
     
     float _SwampHeight;
     float _DesertHeight;
     float _PlainsHeight;
     float _ForestHeight;
     float _MountainHeight;
     float _ArcticHeight;

     struct Input {
         float2 uv_WaterTex;
         float3 worldPos;
         float3 localPos;
         float3 worldNormal;
		 INTERNAL_DATA
     };
     
     void vert (inout appdata_full v, out Input o) {
		UNITY_INITIALIZE_OUTPUT(Input,o);
		o.localPos = v.vertex.xyz;
	 }

     void surf (Input IN, inout SurfaceOutput o) {
     	
         half4 water = tex2D (_WaterTex, IN.uv_WaterTex);
         half4 swamp = tex2D (_SwampTex, IN.uv_WaterTex);
         half4 desert = tex2D (_DesertTex, IN.uv_WaterTex);
         half4 plains = tex2D (_PlainsTex, IN.uv_WaterTex);
         half4 forest = tex2D (_ForestTex, IN.uv_WaterTex);
         half4 mountain = tex2D (_MountainTex, IN.uv_WaterTex);
         half4 arctic = tex2D (_ArcticTex, IN.uv_WaterTex);
         
         float dist = distance(_CentrePoint.xyz, IN.worldPos);
         half4 c = water;
  
  		 float3 planetDirection = _CentrePoint.xyz - IN.worldPos;	
  			
         if(dot(normalize(IN.worldNormal), planetDirection) < _SlopeLimit){
         	 c = mountain;
         } else {
             if (dist > _SwampHeight){
             	float startBlending = _SwampHeight - _BlendThreshold;
             	float changeFactor = saturate((dist - startBlending) / (_BlendThreshold * 2));
             	c = lerp(water, swamp, changeFactor);
             }
             if(dist > _DesertHeight){
             	float startBlending = _DesertHeight - _BlendThreshold;
             	float changeFactor = saturate((dist - startBlending) / (_BlendThreshold * 2));
             	c = lerp(swamp, desert, changeFactor );
             }
             if(dist > _PlainsHeight){
             	float startBlending = _PlainsHeight - _BlendThreshold;
             	float changeFactor = saturate((dist - startBlending) / (_BlendThreshold * 2));
             	c = lerp(desert, plains, changeFactor);
             }
             if(dist > _ForestHeight){
            	float startBlending = _ForestHeight - _BlendThreshold;
             	float changeFactor = saturate((dist - startBlending) / (_BlendThreshold * 2));
             	c = lerp(plains, forest, changeFactor);
             }
             if(dist > _MountainHeight){
             	float startBlending = _MountainHeight - _BlendThreshold;
             	float changeFactor = saturate((dist - startBlending) / (_BlendThreshold * 2));
             	c = lerp(forest, mountain, changeFactor);
             }
             if(dist > _ArcticHeight){
             	float startBlending = _ArcticHeight - _BlendThreshold;
             	float changeFactor = saturate((dist - startBlending) / (_BlendThreshold * 2));
             	c = lerp(mountain, arctic, changeFactor);
             }
         }
         
         o.Albedo = c.rgb;
         o.Alpha = c.a;
     }
     ENDCG
 } 
 FallBack "Diffuse"

}

I have a shader just like this for a spherical terrain. If you are trying to get the slope of the terrain for the purpose of cliffs, and stuff like this, I recommend looking up the concept of Triplanar texturing. While I am not answering your question directly, I have a feelign I am answering the spirit of it. Anyways, here is a snippet from my shader (which is VERY similar to yours):

            /// returns a color that is blended with larger samples of itself. used to
	// reduce the appearance of tiling
	fixed4 tex2DTiled(sampler2D tex, float2 uv) {			
		return tex2D(tex, uv) * tex2D(tex, uv * -0.1) * tex2D(tex, uv * -0.01) * 4;
	}
	
	
	fixed4 tex2DTriPlanar(sampler2D tex, float3 coords, float3 norm) {
		float3 blending = abs(norm);
		blending = normalize(max(blending, 0.00001));
		float b = (blending.x + blending.y + blending.z);
		blending /= float3(b, b, b);
		
		fixed4 xaxis = tex2DTiled(tex, coords.yz);
		fixed4 yaxis = tex2DTiled(tex, coords.xz);
		fixed4 zaxis = tex2DTiled(tex, coords.xy);
		
		// blend the results of the 3 planar projections.
		fixed4 retVal = xaxis * blending.x + yaxis * blending.y + zaxis * blending.z;
		return retVal;
	}

What this does is make textures not look stretched on sloped surfaces. You use it as a drop-in replacment for tex2D(). I realize though that you need this for a different reason (althoguh I bet you’ll get use out of what I posted anyways).

The way you are calculating the slope looks correct to me though:

dot(normalize(IN.worldNormal), planetDirection) < _SlopeLimit

Just remember that 1 means the normals are aligned, and 0 means that are completely perpendicular. Is there some reason that your current code is not working for this? It might be helpful to use IN.worldNormal as the output color for all of this so you can visualize the changes in slope; see if that value coming in even makes sense.