• 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 Rei · Nov 20, 2011 at 10:11 AM · shader

Writing a double-sided shader -- How to reverse the normal for back face??

I am trying create a paper page for books with a plane mesh;

The goal is the front page will be using a texture; and the back side will be say in color white.

I am trying to write my own, simple, double-sided diffuse shader. I started by basing on the standard Normal-Diffuse shader; but soon hits a wall -- the back side does not have the proper normal for lighting, I need to flip the normal somehow, would someone know how to do it?

Thanks a bunch!!

Here's a snippet

//..

     // Disalbe backface culling...
     Cull Off

//..

     void Surf (Input IN, inout SurfaceOutput o) 
     {
         if (dot(IN.worldNormal, IN.viewDir) > 0)
         {
             // Front side is facing the camera, render as normal
             fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
             o.Albedo = c.rgb;
             o.Alpha = c.a;
         }
         else
         {
             // back side is facing the camera
             // will just render a plain color as the back of a paper page
             fixed4 c = _Color;  
             o.Albedo = c.rgb;
             o.Alpha = c.a;

             // but the normal is facing away so the color is always dim!!
             // Looking a way to flip the normal somehow...
 
         }

     }
Comment
Add comment · 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 Rei · Nov 20, 2011 at 08:19 AM 0
Share

Have been stuck on this for a while... $$anonymous$$ost other posts I found just simply turned off culling: Cull Off but again the back face does not have proper lighting then.

Really want to know more about how to do shading for unity. lol

avatar image WillTAtl · Nov 22, 2011 at 01:36 AM 0
Share

I'm no expert on shaders, and my spider sense is tingling that your approach is fundamentally flawed somehow, but re: your specific question, to get the opposite normal just multiply the normal by -1.

avatar image Eric5h5 · Nov 22, 2011 at 02:16 AM 0
Share

Any reason why you wouldn't just model both sides of the page? Especially since you want the texturing to be different on both sides, it doesn't make any sense to try doing this with a shader.

avatar image Rei · Nov 22, 2011 at 03:28 AM 0
Share

actually there is.

I am trying to make it easiest to load any existing jpeg as a texture of the plane page. I am trying to avoid batch processing the images again just to make it fit on a cube model (although that's not hard to do)...

So I am still hoping for an answer for tweaking the shader...

avatar image Eric5h5 · Nov 22, 2011 at 03:38 AM 0
Share

Why would you use a cube model? Just model both sides of the page. Assu$$anonymous$$g your page image (hopefully not actually jpeg, that's a poor choice for text) has a white background, you can UV map a white pixel from the front side of the page onto the entire back side of the page. In the worst case scenario where that's not feasible, then make the front and back sides two different submeshes, and each gets its own material. That won't be any worse for performance than a "true" double-sided shader, plus it will be easier to accomplish.

4 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by Namey5 · Feb 01, 2016 at 06:56 AM

You could get away with it using a multi-pass shader (i.e, one pass for each side), but this may not be the best idea for performance considerations. You can't outright declare passes in surface shaders, although unity will create passes in order of placement. For correct backface normals, you can do the following:

 Shader "Custom/2 Sided" {
     Properties {
         _Color ("Color", Color) = (1,1,1,1)
         _MainTex ("Albedo (RGB)", 2D) = "white" {}
         _Glossiness ("Smoothness", Range(0,1)) = 0.5
         _Metallic ("Metallic", Range(0,1)) = 0.0
     }
     SubShader {
         Tags { "RenderType"="Opaque" }
         LOD 200
         Cull Back
 
         CGPROGRAM
             // Physically based Standard lighting model, and enable shadows on all light types
         #pragma surface surf Standard fullforwardshadows alpha
 
         #pragma target 3.0
 
         sampler2D _MainTex;
 
         struct Input {
             float2 uv_MainTex;
         };
 
         half _Glossiness;
         half _Metallic;
         fixed4 _Color;
 
         void surf (Input IN, inout SurfaceOutputStandard o) {
             // Albedo comes from a texture tinted by color
             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
             o.Albedo = c.rgb;
             // Metallic and smoothness come from slider variables
             o.Metallic = _Metallic;
             o.Smoothness = _Glossiness;
             o.Alpha = c.a;
         }
         ENDCG
 
         Cull Front
 
         CGPROGRAM
             // Physically based Standard lighting model, and enable shadows on all light types
         #pragma surface surf Standard fullforwardshadows alpha
 
         #pragma target 3.0
         #pragma vertex vert
 
         sampler2D _MainTex;
 
         struct Input {
             float2 uv_MainTex;
         };
 
         half _Glossiness;
         half _Metallic;
         fixed4 _Color;
 
         void vert (inout appdata_full v) {
             v.normal *= -1;
         }
 
         void surf (Input IN, inout SurfaceOutputStandard o) {
             // Albedo comes from a texture tinted by color
             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
             o.Albedo = c.rgb;
             // Metallic and smoothness come from slider variables
             o.Metallic = _Metallic;
             o.Smoothness = _Glossiness;
             o.Alpha = c.a;
         }
         ENDCG
     }
     FallBack "Diffuse"
 }

This is an example with the built-in standard shader (plus accurate semi-transparency). The key thing to look out for is in the second pass, which renders the backfaces. In this pass, vertex modification is used to flip the normals. Hopefully this helps anyone looking for something similar,

Namey5

Note You should render the backface first for correct blending. I was in a rush at this point in time and forgot to flip that around.

Comment
Add comment · Show 10 · 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 Cereal_Killa · Apr 03, 2016 at 08:56 AM 0
Share

How do I enable shadows on this shader? Also, this seems to break the Order in Layer of the sprite..

avatar image Namey5 Cereal_Killa · Apr 03, 2016 at 12:08 PM 0
Share

This is a semitransparent shader. Unity has no support for receiving/projecting shadows from semitransparent objects, so technically you can't. Well, I have gotten away with it in the past by using another pass for the transparency alone (you could use GrabPass), but apart from that you can't have full shading with these kinds of objects. I'm not sure what you mean by the second part of the question, however. Are you using this on a 2 dimensional sprite?

avatar image Cereal_Killa Namey5 · Apr 05, 2016 at 12:06 AM 0
Share

I have a 2D sprite (which is basically a quad) with unity's standard shader in cutout mode. Currently the sprite can receive and project shadows.

I also have backface culling turned off so the sprite can be flipped when it moved left/right.

Unfortunately the normals on the reverse side product incorrect results when the sprite is flipped.

Someone else provided this answer:

Shader "Custom/Standard Two Sided AlphaTest" { Properties { Color ("Color", Color) = (1,1,1,1) [NoScaleOffset] $$anonymous$$ainTex ("Albedo (RGB)", 2D) = "white" {} [Toggle] Use$$anonymous$$etallic$$anonymous$$ap ("Use $$anonymous$$etallic $$anonymous$$ap", Float) = 0.0 [NoScaleOffset] $$anonymous$$etallicGloss$$anonymous$$ap("$$anonymous$$etallic", 2D) = "black" {} [Gamma] _$$anonymous$$etallic ("$$anonymous$$etallic", Range(0,1)) = 0.0 _Glossiness ("Smoothness", Range(0,1)) = 0.5 _BumpScale("Scale", Float) = 1.0 [NoScaleOffset] _Bump$$anonymous$$ap("Normal $$anonymous$$ap", 2D) = "bump" {} _Cutoff("Alpha Cutoff", Range(0.01,1)) = 0.5 } SubShader { Tags { "Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout" } LOD 200 ZWrite On Cull Off

     CGPROGRA$$anonymous$$
     #pragma surface surf Standard fullforwardshadows alpha:_Cutoff nolightmap addshadow
     #pragma shader_feature _USE$$anonymous$$ETALLIC$$anonymous$$AP_ON
     #pragma target 3.0
     sampler2D _$$anonymous$$ainTex;
     sampler2D _$$anonymous$$etallicGloss$$anonymous$$ap;
     sampler2D _Bump$$anonymous$$ap;
     struct Input {
         float2 uv_$$anonymous$$ainTex;
         fixed facing : VFACE;
     };
     half _Glossiness;
     half _$$anonymous$$etallic;
     fixed4 _Color;
     half _BumpScale;
     fixed _Cutoff;
     void surf (Input IN, inout SurfaceOutputStandard o) {
         // Albedo comes from a texture tinted by color
         fixed4 c = tex2D (_$$anonymous$$ainTex, IN.uv_$$anonymous$$ainTex) * _Color;
         o.Albedo = c.rgb;
         o.Alpha = c.a;

         #ifdef _USE$$anonymous$$ETALLIC$$anonymous$$AP_ON
         fixed4 mg = tex2D(_$$anonymous$$etallicGloss$$anonymous$$ap, IN.uv_$$anonymous$$ainTex);
         o.$$anonymous$$etallic = mg.r;
         o.Smoothness = mg.a;
         #else
         o.$$anonymous$$etallic = _$$anonymous$$etallic;
         o.Smoothness = _Glossiness;
         #endif

         o.Normal = UnpackScaleNormal(tex2D(_Bump$$anonymous$$ap, IN.uv_$$anonymous$$ainTex), _BumpScale);
         o.Normal.z *= IN.facing; // flip Z based on facing
     }
     ENDCG
 }
 FallBack "Diffuse"

} But unfortunately it doesn't allow for shadows, order in layer, emission or other features of the standard shader..

Show more comments
avatar image Cereal_Killa · Apr 05, 2016 at 06:05 AM 0
Share

@Namey5 Hmm it doesn't let me reply to your comment directly. $$anonymous$$y shader knowledge is very limited and unity shader support is seriously lacking. I'm slowly picking up bits and pieces from various tutorials, forums and pages such as this one.

I've managed to modify the standard shaders to give different cel-shaded effects in the past using dot products though this is no longer an option unfortunately and as of the last few updates these changes are now going ignored by unity.

As stated I've edited the standard shader to turn off backface culling but looking through the code of the standard shader it has a whole lot of #pragma code then references another file/class for each shading type so it seem that perhaps it's these individual files that need to be edited to unpack the normal and multiply it by the direction of the sprite (either 1 or -1).

avatar image Namey5 Cereal_Killa · Apr 05, 2016 at 06:59 AM 0
Share

I was just going to say, all (most) of the normal elements of the standard shader are accessible through this, you just have to define them for yourself. $$anonymous$$g. emission. Also, $$anonymous$$e was just an example shader using default semi-transparency, meaning it will mess with rendering, shadows etc. If you wanted an alpha cutoff shader using the same 2 pass technique, I could probably write you one. It may be a tad more power draining, but I can give it a go.

avatar image Cereal_Killa Namey5 · Apr 05, 2016 at 07:26 AM 0
Share

I wouldn't expect this for free so I can pay you or you could pop it on the asset store as there seems to be some demand for it.

I've tried other sprite shading assets but they don't offer this functionality.

Or if you could point me to a tutorial on surface shaders I'd be thankful as it does seem worth learning.

avatar image Namey5 Cereal_Killa · Apr 05, 2016 at 07:25 AM 0
Share

http://officialnamey5.weebly.com/news/double-sided-cutout-shader

Couldn't post the full shader here, so I put it up for download on my site.

avatar image Cereal_Killa Namey5 · Apr 05, 2016 at 07:29 AM 0
Share

Thanks for this. I'll take a look when I get home and try to break it down and learn as much as I can from it! :D

Show more comments
avatar image
3

Answer by NoxWings · Aug 24, 2015 at 11:44 AM

I'm using this to flip the normals:

 float3 n = UnpackNormal(text2D(_Bump, IN.uv_Bump));
 o.Normal = dot(IN.viewDir, float3(0, 0, 1)) > 0 ? n : -n;

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 Cereal_Killa · Apr 03, 2016 at 10:31 AM 0
Share

Where do I add this?

avatar image NoxWings Cereal_Killa · Apr 05, 2016 at 06:53 AM 0
Share

First line gets the normal from the texture. Second line outputs the normal flipped (-n) if the normal is currently facing away from the camera.

You can plug it in a regular surface shader.

Result in a simple dissolve shader: https://m.youtube.com/watch?v=4lQflueOd9g

avatar image Cereal_Killa NoxWings · Feb 04, 2017 at 03:34 PM 0
Share

Ok so I modified the shader from namey to replace o.Normal = UnpackNormal(stuff) with your 2 lines of code but I receive this error: Shader error in 'Custom/2SidedCutout': expression left of ."viewDir" is not a struct or array at line 98 (on d3d9) The shader worked perfectly before these changes.

Full code below:

 Shader "Custom/2SidedCutout" {
     Properties {
         _Color ("Color", Color) = (1,1,1,1)
         _Glossiness ("Smoothness", Range(0,1)) = 0.5
         _$$anonymous$$etallic ("$$anonymous$$etallic", Range(0,1)) = 0.0
         _$$anonymous$$ainTex ("Albedo (RGB)", 2D) = "white" {}
         _EmitPow ("Emission Power", Float) = 1.0
         _Emission ("Emission", 2D) = "black" {}
         _Bump$$anonymous$$ap ("Normal $$anonymous$$ap", 2D) = "bump" {}
         _Spec$$anonymous$$ap ("Specularity $$anonymous$$ap (A)", 2D) = "white" {}
         _Cutoff ("Cutoff", Range (0,1)) = 0.7
         _$$anonymous$$ask ("Alpha $$anonymous$$ask (A)", 2D) = "white" {}
     }
     SubShader {
         Tags { "RenderType"="Opaque" }
         LOD 200
           
         CGPROGRA$$anonymous$$
         // Physically based Standard lighting model, and enable shadows on all light types
         #pragma surface surf Standard fullforwardshadows alphatest:_Cutoff
 
         // Use shader model 3.0 target, to get nicer looking lighting
         #pragma target 3.0
 
         sampler2D _$$anonymous$$ainTex;
         sampler2D _Emission;
         sampler2D _Bump$$anonymous$$ap;
         sampler2D _Spec$$anonymous$$ap;
         sampler2D _$$anonymous$$ask;
 
         struct Input {
             float2 uv_$$anonymous$$ainTex;
             float2 uv_Emission;
             float2 uv_Bump$$anonymous$$ap;
             float2 uv_Spec$$anonymous$$ap;
             float2 uv_$$anonymous$$ask;
         };
 
         half _EmitPow;
         half _Glossiness;
         half _$$anonymous$$etallic;
         fixed4 _Color;
 
         void surf (Input IN, inout SurfaceOutputStandard o) {
             // Albedo comes from a texture tinted by color
             fixed4 c = tex2D (_$$anonymous$$ainTex, IN.uv_$$anonymous$$ainTex) * _Color;
             o.Albedo = c.rgb;
             o.Emission = tex2D (_Emission, IN.uv_Emission) * _EmitPow;
             float3 n = UnpackNormal (tex2D (_Bump$$anonymous$$ap, IN.uv_Bump$$anonymous$$ap));
             o.Normal = dot(IN.viewDir, float3(0, 0, 1)) > 0 ? n : -n;
             // $$anonymous$$etallic and smoothness come from slider variables
             o.$$anonymous$$etallic = _$$anonymous$$etallic * tex2D (_Spec$$anonymous$$ap, IN.uv_Spec$$anonymous$$ap).a;
             o.Smoothness = _Glossiness * tex2D (_Spec$$anonymous$$ap, IN.uv_Spec$$anonymous$$ap).a;
             o.Alpha = tex2D (_$$anonymous$$ask, IN.uv_$$anonymous$$ask).a;
         }
         ENDCG
     }
     FallBack "Diffuse"
 }
 
Show more comments
avatar image
1

Answer by Owen-Reynolds · Nov 22, 2011 at 04:05 AM

I tried tossing in o.Normal=-1*IN.normal; and got yelled at for passing too many parms. What seems to work was adding an extra material for the backfaces. The front one can be a normal back-face culling diffuse shader. Have the the 2nd one cull front faces (so it draws only the back faces.) The model is drawn twice, which is about the same work as if you made an extra backplane:

 Cull Front
 ...
 // may as well flip in the vert shader, too save time:
 #pragma surface surf Lambert vertex:vert

 void vert (inout appdata_full v, out Input o) {
   o.Normal = v.Normal*-1;
 }

 // surf just draws tint color
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
0

Answer by Suyuanhan · Nov 22, 2011 at 12:20 AM

It seems that shader just for one-side normal...

So maybe you should make a very thin box that makes two opposite normal...

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 aldonaletto · Nov 22, 2011 at 01:48 AM 0
Share

@Rei, you should click the more link and change this answer to a comment in @Suyuanhan's answer - the Your answer box must be used only to answer the question, and replies or comments should be posted with the button add new comment

avatar image Rei · Nov 22, 2011 at 02:01 AM 0
Share

Thanks for the thought but ,, that's what I am trying to avoid.. if to make it to a box I will need to change the textures to cover the extra face, I am trying not to..

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

10 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

Related Questions

How to force the compilation of a shader in Unity? 5 Answers

Shader Shininess based on vertex color 0 Answers

alpha transparent shader with changeable color? 1 Answer

Transparent Camera layer rendering 0 Answers

Toon Shader Shadow Bleeding 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