I've programmed a 2D Water Effect with Springs similar to this one. Now I want to implement it in a Vertex Shader (in Unity). But for Wave Propagation I need to know the left and right Neighbors (to calculate the affecting Force) of the current Vertex and somehow save the resulting Force for the next Iteration. I have no Idea how to do that.
You should create a texture representation of the offsets you need for vertex manipulation and then use tex2lod() in your vertex shader - these are supported in shader model 3 and up.
You then use a fragment shader to generate or update the texture.
Your vertex shader could look something like this:
sampler2D _OffsetMap;
// vertex shader
vert_data vert (appdata_base v) {
vert_data v_out;
float4 vertexPos = v.vertex;
vertexPos += tex2Dlod (_OffsetMap, float4(vertexPos.xz, 0, 0));
v_out.position = UnityObjectToClipPos (vertexPos);
return v_out;
}
You can ofcourse also use the same fetch to manipulate vertex normals.
Related
I made a shader to make 3d assets appear flat and sprite-like, but am running into z-fighting on my vert shader. Has anyone done something similar?
I am working on my making a new shader that flattens then slightly pixelates, but am running into z-fighting. It looks decent enough on the pixelization and the flatten works but if you look at this example you can see that parts of the arm are missing.
It becomes even more obvious when animated as simple static capsules will have a flickering effect..
I am very happy with the fragmentation shader pixelizing things, but the vertrex shader has z-fighting I'm not sure how to address.
The vert shader I created is:
Varyings vert(Attributes IN) {
Varyings OUT = (Varyings)0;
float4 origin = mul (unity_ObjectToWorld, float4(0,0,0.01,1));
OUT.vertex = mul (unity_ObjectToWorld, IN.vertex);
OUT.vertex.z = origin.z;
OUT.vertex = mul (UNITY_MATRIX_VP, OUT.vertex);
OUT.uv = IN.uv;
OUT.color = IN.color;
return OUT;
}
Is there a better way to do the flattening with respect to the world?
I have built a full shader using the above snippet and a fragmentation shader which does pixelization. My expectation was that forward most vertices would remain foremost even after flattening.
I am following this tutorial on baking the shader into a texture Map here It works great. I just have some problem applying it on a standard shader.
so this is an unwrap shader they made using a vertex/fragment(I think these are responsible to render the vertex into uv space):
v2f vert (appdata v)
{
v2f o;
v.vertex = float4(v.uv.xy, 0.0, 1.0);
o.vertex = mul(UNITY_MATRIX_P, v.vertex);
//o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f IN) : SV_Target
{
//here is where you would put the shader code you want to bake
//for now I will just do a noise
float f = fbm(IN.uv + fbm(5*IN.uv, 4), 4);
fixed4 color = fixed4(f,f,1,1);
return color;
}
I wanted to do that but on a surface shader. Can you guys help me?
You have two options. If its not too late already...
Option 1: Alter the generated code from your surface shader
Option 2: Use vertex modifier and counteract UnityObjectToClipPos(v.vertex);
Unity surface shaders are also just Vertex and Fragmentshaders like your snippet up above. It is a long collection of different passes and predefined functions to add all kinds of effects like shadows, fog etc.
If you create a shader as a surface shader you tell unity which predefined functions to use with pragmas like "surface surf Standard fullforwardshadows"
You can always look at the generated code if you click on you compiled shader there is a button. There you see a long shader with vertex and fragment portions. Its a little cluttered with #ifelse and the code that is run on your machine is only a small portion in the end. It is possible to declutter it by hand and only change the specific parts that you want to alter i.e. add a custom vertex shader.
Since this is time consuming and error prone unity has a lot of customisability of the standard shaders.
Option 2:
One of these is the vertex modifier pragma with vertex:vert you can assign a custom vertex function to be called in the vertex shader to modify the vertex position. (See Normal Extrusion in: here) Unfortunately unity wraps a
UnityObjectToClipPos(v.vertex); directly after your vertex modifier function. So if you do a transformation from object-space to uv-space unity then automatically converts the uv-coordinates to clip-space as if it were object-space coordinates resulting in nonsense. What you can do is to counteract this with mul(transpose(UNITY_MATRIX_IT_MV), v.vertex);
The resulting multiplication then is: PVM*t(t(inv(MV))) = P
That way you cheat the vertex modifier to act as an override. Keep in mind thought that position is also used for other operations shadows etc. If you want to have more control and skip this unecessary double multiplication you can do
Option 2:
You can always go into the generated code from your surface shader and alter the vertex functions. You can i.e. remove the call to UnityObjectToClipPos(v.vertex); manually.
Note: One problem i ran into a lot with UV-Space manipulation is that the clipspace depends on your graphics api used. Wether it is OpenGL like or Directx like you might need to set your z coords to -1.0 or 0.0 in float4(v.uv.xy, 0.0, 1.0);. This also might change depending on your build target.
Edit:
Here is an example vertex modifier for a surface shader:
#pragma surface surf Standard fullforwardshadows vertex:vert
void vert (inout appdata_full v) {
v.vertex = float4(v.texcoord.xy, 0.0, 1.0);
//or float4(v.texcoord.xy, -1.0, 1.0);
v.vertex = mul(transpose(UNITY_MATRIX_IT_MV), v.vertex);
}
I wrote a surface shader in Unity with the default render pipeline to use Triplanar texturing on a mesh with no UVs, this worked fine, with the following code:
Shader "Custom/TerrainShader"
{
// These properties can be modified from the material inspector.
Properties{
_MainTex("Ground Texture", 2D) = "white" {}
_WallTex("Wall Texture", 2D) = "white" {}
_TexScale("Texture Scale", Float) = 1
}
// You can have multiple subshaders with different levels of complexity. Unity will pick the first one
// that works on whatever machine is running the game.
SubShader{
Tags { "RenderType" = "Opaque" } // None of our terrain is going to be transparent so Opaque it is.
LOD 200 // We only need diffuse for now so 200 is fine. (higher includes bumped, specular, etc)
CGPROGRAM
#pragma surface surf Standard fullforwardshadows // Use Unity's standard lighting model
#pragma target 3.0 // Lower target = fewer features but more compatibility.
// Declare our variables (above properties must be declared here)
sampler2D _MainTex;
sampler2D _WallTex;
float _TexScale;
// Say what information we want from our geometry.
struct Input {
float3 worldPos;
float3 worldNormal;
};
// This function is run for every pixel on screen.
void surf(Input IN, inout SurfaceOutputStandard o) {
float3 scaledWorldPos = IN.worldPos / _TexScale; // Get a the world position modified by scale.
float3 pWeight = abs(IN.worldNormal); // Get the current normal, using abs function to ignore negative numbers.
pWeight /= pWeight.x + pWeight.y + pWeight.z; // Ensure pWeight isn't greater than 1.
// Get the texture projection on each axes and "weight" it by multiplying it by the pWeight.
float3 xP = tex2D(_WallTex, scaledWorldPos.yz) * pWeight.x;
float3 yP = tex2D(_MainTex, scaledWorldPos.xz) * pWeight.y;
float3 zP = tex2D(_WallTex, scaledWorldPos.xy) * pWeight.z;
// Return the sum of all of the projections.
o.Albedo = xP + yP + zP;
}
ENDCG
}
FallBack "Diffuse"
}
However, when switching to the new RP (HD or LW) the material using it becomes pink. I know it's because Unity no longer supports surface shaders, so my question is, how do you achieve triplanar texturing with the new RP?
There is support for triplanar texturing through the shader graph. Just hit space inside the graph editor and search for "triplanar" and it will show up.
HDRP shaders use deferred rendering, so its shaders look fundamentally different. If you want to learn, i suggest you create a basic shader in the shader graph and then right click on the master node and select "copy shader". Then, you can paste the shader code into a text editor and try to reverse engineer it. The SRP GitHub is also a good reference:
https://github.com/Unity-Technologies/Graphics/tree/master/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary
https://github.com/Unity-Technologies/Graphics/tree/master/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass
For LWRP, there is this template shader which i've found quite useful:
https://gist.github.com/phi-lira/225cd7c5e8545be602dca4eb5ed111ba
I have a gameObject1 which transmit it's position into shader of some screenGameObject. ScreenGameObject has position(0,0,0), rotation(0,0,0), scale(1,1,1).
In the shader I need to make a texture follow this gameObject1.
In general, I think, need to convert world position of gameObject1 to uv - space of ScreenGameObject.
Here I have found some task, which is v close to my: link
In the vertex shader I wrote :
o.uvOffset = mul(unity_WorldToObject, _FrameTexPos).xy;
In frag function I have:
return tex2D(_AimTex, i.uvOffset).rrrr;
As result: the _AimTex texture moves wrongly at all:
_FrameTexPos.x makes texture move along OY, _FrameTexPos.y makes it move along local OX
I guess this:
mul(unity_WorldToObject, _FrameTexPos).xy;
Do not convert _FrameTexPos rightly (from world space, to object's uv space).
I'm working on tattoo simulator program, i need to know if there's a way for the decal (tattoo) to wrap arond the target mesh, like having a tattoo that goes from one side to the other side of lets say leg, or event behind it.
Not at runtime, using a projected decal, no.
What you need here instead is a procedural tattoo map. Think of it as another texture, like a lightmap. You may need a custom shader, but it could possibly be done with the secondary albedo channel of the standard shader.
The tricky part is writing to that texture. I'll outline the basic algorithm, but leave it up to you to implement:
The first thing you need to be able to do is unwrap the mesh's triangles in code. You need to identify which edges are contiguous on the UV map, and which are separate. Next, you need a way to identify the tattoo and the initial transform. First, you'll want to define an origin on the tattoo source texture that it will rotate around. Then you'll want to define a structure that references the source texture, and the UV position (Vector2) / rotation (float) / scale (float) to apply it to in the destination texture.
Once you have the tattoos stored in that format, then you can start building the tattoo mask texture for the skin. If your skin uvs have a consistent pixel density, this is a lot easier because you can work primarily in uv-space, but if not, you'll need to re-project to get the scale for each tri. But, basically, you start with the body triangle that contains the origin, and draw onto that triangle normally. From there, you know where each vertex and edge of that triangle lies on the tattoo source texture. So, loop through each neighboring triangle (I recommend a breadth-first recursive method) and continue it from the edge you already know. If all three verts fall outside the source texture's rect, you can stop there. Otherwise, continue with the next triangle's neighbors. Make sure you're using the 3D mesh when calculating neighbors so you don't get stuck at seams.
That algorithm is going to have an edge case you'll need to deal with for when the tattoo wraps all the way around and overlaps itself, but there are a couple different ways you can deal with that.
Once you've written all tattoos to the tattoo texture, just apply it to the skin material and voila! Not only will this move all the calculations out of real-time rendering, but it will let you fully control how your tattoos can be applied.
You can use a decal projector using Unity's official preview tool Render Pipelines - High Definition.
Here's how I used it to project a "tatoo" onto a bucket. You can apply it to your model of course.
(Child the decal projector so that the tatoo follows the model)
The best way to import Render Pipelines - High Definition package is to use Unity Hub to create a new project, choosing it as a template. If it's an existing project, this official blog might help you.
Once you succefully set up the package, follow this tutorial and you'll be able to project tatoos onto your models anywhere you want.
I've done something similar with a custom shader. I think it would do what you want. Mine is dynamically rendering flags based on rank and type of a unit for an iPad game prototype. Exactly how you'll do it depends a bit on how you have things setup in your project, but here's what mine looks like - first image is the wireframe showing the mesh and second is with the shaders turned on and shows them adding the colors and emblem based on rank and unit. I've just included the shader for the top flag since that has the unit emblem added added similar to how you want your tattoo to be:
Note that you can attach multiple shaders to a particular mesh.
And the emblem is just an image with transparency that is added to the shader and referenced as a texture within the shader:
You can see we also have a picture that has some shadow texture that's used as the background for the banner.
This is my first shader and was written a while ago, so I'm sure it's sub-optimal in all kinds of ways, but it should hopefully be enough to get you started (and it still works in Unity 2018.3.x, though I had to hack in some changes to get it to compile):
Shader "Custom/TroopFlagEmblemShader" {
Properties {
_BackColor ("Background Color", Color) = (0.78, 0.2, 0.2) // scarlet
_MainTex ("Background (RGBA)", 2D) = "" {}
_EmblemTex("Emblem (RGBA)", 2D) = "" {}
_Rank ( "Rank (1-9)", Float ) = 3.0
}
SubShader {
Pass {
CGPROGRAM
#pragma exclude_renderers xbox360 ps3 flash
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex: POSITION;
float4 texcoord: TEXCOORD0;
};
struct v2f {
float4 pos: SV_POSITION;
float2 uv: TEXCOORD0;
};
uniform sampler2D _MainTex;
uniform sampler2D _EmblemTex;
uniform float3 _BackColor;
uniform float _Rank;
v2f vert( appdata v )
{
v2f o;
o.pos = UnityObjectToClipPos( v.vertex );
o.uv = v.texcoord.xy;
return o;
}
float4 frag( v2f IN ) : COLOR
{
float4 outColor;
float4 backTextureColor = tex2D( _MainTex, IN.uv.xy );
float4 emblemTextureColor = tex2D( _EmblemTex, IN.uv.xy );
// not drawing the square at all above rank 5
if ( _Rank >= 6.0 )
discard;
if ( _Rank < 5 ) // 4 and below
{
outColor = float4( (emblemTextureColor.rgb * emblemTextureColor.a) +
(((1.0 - emblemTextureColor.a) * backTextureColor.rgb) * _BackColor.rgb) , 1 );
// float4(_BackColor.rgb, 1 ));
}
else if ( _Rank >= 5.0 ) // but excluded from 6 above
{
// 5 is just solid backcolor combined with background texture
outColor = float4( backTextureColor.rgb * _BackColor.rgb, 1 );
}
return outColor;
}
ENDCG
}}
}
Shaders are a bit maddening to learn how to do, but pretty fun once you get them working - like most programming :)
In my case the overlay texture was the same size/shape as the flag which makes it a bit easier. I'm thinking you'll need to add some parameters to the shader that indicate where you want the overlay to be drawn relative to the mesh and do nothing for vertexes/fragments outside your tattoo bounds, just as a first thought.