Unity - how to make material double sided - unity3d

Search for the issue gives a number of solutions, but they don't work for some reason in mine Unity3D 5.4. Like
camera inside a sphere
I do not see cull and/or sides in material in Unity editor.
In C#
rend = GetComponent<Renderer>();
mater = rend.material;
rend.setFaceCulling( "front", "ccw" );
mater.side = THREE.DoubleSide;
gives no such setFaceCulling and side property.
How to make material double sided?

You need a custom shader to enable double sided material by using Cull Off
The easiest/fastest way to test is to create a new Standard Surface Shader in the editor and open it. Add the line Cull Off below LOD 200.
Now one thing to consider is that lightning will not render correctly for the back faces. If you want that, I would recommend doing models with 2 sides.

Use or create a shader with
Cull off
Seen here in this simple 2 sided shader:
Shader "Custom/NewSurfaceShader" {
Properties {
}
SubShader {
Cull off
Pass {
ColorMaterial AmbientAndDiffuse
}
}
}

Maybe my answer for your Unity Version doesn't work, but here it is a solution for newer versions in HDRP in image below

just Creat an Unlitshader and edit it:
you should write Cull off bellow LOD 100
then drag it to a new material and set an picture for test - now drag material to an object .
lightning will render correctly !!! ( my unity is 2019.4 )
enter code here
Shader "Unlit/unlit"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Cull off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
} }}

Also, In Unity 2020.3 URP/Lit shader has a Render face option guys.

You may use a custom surface shader with Cull Off but the opposite faces will not get the light proper, because the normals are valid only for front faces, for back faces the normals are opposite to faces. If you want the back face to be treated like the front face and don't want to make a model with double sides mesh to consume double memory you can draw in 2 Passes, 1 Pass for front face and 1 for back face where you can inverse normal for every vertex in vertex shader. You can use Cull back and Cull front.
SubShader
{
//Here start first Pass, if you are using standard surface shader passes are created automated,
//else you should specify Pass { }
Tags { ... }
LOD 200
Cull Back
...
struct Input
{
...
}
...
...
//or vert & frag shaders
void surf(Input IN, inout SurfaceOutputStandard p)
{
//processing front face, culling back face
...
}
...
//Here start second pass put automated by unity
Tags {...}
LOD 200
Cull Front
#pragma vertex vert
#pragma surface ...
...
struct Input
{
...
}
...
void vert(inout appdata_full v)
{
v.normal = -v.normal;//flip
}
void surf(Input IN, inout SurfaceOutputStandard p)
{
//processing back face, culling front face
...
}
}

Related

Unity 3D HDRP - Making a hole in a gameobject by shader using stencil

Unity version 2019.1.2f1 HDRP project.
I am trying to make a hole in a finished gameobject which has a material and shader don't want to interfere with, the point being this should work with any object it is done on.
I found this approach somewhere else, but it does not seem to work for the HD Render Pipeline version.
Basically two extra gameobjects/shapes are put where the hole is to be made, one object has a preparation pass, the other makes the hole.
Example shader:
Shader "Custom/HolePrepare" {
Properties{
}
SubShader{
Tags { "RenderType" = "Opaque" "Queue" = "Geometry+1"}
ColorMask 0
ZWrite off
Stencil {
Ref 1
Comp always
Pass replace
}
CGINCLUDE
struct appdata {
float4 vertex : POSITION;
};
struct v2f {
float4 pos : SV_POSITION;
};
v2f vert(appdata v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
return o;
}
half4 frag(v2f i) : SV_Target {
return half4(1,1,0,1);
}
ENDCG
Pass {
Cull Front
ZTest Less
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass {
Cull Back
ZTest Greater
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
}
and
Shader "Custom/Hole" {
Properties{
}
SubShader{
Tags{ "Queue" = "Geometry+10" }
ColorMask RGB
ZWrite On
Stencil {
Ref 1
Comp notequal
Pass Zero
}
Pass{}
}
}
I figure these values aren't theoretically correct, because that's not how the example code was, but since it wasn't working for HDRP I started playing around and see if I got anywhere.
The Hole shader should have ColorMask RGB 0, however nothing happens except the hole object becomes invisible. This led me to believe I am not able to use the stencil buffer properly.
I got to the point where I could mark the pixels that I wanted to erase, however I am not able to erase them.
I want to be able to erase this part of the primary object(cheese) so that the background(floor in this case) is visible.
Is there any way to do this in the HDRP?
Note: I have also tried a render queue approach by script and shader in my HDRP project, without success, although the very same code worked on a standard unity project.

Prevent transparent areas being shaded by projection shader

I'm trying to make a decal shader to use with a projector in Unity. Here's what I've put together:
Shader "Custom/color_projector"
{
Properties {
_Color ("Tint Color", Color) = (1,1,1,1)
_MainTex ("Cookie", 2D) = "gray" {}
}
Subshader {
Tags {"Queue"="Transparent"}
Pass {
ZTest Less
ColorMask RGB
Blend One OneMinusSrcAlpha
Offset -1, -1
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 uvShadow : TEXCOORD0;
float4 pos : SV_POSITION;
};
float4x4 unity_Projector;
float4x4 unity_ProjectorClip;
v2f vert (float4 vertex : POSITION)
{
v2f o;
o.pos = UnityObjectToClipPos (vertex);
o.uvShadow = mul (unity_Projector, vertex);
return o;
}
sampler2D _MainTex;
fixed4 _Color;
fixed4 frag (v2f i) : SV_Target
{
fixed4 tex = tex2Dproj (_MainTex, UNITY_PROJ_COORD(i.uvShadow));
return _Color * tex.a;
}
ENDCG
}
}
}
This works well in most situations:
However, whenever it projects onto a transparent surface (or multiple surfaces) it seems to render an extra time for each surface. Here, I've broken up the divide between the grass and the paving using grass textures with transparent areas:
I've tried numerous blending and options and all of the ZTesting options. This is the best I can get it to look.
From reading around I gather this might be because the a transparent shader does not write to the depth buffer. I tried adding ZWrite On and I tried doing a pass before the main pass:
Pass {
ZWrite On
ColorMask 0
}
But neither had any effect at all.
How can this shader be modified so that it only projects the texture once on the nearest geometries?
Desired result (photoshopped):
The problem is due to how projectors work. Basically, they render all meshes within their field of view a second time, except with a different shader. In your case, this means that both the ground and the plane with the grass will be rendered twice and layered on top of each other. I think it could be possible to fix this using two steps;
First, add the following to the tags of the transparent (grass) shader:
"IgnoreProjector"="True"
Then, change the render queue of your projector from "Transparent" to "Transparent+1". This means that the ground will render first, then the grass edges, and finally the projector will project onto the ground (except appearing on top, since it is rendered last).
As for the blending, i think you want regular alpha blending:
Blend SrcAlpha OneMinusSrcAlpha
Another option if you are using deferred rendering is to use deferred decals. These are both cheaper and usually easier to use than projectors.

how to programmatically allow Unity Shader to control which object renders in front?

I've only just started learning Unity, but because I come from a background of coding in C#, I've found the standard scripting to be very quick to learn. Unfortunately, I've now come across a problem for which I believe a custom shader is required and I'm completely lost when it comes to shaders.
Scenario:
I'm using a custom distance scaling process so that really big, far away objects are moved within a reasonable floating point precision range from the player. This works great and handles scaling of the objects based on their adjusted distance so they appear to actually be really far away. The problem occurs though when two of these objects pass close to eachother in game space (this would still be millions of units apart in real scale) because they visibly collide.
Ex: https://www.youtube.com/watch?v=KFnuQg4R8NQ
Attempted Solution 1:
I've looked into flattening the objects along the player's view axis and this fixes the collision, but this affects shading and particle effects so wasn't a good option
Attempted Solution 2:
I've tried changing the RenderOrder, but because sometimes one object is inside the mesh of another (though the centre of this object is still closer to the camera) it doesn't fix the issue and particle effects are problematic again.
Attempted Solution 3:
I've tried moving the colliding objects to their own layer, spawning a new camera with a higher depth at the same position as my main camera and forcing the cameras to only see the items on their respective layers, but this caused lighting issues as some objects are lighting others and I had only a limited number of layers so this solution was quite limiting as it forced me to only have a low number of objects that could be overlapping at a time. NOTE: this solution is probably the closest I was able to come to what I need though.
Ex: https://www.youtube.com/watch?v=CyFDgimJ2-8
Attempted Solution 4:
I've tried updating the Standard shader code by downloading it from Unity's downloads page and creating my own, custom shader that allows me to modify the ZWrite and ZTest properties, but because I've no real understanding of how these work, I'm not getting anywhere.
Request:
I would greatly appreciate a Shader script code example of how I can programmatically force one object who's mesh is either colliding with or completely inside another mesh to render in front of said mesh. I'm hoping I can then take that example and apply it to all the shaders that I'm currently using (Standard, Particle Additive) to achieve the effect I'm looking for. Thanks in advance for your help.
In the gif below both objects are colliding and according to the camera position the cube is in front of the sphere but I can change their visibility with the render queue:
If that's what you want you only have to add ZWrite Off in your subshader before the CGPROGRAM starts, the following is the Standard Surface Shader including the line:
Shader "Custom/Shader" {
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
ZWrite Off
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)
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"
}
Now sorting particles, look at the shadows and how they collide and how we can change their visibility regardless of their position.
Here's the shader for particles, I'm using the Unity Built-in shader, the only thing added is Ztest Always
Shader "Particles/Alpha Blended Premultiply Custom" {
Properties {
_MainTex ("Particle Texture", 2D) = "white" {}
_InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
}
Category {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
ZTest Always
Blend SrcAlpha OneMinusSrcAlpha
ColorMask RGB
Cull Off Lighting Off ZWrite Off
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#pragma multi_compile_particles
#pragma multi_compile_fog
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed4 _TintColor;
struct appdata_t {
float4 vertex : POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f {
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
#ifdef SOFTPARTICLES_ON
float4 projPos : TEXCOORD1;
#endif
UNITY_VERTEX_OUTPUT_STEREO
};
float4 _MainTex_ST;
v2f vert (appdata_t v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.vertex = UnityObjectToClipPos(v.vertex);
#ifdef SOFTPARTICLES_ON
o.projPos = ComputeScreenPos (o.vertex);
COMPUTE_EYEDEPTH(o.projPos.z);
#endif
o.color = v.color;
o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
return o;
}
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
float _InvFade;
fixed4 frag (v2f i) : SV_Target
{
#ifdef SOFTPARTICLES_ON
float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)));
float partZ = i.projPos.z;
float fade = saturate (_InvFade * (sceneZ-partZ));
i.color.a *= fade;
#endif
return i.color * tex2D(_MainTex, i.texcoord) * i.color.a;
}
ENDCG
}
}
}
}

Inverted View in VR sphere in Unity

I've been trying to project a 360 video inside a Sphere with flipped normals for Google Cardboard VR. The Video works fine, only it is inverted horizontally, which is noticeable only when there is some text on the screen. I've included a screen shot of video and a UI.Text element in front of it to compare it with.
I've tried to invert the view of the camera through projectionMatrix but then it just ends up in blank space. Screenshot :
I can't figure out a way to make the video project the right way. Please help!
Here is a shader that displays the content correctly without inverting it, I have tested it with Unity 2018.1.1 as I am currently using it in my project:
Shader "InsideVisible" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
Cull front // ADDED BY BERNIE, TO FLIP THE SURFACES
LOD 100
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata_t {
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
half2 texcoord : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata_t v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
// ADDED BY BERNIE:
v.texcoord.x = 1 - v.texcoord.x;
o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target {
fixed4 col = tex2D(_MainTex, i.texcoord);
return col;
}
ENDCG
}
}
}
If you need more information about the shader you can view this tutorial.
Flipping the normals on a sphere is insufficient, you also need to reverse the U part of the UV coordinates (that is, change all the values U such that they are 1-U). A sphere is set up so that the outside renders text correctly from right to left. When you flip the normals "right" is still on the right from the outside...meaning that it's on the left when viewed from the inside.
You will either need to manually edit the UV coordinates yourself or get a premade inverted sphere off the asset store (IIRC there are two that are available for free).

Screen coordinates in fragment shader

In a fragment shader like the below:
Shader "ColorReplacement" {
Properties {
_MainTex ("Greyscale (R) Alpha (A)", 2D) = "white" {}
}
SubShader {
ZTest LEqual
ZWrite On
Pass {
Name "ColorReplacement"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#pragma target 3.0
#include "UnityCG.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
};
v2f vert (appdata_tan v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord.xy;
return o;
}
sampler2D _MainTex;
float4 frag(v2f i) : COLOR
{
}
ENDCG
}
}
Fallback off
}
Is there a way to know the coordinates of i.uv in the screen?
I'm totally new to shaders. The shader is applied to an object being drawn somewhere in the screen, the first pixel passed to frag possibly does not correspond to the first pixel of the screen (the viewport), is there a way to know the position of this pixel in screen coordinates?
EDIT
Yes, I want to obtain the fragment location on the screen.
Unity accepts vertex and fragment programs written in both Cg and HLSL. But I don't know how to convert this shader to HLSL.
The equivalent of gl_FragCoord in Cg is WPOS. I can run the following shader:
Shader "Custom/WindowCoordinates/Base" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#include "UnityCG.cginc"
float4 vert(appdata_base v) : POSITION {
return mul (UNITY_MATRIX_MVP, v.vertex);
}
fixed4 frag(float4 sp:WPOS) : COLOR {
return fixed4(sp.xy/_ScreenParams.xy,0.0,1.0);
}
ENDCG
}
}
}
That uses the screen position the way I want, but I'm a such noob that I can't even mix both shaders to get what I want: in my shader I'm trying to access v2f.pos, which is calculated the same way of sp in the shader above, but I get the error:
Program 'frag', variable/member "pos" has semantic "POSITION" which is not visible in this profile
If I change pos to be WPOS instead of SV_POSITION I get a similar error:
Program 'vert', variable/member "pos" has semantic "WPOS" which is not visible in this profile at line 35
Which is strange, since I'm using the same target 3.0 of the above shader.
In GLSL fragment stage there's a built-in variable gl_FragCoord which carries the fragment pixel position within the viewport. If the viewport covers the whole screen, this is all you need. If the viewport covers only a subwindow of the screen, you'll have to pass the xy offset the viewport and add it to gl_FragCoord.xy to get the screen position. Now your shader code is not written in GLSL, but apparently Cg (with Unity extensions as it seems). But it should have some correspondence this this available.
Thought I would suggest you to read some books or manuals on shaders,here is a simple solution
vec2 texelSize = 1.0 / vec2(textureSize(yourTexSampler, 0));
vec2 screenCoords = gl_FragCoord.xy * texelSize;
I don't remember how gl_FragCoord is called in Cg,so search in the docs.For the textureSize() - - substitute with width/height of the input texture.
Here is the pretty same question I asked some time ago.
Also take a look at this.
According to docs there is a helper function - ComputeScreenPos.