Skip to content

Commit d5cb88e

Browse files
committed
Implement cross-section vertex shader
1 parent e8b467a commit d5cb88e

File tree

1 file changed

+106
-9
lines changed

1 file changed

+106
-9
lines changed
Lines changed: 106 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
shader_type spatial;
22
render_mode skip_vertex_transform;
3-
render_mode unshaded;
3+
// render_mode unshaded;
44

55
// World space
66
// Not allowed to pass matrices through instance uniforms, so have to unpack into vectors.
@@ -10,17 +10,114 @@ instance uniform vec4 modelview_basis_y;
1010
instance uniform vec4 modelview_basis_z;
1111
instance uniform vec4 modelview_basis_w;
1212

13-
uniform vec4 albedo: source_color;
13+
uniform vec4 albedo : source_color;
14+
uniform float grid_size;
15+
16+
varying vec3 uvw;
17+
18+
// Maps from an arbitrary edge index to the indices of the vertices in a tetrahedron [a,b,c,d].
19+
const int TETRAHEDRON_EDGE_TO_VERTEX_MAP[] = {
20+
0, 1,
21+
0, 2,
22+
0, 3,
23+
1, 2,
24+
1, 3,
25+
2, 3
26+
};
27+
// Nonsense abstract lookup table for different cases of vertices above and below the cross-section plane. Derived by
28+
// sketching out 3D tetrahedra and hoping it also worked for 4D (it does).
29+
// 16 cases for number of vertices above and below the cross-section plane, each case leads to at most two triangles for 6 vertices.
30+
// Each triangle in the cross-section is made up of vertices that are interpolated along the edges of the tetrahedron,
31+
// falling where the edge intersetcs the cross-section plane. So this table is 16x6, 16 cases, 6 possible verts,
32+
// each value maps to an edge in the TETRAHEDRON_EDGE_TO_VERTEX_MAP. -1 indicates the vertex is unused for that case.
33+
// General pattern: one vertex above and three below is one triangle on the edges between the one vertex above and the rest,
34+
// one vertex below and three above is same but the winding order is flipped, two above and two below is two triangles in some awful pattern.
35+
// Flipping the bit pattern (i.e. flipping the tetrahedron) reverses the winding order of both triangles.
36+
const int CROSS_SECTION_LOOKUP[] = {
37+
-1, -1, -1, -1, -1, -1, // 0000
38+
0, 1, 2, -1, -1, -1, // 0001
39+
0, 4, 3, -1, -1, -1, // 0010
40+
2, 4, 1, 3, 1, 4, // 0011
41+
1, 3, 5, -1, -1, -1, // 0100
42+
0, 3, 2, 5, 2, 3, // 0101
43+
1, 0, 5, 4, 5, 0, // 0110
44+
2, 4, 5, -1, -1, -1, // 0111
45+
2, 5, 4, -1, -1, -1, // 1000
46+
1, 5, 0, 4, 0, 5, // 1001
47+
0, 2, 3, 3, 2, 5, // 1010
48+
1, 5, 3, -1, -1, -1, // 1011
49+
2, 1, 4, 4, 1, 3, // 1100
50+
0, 3, 4, -1, -1, -1, // 1101
51+
0, 2, 1, -1, -1, -1, // 1110
52+
-1, -1, -1, -1, -1, -1 // 1111
53+
};
54+
55+
int get_face_lookup_index(float w1, float w2, float w3, float w4, int vertex_id) {
56+
// Bitwise ops limit compatibility so summing instead.
57+
int negative1 = w1 < 0.0 ? 1 : 0;
58+
int negative2 = w2 < 0.0 ? 2 : 0;
59+
int negative3 = w3 < 0.0 ? 4 : 0;
60+
int negative4 = w4 < 0.0 ? 8 : 0;
61+
int lookup_index = negative1 + negative2 + negative3 + negative4;
62+
63+
// First index in the group of three that the indicated vertex belongs to.
64+
return (lookup_index * 6) + vertex_id - (vertex_id % 3);
65+
}
66+
67+
vec3 slice_edge(vec4 v1, vec4 v2) {
68+
float mix_weight = v1.w / (v1.w - v2.w);
69+
return mix(v1, v2, mix_weight).xyz;
70+
}
1471

1572
void vertex() {
16-
mat4 modelview_basis = mat4(modelview_basis_x, modelview_basis_y, modelview_basis_z, modelview_basis_w);
17-
// Make an arbitrary triangle from the cell so there's something on the screen.
18-
vec4 position = (VERTEX.x == 1.0 ? CUSTOM0 : (VERTEX.y == 1.0 ? CUSTOM1 : CUSTOM2));
19-
position = (modelview_basis * position) + modelview_origin;
20-
POSITION = PROJECTION_MATRIX * vec4(position.xyz, 1.0);
21-
// TODO actual cross-sectioning
73+
mat4 modelview_basis = mat4(modelview_basis_x, modelview_basis_y, modelview_basis_z, modelview_basis_w);
74+
75+
vec4 verts[] = { CUSTOM0, CUSTOM1, CUSTOM2, CUSTOM3 };
76+
verts[0] = (modelview_basis * verts[0]) + modelview_origin;
77+
verts[1] = (modelview_basis * verts[1]) + modelview_origin;
78+
verts[2] = (modelview_basis * verts[2]) + modelview_origin;
79+
verts[3] = (modelview_basis * verts[3]) + modelview_origin;
80+
81+
vec3 uvws[] = { vec3(UV, COLOR.a), vec3(UV2, VERTEX.y), NORMAL, COLOR.rgb };
82+
83+
int vertex_id = int(VERTEX.x);
84+
int face = get_face_lookup_index(verts[0].w, verts[1].w, verts[2].w, verts[3].w, vertex_id);
85+
if (CROSS_SECTION_LOOKUP[face] == -1) {
86+
// This vertex is unused, cull
87+
POSITION = vec4(0.0, 0.0, CLIP_SPACE_FAR, 1.0);
88+
} else {
89+
int position_edge = CROSS_SECTION_LOOKUP[face + (vertex_id % 3)];
90+
int edge_vert1 = TETRAHEDRON_EDGE_TO_VERTEX_MAP[position_edge * 2];
91+
int edge_vert2 = TETRAHEDRON_EDGE_TO_VERTEX_MAP[(position_edge * 2) + 1];
92+
vec4 position1 = verts[edge_vert1];
93+
vec4 position2 = verts[edge_vert2];
94+
float mix_weight = position1.w / (position1.w - position2.w);
95+
vec4 position = mix(position1, position2, mix_weight);
96+
// Vertex is view space and used for lighting, position is clip space and used for rasterizing.
97+
VERTEX = position.xyz;
98+
POSITION = PROJECTION_MATRIX * vec4(position.xyz, 1.0);
99+
100+
uvw = mix(uvws[edge_vert1], uvws[edge_vert2], mix_weight);
101+
102+
// Compute flat normals.
103+
int face_v1_edge = CROSS_SECTION_LOOKUP[face];
104+
int face_v2_edge = CROSS_SECTION_LOOKUP[face + 1];
105+
int face_v3_edge = CROSS_SECTION_LOOKUP[face + 2];
106+
vec3 face_v1 = slice_edge(verts[TETRAHEDRON_EDGE_TO_VERTEX_MAP[face_v1_edge * 2]], verts[TETRAHEDRON_EDGE_TO_VERTEX_MAP[face_v1_edge * 2 + 1]]);
107+
vec3 face_v2 = slice_edge(verts[TETRAHEDRON_EDGE_TO_VERTEX_MAP[face_v2_edge * 2]], verts[TETRAHEDRON_EDGE_TO_VERTEX_MAP[face_v2_edge * 2 + 1]]);
108+
vec3 face_v3 = slice_edge(verts[TETRAHEDRON_EDGE_TO_VERTEX_MAP[face_v3_edge * 2]], verts[TETRAHEDRON_EDGE_TO_VERTEX_MAP[face_v3_edge * 2 + 1]]);
109+
vec3 normal = normalize(cross(face_v2 - face_v1, face_v3 - face_v1));
110+
vec3 tangent = normalize(face_v2 - face_v1);
111+
vec3 binormal = normalize(cross(normal, tangent));
112+
NORMAL = normal;
113+
TANGENT = tangent;
114+
BINORMAL = binormal;
115+
}
22116
}
23117

24118
void fragment() {
25-
ALBEDO = albedo.rgb;
119+
vec3 uvw_scaled = uvw * 10.0;
120+
int cell = (int(uvw_scaled.x) + int(uvw_scaled.y) + int(uvw_scaled.z)) % 2;
121+
ALBEDO = cell == 0 ? vec3(0.0) : albedo.rgb;
122+
NORMAL = normalize(NORMAL);
26123
}

0 commit comments

Comments
 (0)