Home Unity

Unity 3D shader fake uv's

Hi, I am writing a shader where I apply a displacement map on a surface. I am using a plane for the surface. The problem is that I want to turn the normals so that they face away from the surface after I apply the displacement map. So I created fake vertexes so I can calculate the normals, but the problem is that they dont have uv's, and without uv's I can't figure out what height I need to place them because the displacement map desides that. How can I fake uv's for my fake vertexes so I can use the displacement map to give them height? This is my vertex function:
VertexOutput vert (VertexInput i)
		{
			VertexOutput VOUT;
			
			// create fake vertexes
			float4 v1 = i.vertex + float4(0.05,0.0,0.0,0.0) ; // X
			float4 v2 = i.vertex + float4(0.0,0.0,0.05,0.0) ; // Z
			
			float fakeUvCoordX = i.texcoord.x + 0.05;
			float fakeUvCoordY = i.texcoord.y + 0.05;
			
			// assign the displacement map to uv coords 
			float4 disp = tex2Dlod(_Displacement, float4(i.texcoord.x + (_Time.x * _Speed), i.texcoord.y + (_Time.x * _Speed),0.0,0.0));
			float4 disp2 = tex2Dlod(_Displacement, float4(fakeUvCoordX + (_Time.x * _Speed), i.texcoord.y + (_Time.x * _Speed),0.0,0.0));
			float4 disp3 = tex2Dlod(_Displacement, float4(i.texcoord.x + (_Time.x * _Speed), fakeUvCoordY + (_Time.x * _Speed),0.0,0.0));
			
			
			// offset the main vert
			float4 newPos = i.vertex;
			newPos.y += _Scale * disp.y; 
			
			// offset fake vertexes 
			v1 += _Scale * disp2.y; 
			v2 += _Scale * disp3.y; 
			
			// calculate the new normal direction
			float3 newNor = cross(v2 - newPos, v1 - newPos);
			
			VOUT.posWorld = mul(_Object2World, newPos);
			VOUT.pos = mul(UNITY_MATRIX_MVP,newPos);
			VOUT.tex = i.texcoord;
			
			VOUT.normalWorld = normalize( mul(float4(newNor,0.0),_World2Object).xyz);
			VOUT.tangentWorld = normalize( mul(_Object2World,i.tangent).xyz);
			VOUT.binormalWorld = normalize( cross(VOUT.normalWorld, VOUT.tangentWorld) * i.tangent.w);
			
			return VOUT;
		}

Thanks in advance!

Replies

  • Lansiculus
    Okay, so I have fixed the problem by using world positions in stead of uv positions. Now you can scale the plane and it will apply the water shader based on world positions so it will just make the ocean area bigger. I made some pictures, and I am already pretty happy with the result, but I am in need for some help because I feel like the water isn't that pretty yet.

    I like this vieuw:

    2hnymg6.jpg

    But I hate this view:

    qxm9td.jpg

    Are there any tips you guys can give me? I think it has somthing to do with the reflection. Keep in mind I am not aiming to make a super realistic water shader, it just has to look good.

    This is my code:
    Shader "Custom/NoobShader_04" {
    	Properties {
    		_Color ("Color", Color) = (0.21,0.51,0.58,1)
    		_Displacement ("Displacement Map", 2D) = "white" {}
    		_Scale ("Wave Scale", float) = 0.05
    		_Speed ("Speed", float) = 1
    		_Normal ("Normal Map", 2D) = "bump" {}
    		_Bumpiness ("Bumpiness", float) = 1
    		_NormalSpeed ("NormalSpeed", float) = 1.2
    		_Cube ("Cube Map", cube) = ""{}
    		_CubeStrength ("Cube Map Strength", float) = 0.3
    		_SpecColor ("Specular Color", Color) = (0.61,0.61,0.61,1)
    		_Shininess ("Shininess", float) = 100
    	}
    	SubShader {
    	
    		Pass{
    		Tags { "LightMode" = "ForwardBase"}
    		CGPROGRAM
    		#pragma vertex vert
    		#pragma fragment frag
    		
    		float4 _Color;
    		sampler2D _Displacement;
    		sampler2D _Normal;
    		samplerCUBE _Cube;
    		float4 _SpecColor;
    		float _Shininess;
    		float _Bumpiness;
    		float _CubeStrength;
    		
    		float _Scale;
    		float _Speed;
    		float _NormalSpeed;
    		
    		float4 _LightColor0;
    			
    		struct VertexOutput
    		{
    			float4 pos : SV_POSITION;
    			float4 posWorld : TEXCOORD1;
    			float4 tex : TEXCOORD0;
    			float3 normalWorld : TEXCOORD2;
    			float3 tangentWorld : TEXCOORD3;
    			float3 binormalWorld : TEXCOORD4;
    		};
    		
    		struct VertexInput
    		{
    			float4 vertex : POSITION;
    			float3 normal : NORMAL;
    			float4 texcoord : TEXCOORD0;
    			float4 tangent : TANGENT;
    		};
    		
    		struct FragmentOutput
    		{
    			float4 color : COLOR;
    		};
    
    		VertexOutput vert (VertexInput i)
    		{
    			VertexOutput VOUT;
    			
    			// put the vert in world space
    			float4 newVert = mul(_Object2World,i.vertex);
    			
    			// create fake vertexes
    			float4 v1 = newVert + float4(0.05,0.0,0.0,0.0) ; // X
    			float4 v2 = newVert + float4(0.0,0.0,0.05,0.0) ; // Z
    			
    			// assign the displacement map to uv coords 
    			float4 disp = tex2Dlod(_Displacement, float4(newVert.x + (_Time.x * _Speed), newVert.z + (_Time.x * _Speed),0.0,0.0));
    			float4 disp2 = tex2Dlod(_Displacement, float4(v1.x + (_Time.x * _Speed), newVert.z + (_Time.x * _Speed),0.0,0.0));
    			float4 disp3 = tex2Dlod(_Displacement, float4(newVert.x + (_Time.x * _Speed), v2.z + (_Time.x * _Speed),0.0,0.0));
    			
    			// offset the main vert
    			newVert.y += _Scale * disp.y; 
    			
    			// offset fake vertexes 
    			v1 += _Scale * disp2.y; 
    			v2 += _Scale * disp3.y; 
    
    			// calculate the new normal direction
    			float3 newNor = cross(v2 - newVert, v1 - newVert);
    			
    			// return world position of the vert for frag calculations
    			VOUT.posWorld = newVert;
    			
    			// set the vert back in object space
    			float4 vertObjectSpace = mul(newVert,_World2Object);
    			
    			// apply unity mvp matrix to the vert
    			VOUT.pos = mul(UNITY_MATRIX_MVP,vertObjectSpace);
    
    			//return the tex coords for frag calculations
    			VOUT.tex = i.texcoord;
    			
    			// return normal, tangents, and binormal information for frag calculations
    			VOUT.normalWorld = normalize( mul(float4(newNor,0.0),_World2Object).xyz);
    			VOUT.tangentWorld = normalize( mul(_Object2World,i.tangent).xyz);
    			VOUT.binormalWorld = normalize( cross(VOUT.normalWorld, VOUT.tangentWorld) * i.tangent.w);
    			
    			return VOUT;
    		}
    		
    		FragmentOutput frag(VertexOutput v) 
    		{
    			FragmentOutput FOUT;
    			
    			// Get the light and vieuw direction
    			float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
    			float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - v.posWorld.xyz);
    			
    			// tex coords for the normal map
    			float4 texN = tex2D(_Normal,float4(v.posWorld.x + (_Time.x * _NormalSpeed),v.posWorld.z + (_Time.x * _NormalSpeed) ,0.0,0.0));
    			
    			float3 localCoords = float3(2.0 * texN.ag - float2(1.0,1.0), 0.0);
    			localCoords.z = _Bumpiness;
    			
    			float3x3 local2WorldTranspose = float3x3(
    				v.tangentWorld,
    				v.binormalWorld,
    				v.normalWorld
    			);
    			
    			float3 normalDirection = normalize(mul(localCoords,local2WorldTranspose));
    			
    			// Calculate the cube map reflection
    			float3 reflectDir = reflect(viewDirection,v.normalWorld);
    			
    			float4 cubeRef = texCUBE(_Cube, reflectDir);
    			
    			float3 diffuseReflection =  _LightColor0 * saturate(dot(normalDirection,lightDirection));
    			float3 specularReflection = _SpecColor.xyz * pow(saturate(dot(reflect(-lightDirection, normalDirection), viewDirection)), _Shininess);
    			
    			float3 lightFinal = (cubeRef * _CubeStrength) * diffuseReflection + specularReflection;
    			
    			FOUT.color = UNITY_LIGHTMODEL_AMBIENT + max( 0.0, dot(v.normalWorld, lightDirection)) * (_Color + float4(lightFinal,0.0));
    			return FOUT;
    		}
    		ENDCG
    		}
    	} 
    	FallBack "Diffuse"
    }
    
  • Eric Chadwick
    The main difference I see is the specular is invisible in the 2nd shot. If you are using a Directional light, rotate it so the light rays bounce off the water and into the camera. That's how specular reflection works.
Sign In or Register to comment.