• 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 /
avatar image
Question by SharpeDesigns · Dec 20, 2016 at 03:23 PM · shadersgraphicsshader programmingvisual-effectsvertex color

Persistent data values in shaders

Hey everyone! Here's one for all you graphics wizards out there.

Currently diving into the world of shaders thanks to these amazing tutorials and I'm trying to figure out if there's any way to store the changes made in a vertex function for use in future passes through the shader. For example:

 Shader "Example/PersistentProperties" {
     Properties {
         _MainTex ("Texture", 2D) = "white" {}
         _FarColor ("UnlitColor", Color) = (0,0,0,1)
         _NearColor("LitColor", Color) = (1,1,1,1)
     }
     SubShader {
         Tags { "RenderType" = "Opaque" }
         CGPROGRAM
         #pragma surface surf Lambert vertex:vert
 
         float4 _ObjectPosition;
         sampler2D _MainTex;
         float4 _FarColor;
         float4 _NearColor;
 
         struct Input {
             float2 uv_MainTex;
             float4 vertColor;
         };
 
         void vert(inout appdata_full v, out Input o) {
             UNITY_INITIALIZE_OUTPUT(Input, o);
             float distanceVal = 1.0 + ((1.0 / 20.0)*(40.0 - distance(mul(unity_ObjectToWorld, v.vertex).rgb, _ObjectPosition.rgb)));
             
             // This is the value I don't want to reset!
             v.color.a += distanceVal;
 
             o.vertColor.a = v.color.a;
         }
 
         void surf (Input IN, inout SurfaceOutput o) {
             o.Albedo = lerp(_FarColor.rgb, _NearColor.rgb, IN.vertColor.a);
         }
 
         ENDCG
     } 
     Fallback "Diffuse"
 }

Here I've made a surface shader that illuminates all the vertices around a target object, so the closer the object, the brighter its surroundings. But what I want really want, is for vertices to get brighter the closer this object gets but NOT darker as it moves away. To do that, the input vertex alpha would have to add on to the value from the previous iteration through the shader instead of starting from scratch every time.

So is there any way I can cache the existing vertex colors and manipulate them in the following pass? Or is there some method of permanently overwriting the appdata info from within the shader?

I'd previously accomplished this effect by modifying the mesh colors in a separate C# script, but I'm curious if it's possible to calculate all this straight from the shader instead.

Thanks!

EDIT: Here's an example of what I currently have (pictured on the left) vs. what I'd like to accomplish (on the right):

Example

EDIT 2: Added an alternate vertex & fragment version with a grab pass in the comment below.

Comment

People who like this

0 Show 5
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 Glurth · Dec 20, 2016 at 03:44 PM 0
Share

Some questions: if you want the verticiets to get "brighter" (usually this means closer to white in color): why do you adjust the alpha (transparency)? To make stuff brighter I usually multiply the .rgb vector by some value greater than 1.0

You mention a "following pass" but I only see one pass in this shader. "Pass" has a very specific meaning in shaders, perhaps you meant something else? I'm not sure I understand why you can't set the brightness with a single call.

I see a _ObjectPositon variable, but I'm not sure how it is assigned a value, since there is no variable in the shader structure (up top) for it.

Suggestion:

I think you can do this in a single pass, given the distance to the object (your code looks good for this):

 float x=distance(mul(unity_ObjectToWorld, v.vertex).rgb, _ObjectPosition.rgb)

I like the infinity normalization function: 1- a/(a+x) where a is a constant that defines how fast increasing X values should scale towards one. Note: This expression will never have a value >= 1.0 (for positive X)

 float factor = 1- (1 / (1+ x));  //for x=0 factor will be close to 1 for large x factor will be close to 0
 o.vertColor.rgb= v.color.rgb * (factor*brightness);  //this COULD lead to color with a value>1.0,  might want to check and clamp them... not sure if necessary tho.
avatar image SharpeDesigns Glurth · Dec 20, 2016 at 06:55 PM 0
Share

Thanks for the response!

I had the brightness mapped to just the alpha channel since it's only a single float value, but it works across rgb too. And sorry, "following pass" probably wasn't the right language, I think I meant next iteration. Pretty new to shaders, so I'm not sure if "previous frame" is correct either, but that's the concept I'm going for.

The big mystery I'm trying to crack is finding a way to have the distance manipulation add on to the previously calculated values. In my head, it seems like it should be fairly easy to have the vertex colors only get brighter, never darker. But I think that would require a way of somehow saving the changed vertex values.

avatar image Glurth SharpeDesigns · Dec 21, 2016 at 05:10 AM 0
Share

I don't think that going to be possible with a shader alone, but hopefully someone will post otherwise. Though perhaps rather than modify the verticies, you could modify the texture used by the shader at those UV points: no sure if that would be any more efficient though.

avatar image SharpeDesigns · Jan 04, 2017 at 02:20 AM 0
Share

Still wrestling with this challenge and after doing some more research, I'm curious if this might be possible using a grab pass? Tried switching to vertex & fragment shader and adding a grab pass but no luck. Here's what I'm currently playing with if anyone's curious:

 Shader "Custom/Lightup-New"
 {
     Properties
     {
         _MainTex("Texture", 2D) = "white" {}
         _TexStrength("Texture Strength", Range(0, 1)) = 1
         _UnlitColor ("UnlitColor", Color) = (0,0,0,1)
         _LitColor("LitColor", Color) = (1,1,1,1)
         _BaseRadius("BaseRadius", Float) = 20
         _LightRadius("LightRadius", Float) = 40
         _Brightness ("Brightness", Float) = 1
     }
 
     SubShader
     {
 
         GrabPass{ "_GrabTexture" }
 
         Pass
         {
             CGPROGRAM
             #pragma vertex vert
             #pragma fragment frag
             #include "UnityCG.cginc"
 
             sampler2D _GrabTexture;
             float4 _ObjectPosition;
             sampler2D _MainTex;
             float _TexStrength;
             float4 _UnlitColor;
             float4 _LitColor;
             float _BaseRadius;
             float _LightRadius;
             float _Brightness;
 
             struct vertInput {
                 float4 pos : POSITION;
                 float4 color : COLOR;
                 float2 texcoord : TEXCOORD0;
             };
 
             struct vertOutput {
                 float4 pos : SV_POSITION;
                 float4 color : COLOR;
                 float2 texcoord : TEXCOORD0;
                 float4 uvgrab : TEXCOORD1;
             };
 
             vertOutput vert(vertInput input) {
                 vertOutput o;
                 UNITY_INITIALIZE_OUTPUT(vertOutput, o);
 
                 o.pos = mul(UNITY_MATRIX_MVP, input.pos);
                 o.texcoord = input.texcoord;
 
                 // Distance calculations
                 float distanceToObject = distance(mul(unity_ObjectToWorld, input.pos).xyz, _ObjectPosition.xyz);
                 float normalizedDistance = clamp (1.0 - (1.0 / (_BaseRadius-_LightRadius) * (_BaseRadius - distanceToObject)), 0, 1);
                 input.color.a = normalizedDistance * _Brightness;
                 o.color.a = input.color.a;
 
                 return o;
             }
 
             half4 frag(vertOutput output) : COLOR {
                 half4 mainTexture = tex2D(_MainTex, output.texcoord);
                 fixed4 grabTexture = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(output.uvgrab));
 
                 half4 unlitBlended = lerp(_UnlitColor, (_UnlitColor*mainTexture), _TexStrength);
                 half4 litBlended = lerp(_LitColor, (_LitColor*mainTexture), _TexStrength);
 
                 return grabTexture + lerp(unlitBlended, litBlended, output.color.a);
             }
 
             ENDCG
         }
     }
 }

Anybody have some insight into using a grab pass for this purpose? Get the impression I'm probably not using it correctly at all...

avatar image SharpeDesigns · Feb 08, 2017 at 03:53 AM 0
Share

Is this something that might be possible with a compute shader? Searched high and low for a way to do this via standard shaders, but it looks like they just aren't capable of this functionality. Still a novice in this field, so it'd be great to know if this is even possible before jumping in and taking the time to experiment with compute shaders.

2 Replies

· Add your reply
  • Sort: 
avatar image

Answer by tanoshimi · Feb 08, 2017 at 06:53 AM

Shaders do not persist values. However, there are plenty of examples of dynamic painting textures on meshes (which is what it looks like you're trying to do), normally assigning vertex colours to the mesh which are then passed to the shader.

Try this, for example: https://www.reddit.com/r/Unity3D/comments/33bz80/here_is_a_way_to_do_dynamic_texture_painting_in/

Comment

People who like this

0 Show 1 · 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 SharpeDesigns · Feb 08, 2017 at 05:55 PM 0
Share

Thanks for the reply! Do you think this is something that might be possible with compute shaders?

The current method we have implemented is using a similar method of cycling through mesh vertices and changing their colors before passing that information to the shader, but we're finding it's becoming an extreme CPU bottleneck. We also need to find a method that allows the meshes to be marked as batching static, so we won't be able to change the mesh colors directly.

avatar image

Answer by Tunity · Mar 03, 2018 at 04:31 PM

https://github.com/unity3d-jp/WaveShooter/blob/master/Assets/Scripts/WaterInputDrawer.cs

This sample uses Rendertexture to keep the variables.

Comment

People who like this

0 Show 0 · 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

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

6 People are following this question.

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

Related Questions

Adding a clip() to the default shader? 0 Answers

Is it possible to avoid writing to certain g-buffers? 1 Answer

How to achive the same look? Which shaders to use? 2 Answers

How to make shader that uses vertex colors to colorize mesh but accepts shadows? 0 Answers

The Best Way To Make Stylised Grass in Unity? 0 Answers


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