Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
0
Question by Soos621 · Nov 08, 2015 at 05:50 PM · unity5shader programming

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"

}

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
1

Answer by rageingnonsense · Nov 08, 2015 at 06:03 PM

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.

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Soos621 · Nov 08, 2015 at 06:38 PM 0
Share

this is the line I'm having some problems with exactly

float3 planetDirection = _CentrePoint.xyz - IN.worldPos;

I'm getting an incompatible types in initialization, i assume this means that the type of variable that i am using is incorrect, but as i said before I'm very new to shader scripting and my understanding of the syntax and matrix math is at best crude.

Thnak you for the answer though and i will be checking into the triplanar texturing.

EDIT:

So I've fixed the error but I'm not getting the correct values from the slope calculation, this shader is on a sphere and so it is picking up that half the sphere is below the slope limit, which is obviously wrong, anyway i think i may have forgotten to add in a variable somewhere to make sure that its calculating from the correct direction, seems like its calculating from the sphere's general direction. But I'm unsure how to use the code you've posted, ill hold onto it though it may come in handy later on, but as of now I'm lost on how to use it haha. Thanks again.

avatar image rageingnonsense Soos621 · Nov 09, 2015 at 02:28 AM 0
Share

This is because dot product for two normals will go from -1 to 1. Since you only care about 1 to 0, you can actually just use the abs() result. :)

EDIT: To elaborate on this, Your calculation will break down eventually because you will flip to the other side, and on the other side of the planet you would reverse the parameters of the subtraction. At least I think this is what is happening. In any event, the abs() wrapper should be enough to fix the problem. $$anonymous$$inda curious what happens at the poles though...

avatar image rageingnonsense Soos621 · Nov 09, 2015 at 02:30 AM 0
Share

Also the code I posted for triplanar texturing is easy. Anywhere you were going to use tex2D, just use tex2DTriPlanar ins$$anonymous$$d. Easy peasy. Just need to add this function to your shader (just like you would with vert, frag etc). They are support functions.

avatar image Soos621 rageingnonsense · Nov 09, 2015 at 04:26 AM 0
Share

So i tried replacing my tex2d with the triplanar function and it seems to have made them very low resolution and hard to see. What im doing with the triplanar function is this:

fixed4 water = tex2DTriPlanar(_WaterTex, IN.worldPos, IN.worldNormal);

i may be inputting a wrong param which could result in the textures messing up.

Also I'm not getting anything from the wrapping the dot product in abs its actually working worse. I thought that was the case when i first encountered the problem. It seems I'm mixing up something here lol.

Newest Script Section:

       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;
      }
 
      void surf (Input IN, inout SurfaceOutput o) {
          fixed4 water = tex2DTriPlanar(_WaterTex, IN.worldPos, IN.worldNormal);
          fixed4 swamp = tex2DTriPlanar(_SwampTex, IN.worldPos, IN.worldNormal);
          fixed4 desert = tex2DTriPlanar(_DesertTex, IN.worldPos, IN.worldNormal);
          fixed4 plains = tex2DTriPlanar(_PlainsTex, IN.worldPos, IN.worldNormal);;
          fixed4 forest = tex2DTriPlanar(_ForestTex, IN.worldPos, IN.worldNormal);
          fixed4 mountain = tex2DTriPlanar(_$$anonymous$$ountainTex, IN.worldPos, IN.worldNormal);
          fixed4 arctic = tex2DTriPlanar(_ArcticTex, IN.worldPos, IN.worldNormal);
          fixed4 cliff = tex2DTriPlanar(_CliffTex, IN.worldPos, IN.worldNormal);
          
          float dist = distance(_CentrePoint.xyz, IN.worldPos);
          fixed4 c = water;
   
          float planetDirection = IN.localPos - _CentrePoint.xyz;    
               
          if(abs(dot(normalize(IN.worldNormal), planetDirection)) < _SlopeLimit){
             c = cliff;
          } else {
                //all the different distance stuff...
          }
          
          o.Albedo = c.rgb;
          o.Alpha = c.a;
      }
      ENDCG

Thanks for your time and help.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

35 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Replaced '_Object2World' with 'unity_ObjectToWorld' 1 Answer

Standard Cutout Double Sided? 0 Answers

Fresnel/Edge shader problem 1 Answer

Custom shader not working on Samsung S6 1 Answer

Unity 2018 without shader editor 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges