Question by
miloszecket · May 07, 2020 at 06:23 AM ·
shadersshader programmingvertex shadertessellation
How can I get the maximum texture value within a tri in a shader?
I'm making a shader for dynamically tessellating a plane to accommodate the use of an image as a displacement map, but currently the only values used for tessellation are those at each vertex of a tri (which means that if the image has a bright dot in the middle of a tri, the shader won't take it into account for tessellation). How can I get the maximum value within a tri so I can use it to determine tessellation amount?
Code:
Shader "QI/Sample"
{
Properties
{
_Array ("Array", 2DArray) = ""{}
_ArrayLength ("Length", Int) = 1
_UVScale ("UVScale", Float) = 1.0
_DispMap("Heightmap", 2D) = "black" {}
_Uniform("Uniform Tesselation", Range(1, 64)) = 1
_Height("Height", Range(0, 2)) = 1
_DispDetail("Detail", Range(0, 5)) = 3
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex TessellationVertexProgram
#pragma fragment frag
#pragma hull HullProgram
#pragma domain DomainProgram
#pragma require 2darray
#pragma require tessellation tessHW
#include "UnityCG.cginc"
#include "Tessellation.cginc"
int _ArrayLength;
float _Uniform;
UNITY_DECLARE_TEX2DARRAY(_Array);
float _UVScale;
sampler2D _DispMap;
float4 _DispMap_ST;
float _Height;
float _DispDetail;
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
struct appdata{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct ControlPoint
{
float4 vertex : INTERNALTESSPOS;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct TessellationFactors
{
float edge[3] : SV_TessFactor;
float inside : SV_InsideTessFactor;
};
float3 RGBToHSV(float3 c)
{
float4 K = float4(0.0f, -1.0f / 3.0f, 2.0f / 3.0f, -1.0f);
float4 p = lerp( float4( c.bg, K.wz ), float4( c.gb, K.xy ), step( c.b, c.g ) );
float4 q = lerp( float4( p.xyw, c.r ), float4( c.r, p.yzx ), step( p.x, c.r ) );
float d = q.x - min( q.w, q.y );
float e = 1.0e-10;
return float3( abs(q.z + (q.w - q.y) / (6.0f * d + e)), d / (q.x + e), q.x);
}
TessellationFactors PatchConstantFunction(InputPatch<ControlPoint, 3> patch)
{
float p0factor = RGBToHSV(tex2Dlod(_DispMap, float4(patch[0].uv.x, patch[0].uv.y, 0, 0))).z;
float p1factor = RGBToHSV(tex2Dlod(_DispMap, float4(patch[1].uv.x, patch[1].uv.y, 0, 0))).z;
float p2factor = RGBToHSV(tex2Dlod(_DispMap, float4(patch[2].uv.x, patch[2].uv.y, 0, 0))).z;
float factor = p0factor + p1factor + p2factor;
TessellationFactors f;
f.edge[0] = factor > 0.0 ? _Uniform + ((factor + 1) * _DispDetail) : 1.0;
f.edge[1] = factor > 0.0 ? _Uniform + ((factor + 1) * _DispDetail) : 1.0;
f.edge[2] = factor > 0.0 ? _Uniform + ((factor + 1) * _DispDetail) : 1.0;
f.inside = factor > 0.0 ? _Uniform + ((factor + 1) * _DispDetail) : 1.0;
return f;
}
ControlPoint TessellationVertexProgram(appdata v)
{
ControlPoint p;
p.vertex = v.vertex;
p.uv = v.uv;
p.normal = v.normal;
return p;
}
[UNITY_domain("tri")]
[UNITY_outputcontrolpoints(3)]
[UNITY_outputtopology("triangle_cw")]
[UNITY_partitioning("fractional_odd")]
[UNITY_patchconstantfunc("PatchConstantFunction")]
ControlPoint HullProgram(InputPatch<ControlPoint, 3> patch, uint id : SV_OutputControlPointID)
{
return patch[id];
}
v2f vert (appdata IN)
{
v2f o;
o.uv = IN.uv;
float2 uv_DispMap = IN.uv * _DispMap_ST.xy + _DispMap_ST.zw;
float height = RGBToHSV(tex2Dlod(_DispMap, float4(uv_DispMap, 0, 0))).z;
o.vertex = UnityObjectToClipPos(IN.vertex * 2) + UnityObjectToClipPos(float4(height * _Height * IN.normal, 0));
return o;
}
[UNITY_domain("tri")]
v2f DomainProgram(TessellationFactors factors,
OutputPatch<ControlPoint, 3> patch,
float3 barycentricCoordinates : SV_DomainLocation)
{
appdata data;
data.vertex = patch[0].vertex * barycentricCoordinates.x +
patch[1].vertex * barycentricCoordinates.y +
patch[2].vertex * barycentricCoordinates.z;
data.uv = patch[0].uv * barycentricCoordinates.x +
patch[1].uv * barycentricCoordinates.y +
patch[2].uv * barycentricCoordinates.z;
data.normal = patch[0].normal * barycentricCoordinates.x +
patch[1].normal * barycentricCoordinates.y +
patch[2].normal * barycentricCoordinates.z;
return vert(data);
}
fixed4 frag (v2f i) : SV_Target
{
half4 col = half4(0, 0, 0, 0);
for(int index = 0; index < _ArrayLength; index ++){
col = UNITY_SAMPLE_TEX2DARRAY(_Array, float3(i.uv.x, i.uv.y, index)) + col;
}
return col;
}
ENDCG
}
}
}
Comment
Your answer
Follow this Question
Related Questions
Very basic shader problem 0 Answers
Reversed UV Light with 2D PointLight (shader graph) 0 Answers
Standard Cutout Double Sided? 0 Answers
A Blend Shader That Uses Vertex Information 0 Answers
Shader - SV_Target 1 Answer