Hello everyone! I have a Unity project. And I want to write a shader which represents a temperature map in Unity. It is necessary to provide closed lines with borders, which shows tonality of temperature and the corresponding color gradation areas with different temperatures. Shader Language is Cg... Input data On output I want to get something like this texture, stretched to the globe sphere. I certainly can check every pixel, but maybe there are standard approaches to this problem? I would be grateful for any advice!
I think it actually is a toon style, you can achive this by some math trick,like this diffuse=floor(diffuse*count)/count, but for the black line,i think there has to be one more caculate,or you can do something remap,check the toon shader on unitywiki
I don`t need a shadow boundaries of the object... I need to cut around the various temperature regions. I tried to find the boundary at which the color changes by checking all the surrounding pixels and did not get anything good. Code (csharp): Shader "FFFFarik/8thPix1" { Properties { _MainTex ("Texture For Diffuse Material Color", 2D) = "white" {} } SubShader { Pass { CGPROGRAM #pragma vertex vert // vert function is the vertex shader #pragma fragment frag // frag function is the fragment shader #pragma target 3.0 uniform sampler2D _MainTex; struct vertexInput { float4 vertex : POSITION; float4 texcoord : TEXCOORD0; }; struct vertexOutput { float4 pos : SV_POSITION; float4 tex : TEXCOORD0; float3 posInObjectCoords : TEXCOORD1; }; vertexOutput vert(vertexInput input) { vertexOutput output; output.pos = mul(UNITY_MATRIX_MVP, input.vertex); output.tex = input.texcoord; output.posInObjectCoords = float3(input.vertex); return output; } float4 frag(vertexOutput input) : COLOR { float3 k; k.x = input.posInObjectCoords.x; k.y = input.posInObjectCoords.y; k.z = tex2D(_MainTex, float2(input.tex)).x; float t_col = tex2D(_MainTex, float2(k.x, k.y)); float a0, a1, a2, a3, a4, a5, a6, a7; float dx = 1.0 / 360.0; float dy = 1.0 / 181.0; a0 = tex2D(_MainTex, float2(k.x-dx,k.y-dy) ); a1 = tex2D(_MainTex, float2(k.x-dx,k.y) ); a2 = tex2D(_MainTex, float2(k.x-dx,k.y+dy) ); a3 = tex2D(_MainTex, float2(k.x,k.y-dy) ); a4 = tex2D(_MainTex, float2(k.x,k.y+dy) ); a5 = tex2D(_MainTex, float2(k.x+dx,k.y-dy) ); a6 = tex2D(_MainTex, float2(k.x+dx,k.y) ); a7 = tex2D(_MainTex, float2(k.x+dx,k.y+dy) ); if ( a0 != a7 || a2 != a5 || a1 != a6 || a3 != a4) return float4(1.0, 1.0, 1.0, 1.0); return float4(k, 1.0); } ENDCG } } } Result:
If your input data is that grayscale image, all you need is to saturate heat colors through it. You can even achieve the black lines if you use a nicely prepared gradient map. EDIT: For an example, you can use my thermal vision effect in my "post processing pack" Or "fire shader", from the assetstore.
I dont understand, why i need to use saturate function, i already have color from 0 to 1? What it gives me? Why it is not floor? But how i can make this lines?
What you'll want is a color ramp texture, where the U coordinate of the ramp UVs is the grayscale texture pixel data. The lines are tricky though, not sure what the best way to achieve uniform width and smoothness. Blurring the input data helps. Looks quite bad, but it works: Here's the ramp I used: Semi-pseudo code: Code (csharp): fixed tempData = tex2D(_MyData, input.tex.xy).; fixed2 rampUV = fixed2(tempData, 0); fixed3 heatColor = tex2d(_MyRamp, rampUV);
Thank you very much!!!! That's great! It was much easier than I thought... If anyone is interested, here the alternative way, where I try to find intersection of some grayscale level with some height level (from 1 to 500). Code (csharp): Shader "Contours/MyShader3" { Properties { _MainTex ("Texture For Diffuse Material Color", 2D) = "white" {} } SubShader { Pass { CGPROGRAM #pragma vertex vert // vert function is the vertex shader #pragma fragment frag // frag function is the fragment shader #pragma target 3.0 uniform sampler2D _MainTex; struct vertexInput { float4 vertex : POSITION; float4 texcoord : TEXCOORD0; }; struct vertexOutput { float4 pos : SV_POSITION; float4 tex : TEXCOORD0; float3 posInObjectCoords : TEXCOORD1; }; vertexOutput vert(vertexInput input) { vertexOutput output; output.pos = mul(UNITY_MATRIX_MVP, input.vertex); output.tex = input.texcoord; output.posInObjectCoords = float3(input.vertex); return output; } float4 frag(vertexOutput input) : COLOR { float3 k; k.x = input.posInObjectCoords.x; k.y = input.posInObjectCoords.y; k.z = tex2D(_MainTex, float2(input.tex)).x; float3 f = floor(k * 500); for(float i = 1.0; i < 500.0; i += 50.0) { if(f.z == i) { return float4(1.0, 1.0, 1.0, 1.0); } } return float4(k, 1.0); } ENDCG } } } But they have some problems with line width, which is shown on the screenshot:
Hello again! I solved the problem with line width by calculating distance between camera and fragment position. Code (csharp): float base_dist = 800.0; float dist = distance(_WorldSpaceCameraPos, input.position_in_world_space); float scale_level = base_dist / dist; Part of the problem is solved, but the lines at the edges still have a different width(smaller): To solve the problem, I also calculated the angle between the camera and a fragment normal: Code (csharp): float3 normalDirection = normalize(input.normal); float3 viewDirection = normalize(input.viewDir); float base_dist = 800.0; float dist = distance(_WorldSpaceCameraPos, input.position_in_world_space); float edge = abs(dot(normalDirection, viewDirection)); edge = edge < 0.4 ? edge*1.5 : edge; float scale_level = (base_dist * edge) / dist; But this does not solve the problem completely... How can i achieve 1px smooth contours with constant width? As alternative way in this thread discusses the same problem: LINK But not all platforms support the derivatives. How can I avoid this problem?
I think its a similar problem to making a shader generate antialiased output.. whereby you need the rate of change across the pixel (like ddx/ddy commands) to figure out *in screen space* how many pixels away from the perimeter a given fragment is.