[spline/bezier]Move whole tessellation logic in the shaders into a subroutine.

This commit is contained in:
xebra 2018-07-13 23:36:36 +09:00
parent 3d07bca010
commit 41d6c3cf3a
3 changed files with 273 additions and 225 deletions

View File

@ -297,6 +297,87 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage
WRITE(p, " return pos;\n");
WRITE(p, "}\n");
}
WRITE(p, "struct Tess {\n");
WRITE(p, " float3 pos;\n");
if (doTexture && hasTexcoord)
WRITE(p, " float2 tex;\n");
if (hasColor)
WRITE(p, " float4 col;\n");
if (hasNormal)
WRITE(p, " float3 nrm;\n");
WRITE(p, "};\n");
WRITE(p, "void tessellate(in VS_IN In, out Tess tess) {\n");
WRITE(p, " int2 spline_num_patches = int2((u_spline_counts >> 0) & 0xFF, (u_spline_counts >> 8) & 0xFF);\n");
WRITE(p, " int2 spline_tess = int2((u_spline_counts >> 16) & 0xFF, (u_spline_counts >> 24) & 0xFF);\n");
// Calculate current patch position and vertex position(index for the weights)
WRITE(p, " int spline_count_u = %s;\n", doBezier ? "spline_num_patches.x * 3 + 1" : "spline_num_patches.x + 3");
WRITE(p, " int u = In.instanceId %% spline_num_patches.x;\n");
WRITE(p, " int v = In.instanceId / spline_num_patches.x;\n");
WRITE(p, " int2 patch_pos = int2(u, v);\n");
WRITE(p, " int2 vertex_pos = int2(In.position.xy);\n");
if (doSpline) {
WRITE(p, " bool2 isFirstEdge = !bool2(vertex_pos);\n"); // vertex_pos == 0
WRITE(p, " bool2 isNotFirstPatch = bool2(patch_pos);\n"); // patch_pos > 0
WRITE(p, " vertex_pos += patch_pos * spline_tess;\n");
}
// Load 4x4 control points
WRITE(p, " float3 _pos[16];\n");
WRITE(p, " float2 _tex[16];\n");
WRITE(p, " float4 _col[16];\n");
WRITE(p, " int index;\n");
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
WRITE(p, " index = (%i + v%s) * spline_count_u + (%i + u%s);\n", i, doBezier ? " * 3" : "", j, doBezier ? " * 3" : "");
WRITE(p, " _pos[%i] = tess_data[index].pos;\n", i * 4 + j);
if (doTexture && hasTexcoord && hasTexcoordTess)
WRITE(p, " _tex[%i] = tess_data[index].tex;\n", i * 4 + j);
if (hasColor && hasColorTess)
WRITE(p, " _col[%i] = tess_data[index].col;\n", i * 4 + j);
}
}
// Basis polynomials as weight coefficients
WRITE(p, " float4 basis_u = tess_weights_u[vertex_pos.x].basis;\n");
WRITE(p, " float4 basis_v = tess_weights_v[vertex_pos.y].basis;\n");
if (doSpline) {
WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n");
WRITE(p, " basis_u = float4(basis_u.yzw, 0);\n");
WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n");
WRITE(p, " basis_v = float4(basis_v.yzw, 0);\n");
}
// Tessellate
WRITE(p, " tess.pos = tess_sample(_pos, basis_u, basis_v);\n");
if (doTexture && hasTexcoord) {
if (hasTexcoordTess)
WRITE(p, " tess.tex = tess_sample(_tex, basis_u, basis_v);\n");
else
WRITE(p, " tess.tex = In.normal.xy + float2(patch_pos);\n");
}
if (hasColor) {
if (hasColorTess)
WRITE(p, " tess.col = tess_sample(_col, basis_u, basis_v);\n");
else
WRITE(p, " tess.col = tess_data[0].col;\n");
}
if (hasNormal) {
// Derivatives as weight coefficients
WRITE(p, " float4 deriv_u = tess_weights_u[vertex_pos.x].deriv;\n");
WRITE(p, " float4 deriv_v = tess_weights_v[vertex_pos.y].deriv;\n");
if (doSpline) {
WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n");
WRITE(p, " deriv_u = float4(deriv_u.yzw, 0);\n");
WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n");
WRITE(p, " deriv_v = float4(deriv_v.yzw, 0);\n");
}
WRITE(p, " float3 du = tess_sample(_pos, deriv_u, basis_v);\n");
WRITE(p, " float3 dv = tess_sample(_pos, basis_u, deriv_v);\n");
WRITE(p, " tess.nrm = normalize(cross(du, dv));\n");
}
WRITE(p, "}\n");
}
WRITE(p, "VS_OUT main(VS_IN In) {\n");
@ -346,80 +427,14 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage
} else {
// Step 1: World Transform / Skinning
if (!enableBones) {
// Hardware tessellation
if (doSpline || doBezier) {
WRITE(p, " int2 spline_num_patches = int2((u_spline_counts >> 0) & 0xFF, (u_spline_counts >> 8) & 0xFF);\n");
WRITE(p, " int2 spline_tess = int2((u_spline_counts >> 16) & 0xFF, (u_spline_counts >> 24) & 0xFF);\n");
// Hardware tessellation
WRITE(p, " Tess tess;\n");
WRITE(p, " tessellate(In, tess);\n");
WRITE(p, " int spline_count_u = %s;\n", doBezier ? "spline_num_patches.x * 3 + 1" : "spline_num_patches.x + 3");
WRITE(p, " int u = In.instanceId %% spline_num_patches.x;\n");
WRITE(p, " int v = In.instanceId / spline_num_patches.x;\n");
WRITE(p, " int2 patch_pos = int2(u, v);\n");
WRITE(p, " int2 vertex_pos = int2(In.position.xy);\n");
if (doSpline) {
WRITE(p, " bool2 isFirstEdge = !bool2(vertex_pos);\n"); // vertex_pos == 0
WRITE(p, " bool2 isNotFirstPatch = bool2(patch_pos);\n"); // patch_pos > 0
WRITE(p, " vertex_pos += patch_pos * spline_tess;\n");
}
// Load 4x4 control points
WRITE(p, " float3 _pos[16];\n");
WRITE(p, " float2 _tex[16];\n");
WRITE(p, " float4 _col[16];\n");
WRITE(p, " int index;\n");
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
WRITE(p, " index = (%i + v%s) * spline_count_u + (%i + u%s);\n", i, doBezier ? " * 3" : "", j, doBezier ? " * 3" : "");
WRITE(p, " _pos[%i] = tess_data[index].pos;\n", i * 4 + j);
if (doTexture && hasTexcoord && hasTexcoordTess)
WRITE(p, " _tex[%i] = tess_data[index].tex;\n", i * 4 + j);
if (hasColor && hasColorTess)
WRITE(p, " _col[%i] = tess_data[index].col;\n", i * 4 + j);
}
}
// Basis polynomials as weight coefficients
WRITE(p, " float4 basis_u = tess_weights_u[vertex_pos.x].basis;\n");
WRITE(p, " float4 basis_v = tess_weights_v[vertex_pos.y].basis;\n");
if (doSpline) {
WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n");
WRITE(p, " basis_u = float4(basis_u.yzw, 0);\n");
WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n");
WRITE(p, " basis_v = float4(basis_v.yzw, 0);\n");
}
// Tessellate
WRITE(p, " float3 pos = tess_sample(_pos, basis_u, basis_v);\n");
if (doTexture && hasTexcoord) {
if (hasTexcoordTess)
WRITE(p, " float2 tex = tess_sample(_tex, basis_u, basis_v);\n");
else
WRITE(p, " float2 tex = In.normal.xy + float2(patch_pos);\n");
}
if (hasColor) {
if (hasColorTess)
WRITE(p, " float4 col = tess_sample(_col, basis_u, basis_v);\n");
else
WRITE(p, " float4 col = tess_data[0].col;\n");
}
if (hasNormal) {
// Derivatives as weight coefficients
WRITE(p, " float4 deriv_u = tess_weights_u[vertex_pos.x].deriv;\n");
WRITE(p, " float4 deriv_v = tess_weights_v[vertex_pos.y].deriv;\n");
if (doSpline) {
WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n");
WRITE(p, " deriv_u = float4(deriv_u.yzw, 0);\n");
WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n");
WRITE(p, " deriv_v = float4(deriv_v.yzw, 0);\n");
}
WRITE(p, " float3 du = tess_sample(_pos, deriv_u, basis_v);\n");
WRITE(p, " float3 dv = tess_sample(_pos, basis_u, deriv_v);\n");
WRITE(p, " float3 nrm = cross(du, dv);\n");
WRITE(p, " nrm = normalize(nrm);\n");
}
WRITE(p, " float3 worldpos = mul(float4(pos.xyz, 1.0), u_world);\n");
WRITE(p, " float3 worldpos = mul(float4(tess.pos.xyz, 1.0), u_world);\n");
if (hasNormal)
WRITE(p, " float3 worldnormal = normalize(mul(float4(%snrm, 0.0), u_world));\n", flipNormalTess ? "-" : "");
WRITE(p, " float3 worldnormal = normalize(mul(float4(%stess.nrm, 0.0), u_world));\n", flipNormalTess ? "-" : "");
else
WRITE(p, " float3 worldnormal = float3(0.0, 0.0, 1.0);\n");
} else {
@ -524,9 +539,9 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage
const char *diffuseStr = (matUpdate & 2) && hasColor ? "In.color0.rgb" : "u_matdiffuse";
const char *specularStr = (matUpdate & 4) && hasColor ? "In.color0.rgb" : "u_matspecular.rgb";
if (doBezier || doSpline) {
ambientStr = (matUpdate & 1) && hasColor ? "col" : "u_matambientalpha";
diffuseStr = (matUpdate & 2) && hasColor ? "col.rgb" : "u_matdiffuse";
specularStr = (matUpdate & 4) && hasColor ? "col.rgb" : "u_matspecular.rgb";
ambientStr = (matUpdate & 1) && hasColor ? "tess.col" : "u_matambientalpha";
diffuseStr = (matUpdate & 2) && hasColor ? "tess.col.rgb" : "u_matdiffuse";
specularStr = (matUpdate & 4) && hasColor ? "tess.col.rgb" : "u_matspecular.rgb";
}
bool diffuseIsZero = true;
@ -653,7 +668,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage
// Lighting doesn't affect color.
if (hasColor) {
if (doBezier || doSpline)
WRITE(p, " Out.v_color0 = col;\n");
WRITE(p, " Out.v_color0 = tess.col;\n");
else
WRITE(p, " Out.v_color0 = In.color0;\n");
} else {
@ -671,7 +686,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage
if (scaleUV) {
if (hasTexcoord) {
if (doBezier || doSpline)
WRITE(p, " Out.v_texcoord = float3(tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n");
WRITE(p, " Out.v_texcoord = float3(tess.tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n");
else
WRITE(p, " Out.v_texcoord = float3(In.texcoord.xy * u_uvscaleoffset.xy, 0.0);\n");
} else {
@ -680,7 +695,7 @@ void GenerateVertexShaderHLSL(const VShaderID &id, char *buffer, ShaderLanguage
} else {
if (hasTexcoord) {
if (doBezier || doSpline)
WRITE(p, " Out.v_texcoord = float3(tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n");
WRITE(p, " Out.v_texcoord = float3(tess.tex.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n");
else
WRITE(p, " Out.v_texcoord = float3(In.texcoord.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n");
} else {

View File

@ -400,6 +400,84 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask,
WRITE(p, " return pos;\n");
WRITE(p, "}\n");
}
WRITE(p, "struct Tess {\n");
WRITE(p, " vec3 pos;\n");
if (doTexture && hasTexcoord)
WRITE(p, " vec2 tex;\n");
if (hasColor)
WRITE(p, " vec4 col;\n");
if (hasNormal)
WRITE(p, " vec3 nrm;\n");
WRITE(p, "};\n");
WRITE(p, "void tessellate(out Tess tess) {\n");
// Calculate current patch position and vertex position(index for the weights)
WRITE(p, " int spline_count_u = %s;\n", doBezier ? "u_spline_num_patches.x * 3 + 1" : "u_spline_num_patches.x + 3");
WRITE(p, " int u = gl_InstanceID %% u_spline_num_patches.x;\n");
WRITE(p, " int v = gl_InstanceID / u_spline_num_patches.x;\n");
WRITE(p, " ivec2 patch_pos = ivec2(u, v);\n");
WRITE(p, " ivec2 vertex_pos = ivec2(position.xy);\n");
if (doSpline) {
WRITE(p, " bvec2 isFirstEdge = not(bvec2(vertex_pos));\n"); // vertex_pos == 0
WRITE(p, " bvec2 isNotFirstPatch = bvec2(patch_pos);\n"); // patch_pos > 0
WRITE(p, " vertex_pos += patch_pos * u_spline_tess;\n");
}
// Load 4x4 control points
WRITE(p, " vec3 _pos[16];\n");
WRITE(p, " vec2 _tex[16];\n");
WRITE(p, " vec4 _col[16];\n");
WRITE(p, " for (int i = 0; i < 4; i++) {\n");
WRITE(p, " for (int j = 0; j < 4; j++) {\n");
WRITE(p, " int index = (i + v%s) * spline_count_u + (j + u%s);\n", doBezier ? " * 3" : "", doBezier ? " * 3" : "");
WRITE(p, " _pos[i * 4 + j] = %s(u_tess_points, ivec2(index, 0), 0).xyz;\n", texelFetch);
if (doTexture && hasTexcoord && hasTexcoordTess)
WRITE(p, " _tex[i * 4 + j] = %s(u_tess_points, ivec2(index, 1), 0).xy;\n", texelFetch);
if (hasColor && hasColorTess)
WRITE(p, " _col[i * 4 + j] = %s(u_tess_points, ivec2(index, 2), 0).rgba;\n", texelFetch);
WRITE(p, " }\n");
WRITE(p, " }\n");
// Basis polynomials as weight coefficients
WRITE(p, " vec4 basis_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(vertex_pos.x * 2, 0)");
WRITE(p, " vec4 basis_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(vertex_pos.y * 2, 0)");
if (doSpline) {
WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n");
WRITE(p, " basis_u = vec4(basis_u.yzw, 0);\n");
WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n");
WRITE(p, " basis_v = vec4(basis_v.yzw, 0);\n");
}
// Tessellate
WRITE(p, " tess.pos = tess_sample(_pos, basis_u, basis_v);\n");
if (doTexture && hasTexcoord) {
if (hasTexcoordTess)
WRITE(p, " tess.tex = tess_sample(_tex, basis_u, basis_v);\n");
else
WRITE(p, " tess.tex = normal.xy + vec2(patch_pos);\n");
}
if (hasColor) {
if (hasColorTess)
WRITE(p, " tess.col = tess_sample(_col, basis_u, basis_v);\n");
else
WRITE(p, " tess.col = %s(u_tess_points, ivec2(0, 2), 0).rgba;\n", texelFetch);
}
if (hasNormal) {
// Derivatives as weight coefficients
WRITE(p, " vec4 deriv_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(vertex_pos.x * 2 + 1, 0)");
WRITE(p, " vec4 deriv_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(vertex_pos.y * 2 + 1, 0)");
if (doSpline) {
WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n");
WRITE(p, " deriv_u = vec4(deriv_u.yzw, 0);\n");
WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n");
WRITE(p, " deriv_v = vec4(deriv_v.yzw, 0);\n");
}
WRITE(p, " vec3 du = tess_sample(_pos, deriv_u, basis_v);\n");
WRITE(p, " vec3 dv = tess_sample(_pos, basis_u, deriv_v);\n");
WRITE(p, " tess.nrm = normalize(cross(du, dv));\n");
}
WRITE(p, "}\n");
}
WRITE(p, "void main() {\n");
@ -438,76 +516,14 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask,
} else {
// Step 1: World Transform / Skinning
if (!enableBones) {
// Hardware tessellation
if (doBezier || doSpline) {
WRITE(p, " int spline_count_u = %s;\n", doBezier ? "u_spline_num_patches.x * 3 + 1" : "u_spline_num_patches.x + 3");
WRITE(p, " int u = gl_InstanceID %% u_spline_num_patches.x;\n");
WRITE(p, " int v = gl_InstanceID / u_spline_num_patches.x;\n");
WRITE(p, " ivec2 patch_pos = ivec2(u, v);\n");
WRITE(p, " ivec2 vertex_pos = ivec2(position.xy);\n");
if (doSpline) {
WRITE(p, " bvec2 isFirstEdge = not(bvec2(vertex_pos));\n"); // vertex_pos == 0
WRITE(p, " bvec2 isNotFirstPatch = bvec2(patch_pos);\n"); // patch_pos > 0
WRITE(p, " vertex_pos += patch_pos * u_spline_tess;\n");
}
// Load 4x4 control points
WRITE(p, " vec3 _pos[16];\n");
WRITE(p, " vec2 _tex[16];\n");
WRITE(p, " vec4 _col[16];\n");
WRITE(p, " for (int i = 0; i < 4; i++) {\n");
WRITE(p, " for (int j = 0; j < 4; j++) {\n");
WRITE(p, " int index = (i + v%s) * spline_count_u + (j + u%s);\n", doBezier ? " * 3" : "", doBezier ? " * 3" : "");
WRITE(p, " _pos[i * 4 + j] = %s(u_tess_points, ivec2(index, 0), 0).xyz;\n", texelFetch);
if (doTexture && hasTexcoord && hasTexcoordTess)
WRITE(p, " _tex[i * 4 + j] = %s(u_tess_points, ivec2(index, 1), 0).xy;\n", texelFetch);
if (hasColor && hasColorTess)
WRITE(p, " _col[i * 4 + j] = %s(u_tess_points, ivec2(index, 2), 0).rgba;\n", texelFetch);
WRITE(p, " }\n");
WRITE(p, " }\n");
// Hardware tessellation
WRITE(p, " Tess tess;\n");
WRITE(p, " tessellate(tess);\n");
// Basis polynomials as weight coefficients
WRITE(p, " vec4 basis_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(vertex_pos.x * 2, 0)");
WRITE(p, " vec4 basis_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(vertex_pos.y * 2, 0)");
if (doSpline) {
WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n");
WRITE(p, " basis_u = vec4(basis_u.yzw, 0);\n");
WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n");
WRITE(p, " basis_v = vec4(basis_v.yzw, 0);\n");
}
// Tessellate
WRITE(p, " vec3 pos = tess_sample(_pos, basis_u, basis_v);\n");
if (doTexture && hasTexcoord) {
if (hasTexcoordTess)
WRITE(p, " vec2 tex = tess_sample(_tex, basis_u, basis_v);\n");
else
WRITE(p, " vec2 tex = normal.xy + vec2(patch_pos);\n");
}
if (hasColor) {
if (hasColorTess)
WRITE(p, " vec4 col = tess_sample(_col, basis_u, basis_v);\n");
else
WRITE(p, " vec4 col = %s(u_tess_points, ivec2(0, 2), 0).rgba;\n", texelFetch);
}
WRITE(p, " vec3 worldpos = (u_world * vec4(tess.pos.xyz, 1.0)).xyz;\n");
if (hasNormal) {
// Derivatives as weight coefficients
WRITE(p, " vec4 deriv_u = %s(u_tess_weights_u, %s, 0);\n", texelFetch, "ivec2(vertex_pos.x * 2 + 1, 0)");
WRITE(p, " vec4 deriv_v = %s(u_tess_weights_v, %s, 0);\n", texelFetch, "ivec2(vertex_pos.y * 2 + 1, 0)");
if (doSpline) {
WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n");
WRITE(p, " deriv_u = vec4(deriv_u.yzw, 0);\n");
WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n");
WRITE(p, " deriv_v = vec4(deriv_v.yzw, 0);\n");
}
WRITE(p, " vec3 du = tess_sample(_pos, deriv_u, basis_v);\n");
WRITE(p, " vec3 dv = tess_sample(_pos, basis_u, deriv_v);\n");
WRITE(p, " vec3 nrm = cross(du, dv);\n");
WRITE(p, " nrm = normalize(nrm);\n");
}
WRITE(p, " vec3 worldpos = (u_world * vec4(pos.xyz, 1.0)).xyz;\n");
if (hasNormal) {
WRITE(p, " mediump vec3 worldnormal = normalize((u_world * vec4(%snrm, 0.0)).xyz);\n", flipNormalTess ? "-" : "");
WRITE(p, " mediump vec3 worldnormal = normalize((u_world * vec4(%stess.nrm, 0.0)).xyz);\n", flipNormalTess ? "-" : "");
} else {
WRITE(p, " mediump vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n");
}
@ -611,9 +627,9 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask,
const char *diffuseStr = (matUpdate & 2) && hasColor ? "color0.rgb" : "u_matdiffuse";
const char *specularStr = (matUpdate & 4) && hasColor ? "color0.rgb" : "u_matspecular.rgb";
if (doBezier || doSpline) {
ambientStr = (matUpdate & 1) && hasColor ? "col" : "u_matambientalpha";
diffuseStr = (matUpdate & 2) && hasColor ? "col.rgb" : "u_matdiffuse";
specularStr = (matUpdate & 4) && hasColor ? "col.rgb" : "u_matspecular.rgb";
ambientStr = (matUpdate & 1) && hasColor ? "tess.col" : "u_matambientalpha";
diffuseStr = (matUpdate & 2) && hasColor ? "tess.col.rgb" : "u_matdiffuse";
specularStr = (matUpdate & 4) && hasColor ? "tess.col.rgb" : "u_matspecular.rgb";
}
bool diffuseIsZero = true;
@ -740,7 +756,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask,
// Lighting doesn't affect color.
if (hasColor) {
if (doBezier || doSpline)
WRITE(p, " v_color0 = col;\n");
WRITE(p, " v_color0 = tess.col;\n");
else
WRITE(p, " v_color0 = color0;\n");
} else {
@ -760,7 +776,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask,
if (doBezier || doSpline)
// TODO: Need fix?
// Fix to avoid temporarily texture animation bug with hardware tessellation.
WRITE(p, " v_texcoord = vec3(tex * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n");
WRITE(p, " v_texcoord = vec3(tess.tex * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n");
else
WRITE(p, " v_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy, 0.0);\n");
} else {
@ -769,7 +785,7 @@ void GenerateVertexShader(const VShaderID &id, char *buffer, uint32_t *attrMask,
} else {
if (hasTexcoord) {
if (doBezier || doSpline)
WRITE(p, " v_texcoord = vec3(tex * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n");
WRITE(p, " v_texcoord = vec3(tess.tex * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n");
else
WRITE(p, " v_texcoord = vec3(texcoord.xy * u_uvscaleoffset.xy + u_uvscaleoffset.zw, 0.0);\n");
} else {

View File

@ -249,6 +249,87 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) {
WRITE(p, " return pos;\n");
WRITE(p, "}\n");
}
WRITE(p, "struct Tess {\n");
WRITE(p, " vec3 pos;\n");
if (doTexture && hasTexcoord)
WRITE(p, " vec2 tex;\n");
if (hasColor)
WRITE(p, " vec4 col;\n");
if (hasNormal)
WRITE(p, " vec3 nrm;\n");
WRITE(p, "};\n");
WRITE(p, "void tessellate(out Tess tess) {\n");
// Calculate current patch position and vertex position(index for the weights)
WRITE(p, " ivec2 spline_num_patches = ivec2((base.spline_counts >> 0) & 0xff, (base.spline_counts >> 8) & 0xff);\n");
WRITE(p, " ivec2 spline_tess = ivec2((base.spline_counts >> 16) & 0xff, (base.spline_counts >> 24) & 0xff);\n");
WRITE(p, " int spline_count_u = %s;\n", doBezier ? "spline_num_patches.x * 3 + 1" : "spline_num_patches.x + 3");
WRITE(p, " int u = gl_InstanceIndex %% spline_num_patches.x;\n");
WRITE(p, " int v = gl_InstanceIndex / spline_num_patches.x;\n");
WRITE(p, " ivec2 patch_pos = ivec2(u, v);\n");
WRITE(p, " ivec2 vertex_pos = ivec2(position.xy);\n");
if (doSpline) {
WRITE(p, " bvec2 isFirstEdge = not(bvec2(vertex_pos));\n"); // vertex_pos == 0
WRITE(p, " bvec2 isNotFirstPatch = bvec2(patch_pos);\n"); // patch_pos > 0
WRITE(p, " vertex_pos += patch_pos * spline_tess;\n");
}
// Load 4x4 control points
WRITE(p, " vec3 _pos[16];\n");
WRITE(p, " vec2 _tex[16];\n");
WRITE(p, " vec4 _col[16];\n");
WRITE(p, " for (int i = 0; i < 4; i++) {\n");
WRITE(p, " for (int j = 0; j < 4; j++) {\n");
WRITE(p, " int idx = (i + v%s) * spline_count_u + (j + u%s);\n", doBezier ? " * 3" : "", doBezier ? " * 3" : "");
WRITE(p, " _pos[i * 4 + j] = tess_data.data[idx].pos.xyz;\n");
if (doTexture && hasTexcoord && hasTexcoordTess)
WRITE(p, " _tex[i * 4 + j] = tess_data.data[idx].uv.xy;\n");
if (hasColor && hasColorTess)
WRITE(p, " _col[i * 4 + j] = tess_data.data[idx].color;\n");
WRITE(p, " }\n");
WRITE(p, " }\n");
// Basis polynomials as weight coefficients
WRITE(p, " vec4 basis_u = tess_weights_u.data[vertex_pos.x].basis;\n");
WRITE(p, " vec4 basis_v = tess_weights_v.data[vertex_pos.y].basis;\n");
if (doSpline) {
WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n");
WRITE(p, " basis_u = vec4(basis_u.yzw, 0);\n");
WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n");
WRITE(p, " basis_v = vec4(basis_v.yzw, 0);\n");
}
// Tessellate
WRITE(p, " tess.pos = tess_sample(_pos, basis_u, basis_v);\n");
if (doTexture && hasTexcoord) {
if (hasTexcoordTess)
WRITE(p, " tess.tex = tess_sample(_tex, basis_u, basis_v);\n");
else
WRITE(p, " tess.tex = normal.xy + vec2(patch_pos);\n");
}
if (hasColor) {
if (hasColorTess)
WRITE(p, " tess.col = tess_sample(_col, basis_u, basis_v);\n");
else
WRITE(p, " tess.col = tess_data.data[0].color;\n");
}
if (hasNormal) {
// Derivatives as weight coefficients
WRITE(p, " vec4 deriv_u = tess_weights_u.data[vertex_pos.x].deriv;\n");
WRITE(p, " vec4 deriv_v = tess_weights_v.data[vertex_pos.y].deriv;\n");
if (doSpline) {
WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n");
WRITE(p, " deriv_u = vec4(deriv_u.yzw, 0);\n");
WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n");
WRITE(p, " deriv_v = vec4(deriv_v.yzw, 0);\n");
}
WRITE(p, " vec3 du = tess_sample(_pos, deriv_u, basis_v);\n");
WRITE(p, " vec3 dv = tess_sample(_pos, basis_u, deriv_v);\n");
WRITE(p, " tess.nrm = normalize(cross(du, dv));\n");
}
WRITE(p, "}\n");
}
WRITE(p, "void main() {\n");
@ -288,77 +369,13 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) {
// Step 1: World Transform / Skinning
if (!enableBones) {
if (doBezier || doSpline) {
WRITE(p, " ivec2 spline_num_patches = ivec2((base.spline_counts >> 0) & 0xff, (base.spline_counts >> 8) & 0xff);\n");
WRITE(p, " ivec2 spline_tess = ivec2((base.spline_counts >> 16) & 0xff, (base.spline_counts >> 24) & 0xff);\n");
// Hardware tessellation
WRITE(p, " Tess tess;\n");
WRITE(p, " tessellate(tess);\n");
WRITE(p, " int spline_count_u = %s;\n", doBezier ? "spline_num_patches.x * 3 + 1" : "spline_num_patches.x + 3");
WRITE(p, " int u = gl_InstanceIndex %% spline_num_patches.x;\n");
WRITE(p, " int v = gl_InstanceIndex / spline_num_patches.x;\n");
WRITE(p, " ivec2 patch_pos = ivec2(u, v);\n");
WRITE(p, " ivec2 vertex_pos = ivec2(position.xy);\n");
if (doSpline) {
WRITE(p, " bvec2 isFirstEdge = not(bvec2(vertex_pos));\n"); // vertex_pos == 0
WRITE(p, " bvec2 isNotFirstPatch = bvec2(patch_pos);\n"); // patch_pos > 0
WRITE(p, " vertex_pos += patch_pos * spline_tess;\n");
}
// Load 4x4 control points
WRITE(p, " vec3 _pos[16];\n");
WRITE(p, " vec2 _tex[16];\n");
WRITE(p, " vec4 _col[16];\n");
WRITE(p, " for (int i = 0; i < 4; i++) {\n");
WRITE(p, " for (int j = 0; j < 4; j++) {\n");
WRITE(p, " int idx = (i + v%s) * spline_count_u + (j + u%s);\n", doBezier ? " * 3" : "", doBezier ? " * 3" : "");
WRITE(p, " _pos[i * 4 + j] = tess_data.data[idx].pos.xyz;\n");
if (doTexture && hasTexcoord && hasTexcoordTess)
WRITE(p, " _tex[i * 4 + j] = tess_data.data[idx].uv.xy;\n");
if (hasColor && hasColorTess)
WRITE(p, " _col[i * 4 + j] = tess_data.data[idx].color;\n");
WRITE(p, " }\n");
WRITE(p, " }\n");
// Basis polynomials as weight coefficients
WRITE(p, " vec4 basis_u = tess_weights_u.data[vertex_pos.x].basis;\n");
WRITE(p, " vec4 basis_v = tess_weights_v.data[vertex_pos.y].basis;\n");
if (doSpline) {
WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n");
WRITE(p, " basis_u = vec4(basis_u.yzw, 0);\n");
WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n");
WRITE(p, " basis_v = vec4(basis_v.yzw, 0);\n");
}
// Tessellate
WRITE(p, " vec3 pos = tess_sample(_pos, basis_u, basis_v);\n");
if (doTexture && hasTexcoord) {
if (hasTexcoordTess)
WRITE(p, " vec2 tex = tess_sample(_tex, basis_u, basis_v);\n");
else
WRITE(p, " vec2 tex = normal.xy + vec2(patch_pos);\n");
}
if (hasColor) {
if (hasColorTess)
WRITE(p, " vec4 col = tess_sample(_col, basis_u, basis_v);\n");
else
WRITE(p, " vec4 col = tess_data.data[0].color;\n");
}
WRITE(p, " vec3 worldpos = vec4(tess.pos.xyz, 1.0) * base.world_mtx;\n");
if (hasNormal) {
// Derivatives as weight coefficients
WRITE(p, " vec4 deriv_u = tess_weights_u.data[vertex_pos.x].deriv;\n");
WRITE(p, " vec4 deriv_v = tess_weights_v.data[vertex_pos.y].deriv;\n");
if (doSpline) {
WRITE(p, " if (isFirstEdge.x && isNotFirstPatch.x)\n");
WRITE(p, " deriv_u = vec4(deriv_u.yzw, 0);\n");
WRITE(p, " if (isFirstEdge.y && isNotFirstPatch.y)\n");
WRITE(p, " deriv_v = vec4(deriv_v.yzw, 0);\n");
}
WRITE(p, " vec3 du = tess_sample(_pos, deriv_u, basis_v);\n");
WRITE(p, " vec3 dv = tess_sample(_pos, basis_u, deriv_v);\n");
WRITE(p, " vec3 nrm = cross(du, dv);\n");
WRITE(p, " nrm = normalize(nrm);\n");
}
WRITE(p, " vec3 worldpos = vec4(pos.xyz, 1.0) * base.world_mtx;\n");
if (hasNormal) {
WRITE(p, " mediump vec3 worldnormal = normalize(vec4(%snrm, 0.0) * base.world_mtx);\n", flipNormalTess ? "-" : "");
WRITE(p, " mediump vec3 worldnormal = normalize(vec4(%stess.nrm, 0.0) * base.world_mtx);\n", flipNormalTess ? "-" : "");
} else {
WRITE(p, " mediump vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n");
}
@ -415,9 +432,9 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) {
const char *diffuseStr = ((matUpdate & 2) && hasColor) ? "color0.rgb" : "light.matdiffuse";
const char *specularStr = ((matUpdate & 4) && hasColor) ? "color0.rgb" : "light.matspecular.rgb";
if (doBezier || doSpline) {
ambientStr = (matUpdate & 1) && hasColor ? "col" : "base.matambientalpha";
diffuseStr = (matUpdate & 2) && hasColor ? "col.rgb" : "light.matdiffuse";
specularStr = (matUpdate & 4) && hasColor ? "col.rgb" : "light.matspecular.rgb";
ambientStr = (matUpdate & 1) && hasColor ? "tess.col" : "base.matambientalpha";
diffuseStr = (matUpdate & 2) && hasColor ? "tess.col.rgb" : "light.matdiffuse";
specularStr = (matUpdate & 4) && hasColor ? "tess.col.rgb" : "light.matspecular.rgb";
}
bool diffuseIsZero = true;
@ -538,7 +555,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) {
// Lighting doesn't affect color.
if (hasColor) {
if (doBezier || doSpline)
WRITE(p, " v_color0 = col;\n");
WRITE(p, " v_color0 = tess.col;\n");
else
WRITE(p, " v_color0 = color0;\n");
} else {
@ -559,7 +576,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) {
if (scaleUV) {
if (hasTexcoord) {
if (doBezier || doSpline)
WRITE(p, " v_texcoord = vec3(tex.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n");
WRITE(p, " v_texcoord = vec3(tess.tex.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n");
else
WRITE(p, " v_texcoord = vec3(texcoord.xy * base.uvscaleoffset.xy, 0.0);\n");
} else {
@ -568,7 +585,7 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer) {
} else {
if (hasTexcoord) {
if (doBezier || doSpline)
WRITE(p, " v_texcoord = vec3(tex.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n");
WRITE(p, " v_texcoord = vec3(tess.tex.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n");
else
WRITE(p, " v_texcoord = vec3(texcoord.xy * base.uvscaleoffset.xy + base.uvscaleoffset.zw, 0.0);\n");
} else {