Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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 /
avatar image
1
Question by Matt Woods · Jan 31, 2012 at 04:40 PM · shadertextureparticlecgmatrix

Shader programming question for Cg expert : Scaling textures

Hi folks,

This is a follow up to my question here: http://answers.unity3d.com/questions/162769/preventing-quotzombie-fishquot-a-question-about-st.html

I have been learning a little about shader programming since I asked that question, and now I'm wondering if its possible to solve this in Cg with a custom particle shader. It feels like it is, but I am having a hard time finding examples.

What I would like to do, is scale my texture vertically by negative 1 when my particle is rotated between 90º and 270º.
It seems like I could do the scaling by muliplying my texture transformation matrix: (UNITY_MATRIX_TEXTURE0) by this matrix: ((1,0,0,0),(0,-1,0,0),(0,0,1,0),(0,0,0,1)). I would need to do this, only if my particle is rotated which I believe I can somehow ascertain from the projection transform matrix (UNITY_MATRIX_MVP).

Thats about as far as I got before I hit a wall though. I can't find many examples out there, and my grasp of Cg and matrix math is very shaky. Does someone more knowledgable know if A: this is possible. B: can you give me some code samples or pointers.

Thanks much,

-Matt

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

5 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Matt Woods · Feb 03, 2012 at 03:19 PM

The following shader is the result of Owen's help with shader code, and Jesse's clever idea of using vertex color information to tell the particles to right themselves. It solves my original question, so I'm going to mark this answered. Unfortunately, I also needed the particles to be vertex lit, and we haven't been able to get that to work with the flipped texture. This one, the particles will take their color from the primary light, but thats as close as I've been able to come to get the lighting working.

 Shader "FishParticles4" {
 Properties {
     _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
     _MainTex ("Particle Texture", 2D) = "white" {}
     _EmisTex ("Emmision Texture", 2D) = "white" {}
 }
 
 CGINCLUDE
 
 #include "UnityCG.cginc"
 #include "AutoLight.cginc"
 #include "Lighting.cginc"
 
 
 uniform sampler2D _MainTex;
 uniform sampler2D _EmisTex;
 
 ENDCG
 
 SubShader
 {
     Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "LightMode" = "ForwardBase"}
     
     Blend SrcAlpha OneMinusSrcAlpha
     AlphaTest Greater .01
     ColorMask RGB
     Cull Off Lighting On ZWrite On
 
     Pass
     {
        Lighting On
 
 
        CGPROGRAM 
 
        #pragma vertex vert
        #pragma fragment frag
        #pragma multi_compile_fwdbase
        #pragma multi_compile_particles
 
         struct appdata_t {
                 float4 vertex : POSITION;
                 fixed4 color : COLOR;
                 float2 texcoord : TEXCOORD0;
                 float3 normal : NORMAL;
             };
 
        struct VSOut
        {
          float4 pos     : SV_POSITION;
          fixed4 color : COLOR;
          float2 uv       : TEXCOORD1;
          LIGHTING_COORDS(3,4)
        };
 
        VSOut vert(appdata_t v)
        {
          VSOut o;
          o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
          o.uv = v.texcoord.xy;
          if(v.color.b>0.5) o.uv.y*=-1;
          
          float3 ldir = normalize( ObjSpaceLightDir( v.vertex ) );
          float diffuse = dot( v.normal, ldir );
          
          o.color = 1 * unity_LightColor[0];//1;
 
          TRANSFER_VERTEX_TO_FRAGMENT(o);
 
          return o;
        }
 
        float4 frag(VSOut i) : COLOR
        { 
          return i.color*tex2D(_MainTex, i.uv)+tex2D(_EmisTex, i.uv);
        }
 
        ENDCG
     }
 } 
 FallBack "Diffuse"
 }

Use this shader with the following javascript to change the particle color:

 function LateUpdate () {
 
 var particles = particleEmitter.particles;
 
 for (var i = 0; i < particles.Length; i++) {
     var m : Matrix4x4 = Camera.main.worldToCameraMatrix;
     var v : Vector3 = m.MultiplyVector(particles[i].velocity);
     if (v.x<=0){particles[i].color = Color.red;} else{particles[i].color = Color.blue;}
 
     particleEmitter.particles = particles;
 }
Comment
Add comment · 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
2

Answer by Jessy · Jan 31, 2012 at 05:09 PM

It's not possible, because the MVP is for an entire object (the particle system in this case). The mesh data for the system is inaccessible to us, so you need to write your own particle system if some number of Unity's can't get you what you need.

Comment
Add comment · Show 5 · 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 Matt Woods · Jan 31, 2012 at 05:51 PM 0
Share

Hmmm... Thanks for the tip. It felt possible. I thought using the $$anonymous$$VP would give the transform of the particle, not the particle system. Would using a javascript to loop through all the particles and check their Particle.rotation then set the custom shader's fliping matrix with $$anonymous$$aterial.Set$$anonymous$$atrix work? Or would that not work, because the material is attached to the renderer, not to the individual particle, thus using Set$$anonymous$$atrix external to the shader would effect all particles rather than one at a time.

avatar image Jessy · Jan 31, 2012 at 06:20 PM 0
Share

The latter sums it up. A particle system is sent to the GPU as a single mesh (and if it's batched, even more particle systems may be included in the mesh), because that's what will run on today's hardware, not because it's easy to deal with. I believe the only way you may be able to do this is to set the color of the particle based on whatever you want, and then use the vertex colors to alter UV mapping.

avatar image Matt Woods · Jan 31, 2012 at 06:31 PM 0
Share

Hah! Tricky. I like that idea. I'm not using the particle's color property, just the texture, so if I modify the Particle.color, I can access that within the shader? Let me play around with that. I may be back with more questions.

avatar image Jessy · Jan 31, 2012 at 06:53 PM 0
Share

Particle.color sets the vertex color for every vert of the particle.

avatar image Matt Woods · Feb 01, 2012 at 04:25 PM 0
Share

Ok, progress. Testing the particle rotation with "Particle.rotation" doesn't work, because apparently Strectched particles don't effect the Particle.rotation value. I was able to test the particle velocity however, and transform it into camera space. Using this script:

function LateUpdate () {

var particles = particleEmitter.particles;

 for (var i = 0; i < particles.Length; i++) {
 var m : $$anonymous$$atrix4x4 = Camera.main.worldToCamera$$anonymous$$atrix;
 var v : Vector3 = m.$$anonymous$$ultiplyVector(particles[i].velocity);

if (v.x<=0){particles[i].color = Color.red;} else{particles[i].color = Color.blue;}

 particleEmitter.particles = particles;

}

This does a pretty good job of making the fish blue when heading right, and red when heading left. Unfortunately, I'm still stuck on the CG shader code. $$anonymous$$ost of the examples I can find are based on surface shaders and don't seem to work correctly with particles (they turn pink). Could someone help me with a simple conditional statement that will flip the texture based on color that will work with particles?

The following is my shader for biolu$$anonymous$$escent particle fish which I have been trying to modify. ($$anonymous$$y other fish still use the standard shader) I'm not sure where to put the CGPROGRA$$anonymous$$.

Shader "ParticleLitUnlit" {

Properties { _$$anonymous$$ainTex ("Particle Texture", 2D) = "white" {} _EmisTex ("Emissive Texture", 2D) = "white" {} _Color ("$$anonymous$$ain Color", Color) = (1,1,1,1) }

SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } Tags { "Light$$anonymous$$ode" = "Vertex" } Cull Off Lighting On

 Color$$anonymous$$aterial AmbientAndDiffuse
 ZWrite On
 Color$$anonymous$$ask RGB
 Blend SrcAlpha One$$anonymous$$inusSrcAlpha
 AlphaTest Greater .001
 
 Pass { 

/*CGPROGRA$$anonymous$$ #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc"

 //if(UNITY_$$anonymous$$ATRIX_$$anonymous$$VP._m00>0.05) // && UNITY_$$anonymous$$ATRIX_$$anonymous$$VP._m00<1.01)
         o.texcoord.y*=-1;

ENDCG*/

     SetTexture [_$$anonymous$$ainTex] { combine primary * texture }
     //SetTexture [_EmisTex] { combine previous + texture }
 }

} }

Thanks for the help!

avatar image
1

Answer by Owen-Reynolds · Feb 01, 2012 at 05:57 PM

The comments are getting way too long, but this is a reply to the OPs giant comment.

The shader you've got uses the old "switches" method, which Unity calls shaderLab. You can set lots of values, such as "blend with the previous texture, based on one minus its alpha", but can't actually write code. For anything odd ("blue flips texture" counts as odd) you have to get the "write your code here" version.

I assume you started with something dragged in from builtin_shaders (Didn't see your's there. Is it mobile? If you got it some where else builtin_shaders is downloadable from Unity.) If you drag in something like Particle/AlphaBlend shader, you'll see spots to write code:

 v2f vert (appdata_t v) {
   v2f o;
   o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
       [.. deleted soft particles ..]
   o.color = v.color;
   o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
   return o;
 }

This runs for each corner of the billboard. Since you're using the color as a marker, and not for color, don't copy it -- just set to white. This should be self-explainitory:

       [.. deleted soft particles ..]
   o.color = 1;    // sets tintcolor to opaque white ("do nothing")
   o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
   //NOTE: the blue value is either 0 (if we are red) or 1 (if we are blue)
   if(v.color.b>0.5) o.texcoord.y*=-1;
   return o;

There are some improvements. For example the pixel shader (just below -- "frag") multiples everything by o.color (it calls it i.color.) You could just delete that part and not set o.color. TRANSFORM_TEX applies the tiling and offset. You probably will never have any, for fish, so could delete that.

Comment
Add comment · Show 2 · 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 Matt Woods · Feb 01, 2012 at 06:22 PM 0
Share

Not doing mobile. I started with the Particle VertexLit Blended shader, and modified it to have an emissive property. Taking a look at the Particle/AlphaBlend shader now. Its a little intimidating. I'll see if I can decipher it. Thanks for the tips.

avatar image Matt Woods · Feb 01, 2012 at 06:30 PM 0
Share

Btw, I do need the particles to be effected by lighting. I think thats why I started with vertexlit blended. Particle/AlphaBlend doesn't seem to be effected by lights, and I have no idea how to add them back in.

avatar image
0

Answer by Owen-Reynolds · Jan 31, 2012 at 06:49 PM

To just flip upside down, put o.texcoord.y*=-1; in the vertex shader (just after the line that computes o.texcoord.) To verify this, try using *=-2. That will double the vertical fish, as well as flipping them.

Turns out the texture matrix isn't used that much -- if you rotate the model (in this case, the plane billboard,) the tex-coords go with it anyway. The texMatrix is for when you have a stationary billboard and want to spin the texture (which is rare.)

But, a quick test with the MV and MVP matrices has me baffled. We really want the MV matrix -- model rotation with respect to the camera. The P stands for projection, and is just there to adjust size for depth. The shader can't "see" the motion, but the billboard is obviously rotated, with a "wrong way" rotated 180 degrees.

The thing is, testing shows the rotation numbers in MV and MVP don't change in any useful way (is there a Unity shader debugger?) Rotation about just z, for example, should change slots 00, 02, 20 and 22. The test (in the vert shader):

 if(UNITY_MATRIX_MVP._m00>0.05) // && UNITY_MATRIX_MVP._m00<1.01)
   o.texcoord.y=0.5; // in-your-face test value

This changes as you scroll in and out (for depth,) but doesn't seem to care about rotated particles. If you leave out the P, 00 is always 1 (the identity.) It appears as if the secret particle code is adjusting the billboard verts itself, and the shader has no information about the spin.

Adding Update code to the emitter can set shader values for everyone, but I don't think for each fish. Aren't there fish that look about the same upside down?

Comment
Add comment · 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 Matt Woods · Jan 31, 2012 at 08:06 PM 0
Share

Thanks for the testing and code example Owen. I think Jessy was on the right track of sending the particle orientation to the shader using Particle.color. I'm about to leave for the day, but I'll be doing some more testing tomorrow, and let people know my results.

avatar image
0

Answer by Matt Woods · Feb 01, 2012 at 10:26 PM

Ok, the texture flipping is working great. No more upside down fish! I'm now trying to get my vertex lighting, and emissive texture back into my particles. I've tried turning lighting tags on, but that seems to have no effect. I tried getting the vertex color, but that doesn't seem to incorporate the lighting like "primary" did in my old shader. I tried making a separate pass using the previous syntax, but that seems to draw one over the other without combining. I tried enabling #pragma surface surf Lambert but the particle renderer doesn't seem to like that. Here is my current code. Any tips for adding vertex lighting, and incorporating my emissive texture?

Thanks for both of your help.

-Matt

Shader "FishParticles" { Properties { _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5) _MainTex ("Particle Texture", 2D) = "white" {} _EmisTex ("Emmision Texture", 2D) = "white" {} }

Category { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } Blend SrcAlpha OneMinusSrcAlpha AlphaTest Greater .01 ColorMask RGB Cull Off Lighting On ZWrite On Fog { Color (0,0,0,0) } BindChannels { Bind "Color", color Bind "Vertex", vertex Bind "TexCoord", texcoord }

 SubShader {
 
     Pass {
     
         CGPROGRAM
         #pragma vertex vert
             //        #pragma surface surf Lambert
         #pragma fragment frag
         #pragma fragmentoption ARB_precision_hint_fastest
         #pragma multi_compile_particles
         
         #include "UnityCG.cginc"

         sampler2D _MainTex;
         sampler2D _EmisTex;
         fixed4 _TintColor;
         
         struct appdata_t {
             float4 vertex : POSITION;
             fixed4 color : COLOR;
             float2 texcoord : TEXCOORD0;
             float2 texcoord1 : TEXCOORD1;
         };

         struct v2f {
             float4 vertex : POSITION;
             fixed4 color : COLOR;
             float2 texcoord : TEXCOORD0;
             float2 texcoord1 : TEXCOORD1;
         };
         
         float4 _MainTex_ST;

         v2f vert (appdata_t v)
         {
             v2f o;
             o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
             o.color = 1;//v.color;
             o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
             o.texcoord1 = TRANSFORM_TEX(v.texcoord,_MainTex);
             if(v.color.b>0.5) o.texcoord.y*=-1;
             if(v.color.b>0.5) o.texcoord1.y*=-1;
             return o;
         }
         
         fixed4 frag (v2f i) : COLOR
         {
             
             return i.color* tex2D(_MainTex, i.texcoord);
         }
         ENDCG 
         
     }
     /*Pass { 

     SetTexture [_MainTex] { combine primary * texture }
     SetTexture [_EmisTex] { combine previous + texture }
 }*/
 }     

} }

Comment
Add comment · Show 2 · 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 Owen-Reynolds · Feb 02, 2012 at 07:35 PM 0
Share

A surface shader takes: inout appdata_full v in the vert shader and you specify it with #pragma surface surf Lambert vertex:vert, where vert is the name of the vertex shader. I got this surface shader working, but it completely ignores point lights and the light intensity. I couldn't get the vertex part working (could find the appdatafull docs,) so it flips per/pixel, which is slower. At this point, making your own fish-mover is seemer easier:

 Shader "Particles/fish" {
   Properties {
 _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
 _$$anonymous$$ainTex ("Particle Texture", 2D) = "white" {}
 _InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
 }

 Category {
 Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
 Blend SrcAlpha One$$anonymous$$inusSrcAlpha
 AlphaTest Greater .01
 Color$$anonymous$$ask RGB
 Cull Off Lighting On ZWrite Off Fog { Color (0,0,0,0) }
 BindChannels {
     Bind "Color", color
     Bind "Vertex", vertex
     Bind "TexCoord", texcoord
 }   

 SubShader {
   Tags { "RenderType" = "Opaque" }
   CGPROGRA$$anonymous$$
   #pragma surface surf Lambert alpha     
   sampler2D _$$anonymous$$ainTex;
   struct Input {
       float2 uv_$$anonymous$$ainTex;
       float4 color : COLOR;
   };
  
   void surf (Input IN, inout SurfaceOutput o) {
      if(IN.color.r<0.5) IN.uv_$$anonymous$$ainTex*=-1;
       half4 cc = tex2D (_$$anonymous$$ainTex, IN.uv_$$anonymous$$ainTex);
       o.Albedo = cc.rgb;
       o.Alpha = cc.a * IN.color.a;  
   }
   ENDCG
 } 
 //Fallback "Diffuse" // wrong   }

 }
avatar image Matt Woods · Feb 03, 2012 at 02:47 PM 0
Share

Hi Owen, I tried your shader, but couldn't get it working. Does it only work with directional lights? The big reason I need the lighting is I have spotlights on my submarine. I haven't been able to get any surface shaders to work well with particles. I had been trying the vertex/frag shader route based on these two links: http://unity3d.com/support/documentation/Components/SL-Attenuation.html

http://answers.unity3d.com/questions/180298/how-do-i-sample-a-shadowmap-in-a-custom-shader.html

I'll post my resulting shader in a new answer, but I agree I'm about ready to give up on this. I've learned a lot more about shaders though. Thank you for your help. If you're ever come to western $$anonymous$$assachusetts, I'll buy you a beer.

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

6 People are following this question.

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

Related Questions

uv not being passed through from vertex to surface shader 1 Answer

UnityObjectToClipPos is inverted? 0 Answers

Projected Texture Shader Issues 1 Answer

shader cg blending two textures 1 Answer

Projector + custom fragment shader = endless texture draw 2 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