for fun i am trying to make a pure C library for modeling surface-based objects.
as a first simple test i am trying to define a cube, and i am doing it
algorithmically so the faces are described in an inner loop rather
than literally one-by-one like one often sees.
i'm experiencing a lot of inhibition imagining how to plot and index
which neighboring surfaces are adjacent to which edges of which face.
so, i'm spamming it here cause the inhibition increase was pretty
sharp.
bloopa-blrgh!
so first for the cube i define 3 axes, a vector pointing in the
direction of each face.
for each face, 1 axis (or its negation) defines where the face is
located relative to the cube center,
and the other 2 axes (or their negation optionally) define the local
coordinates of that face, basically.
i have a nested loop, for (int axis = 0; axis < 3; ++axis) for (int
sign = -1, sign < 2; sign += 2) that defines 6 unique faces.
so, say the axes are simply <1,0,0>,<0,1,0>,<0,0,1>. in the first
iteration, that means we're doing the -X face, then the +X face. I
could alternatively swap the for loops.
let's make it more intuitive. i'll restructure the loops like so:
for (int sign = 1; sign > -2; sign -= 2) for (int axis = 0; axis < 3; ++axis)
now the loop starts on +X, then does +Y, then +Z, then -X, then -Y, then -Z.
ok, so on the first +X face, the two coordinates for the face will be +Y and +Z.
when i define neighbors of a piecewise object surface, i was thinking
of doing it using a 2x2 multidimensional array ... this was intended
to aid intuition but i've forgotten the meaning of it a bit.
each surface is modeled as having rectangular uv coordinates in the
range [<0,0>,<1,1>].
there are up to 4 neighbors, fewer if a side has 0 length.
so there is a neighbor along <0,0>, <0,1>
and one along <1,0>, <1,1>
these are the two neighbors where U is held constant.
then there is a neighbor along <0,0>,<1,0>
and one along <0,1>, <1,1>
these are the two neighbors where V is held constant
in other words, there is a neighbor in the direction of -V where V=0
and U ranges,
then a neighbor in the direction of +V where V=1 and U ranges,
and a neighbor in the direction of -U where U=0 and V ranges,
and a neighbor in the direction of +U where U=1 and V ranges.
So we could think of the indices in neighbors[2][2] as representing,
is U positive? in the first dimension, and is V positive? in the
second dimension,
so a point at the midpoint of an edge with uv coordinates could select
a neighbor like
neighbors[u > 0.5 ? 1 : 0][v > 0.5 ? 1 : 0].
arrighty ??
now with these square faces, the two other axes would represent the
directions of U and V.
So, with the first square face, the face is centered on X, and U will
be Y, and V will be Z (because the formula is (axis+n)%3).
So in the +U direction, the neighbor will actually _be_ Y. because
going in the direction of Y on any face moves you to the Y face. we're
1/3rd there!!
for the X face, neighbors[1][0] .. wait V has no sign when U is +/-
so this doesn't work:
does not work oops: neighbors[u > 0.5 ? 1 : 0][v > 0.5 ? 1 : 0].
instead we need something like this:
neighbors[dim > U_DIM ? 1 : 0][pt[dim] > 0.5 ? 1 : 0]
one of the indices selects whether we are considering a U or a V neighbor
and the other index selects where it is the positive or the negative neighbor.
so, if we are considering the +U and +Y neighbor of the +X face,+sign
then we would set neighbors[0/*for U axis*/][1/*for positive
direction*/] = &faces[Y_face_idx];
now the way i am calculating Y_face_idx right now is axis + sign * 3
so the idx for the +Y face would be 1 + 1*3
but i gotta fix a bug there because i'm assuming sign ranges [0,1] and
instead it's {-1,1}
uhh i guess that would be (axis*2+(sign+1)*3)/2 or such
but that's kind of complicated, basically i'll be calculating 5/6 of
all the face idcs for every face
i want it more clear to fix bugs while confused
ok so basically i've simplified the problem down to these indices
hmm and it looks like i'm trying to make it succcinct rather than
clear or something...
so what kind of axis changes are there?
- the axis increases by 1 or 2 (mod 3) to find the adjacent faces
- both signs are engaged to find adjacent faces
so basically a sign shifts it by either 3 or 1 depending on storage
axis majority
and the opposite (1 or 3) is true of the axis
that's reasonable. i could have local constants for AXIS_STRIDE and
SIGN_STRIDE and use those :) super clear !
i've started implementing that. i'll write hte time (1940). i also
want to make helper functions
for the surface to set norms for how the neighbor indexing works.
i've got:
int idx = axis*FACE_AXIS_STRIDE+(sign+1)*SIGN_AXIS_STRIDE/2;
i'm thinking i can make a double nested loop to iterate the surface
neighbors, just like the storage
norm. i'll make the helper functions first i guess. unsure what to
call them. 1942
1944 here's my helper to set the norm:
surface** surface_neighbor(surface* sface, int dim_0_or_1, int edge_0_or_1)
{
return &sface->neighbors[dim_0_or_1][edge_0_or_1];
}
hmm i think i'll invert the order of those indices so that memory
locality relates to spacial locality more
1945
hrmmm but then i want to make the implementation order different from
the helper order which
could trip me up later. i'll leave the ordering as-is.
1946
omigod i'm using vim at the same time as gmail and i keep hitting
escape when i am done typing which closes the draft window o_o
1946
good for practicing contextual habit selection
1946 1947
1948 ok i'm calculating the neighbor index based on axis and direction
and i'm confused about it again ummm thought i figured this out
we care about what the axis is of the actual neighbor. so, given what
the _uv_ neighbor axis is, we can calculate the _xyz_ axis by
inverting the existing mapping.
the u axis is specifically set to face axis + 1, and the v axis to
face axis + 2,
so we can add the uv dimension index to the face axis index to get the
neighbor axis index.
1949
1950
ok now the sign of the neighbor axis ...
the u or v can be multiplied by the sign of the face direction or not,
it is up to what makes sense right here. right now it is indeed
multiplied:
surfaces[idx] = square3_new(
add3(position, mul31(axes[axis], sign)),
axes[mul31((axis+1)%3, sign)],
axes[mul31((axis+2)%3, sign)]
);
mul31 is my C functoin for scaling a 3-vector.
looks like i have some bugs there, the axes[] list index should go
inside the mul call, not outside
ok i'll try to fix it
maybe this looks better:
surfaces[idx] = square3_new(
add3(position, mul31(axes[axis], sign)),
mul31(axes[(axis+1)%3], sign),
mul31(axes[(axis+2)%3], sign)
);
ok so i am trying to figure out if the neighbor is on the positive or
negative (locally transformed) XYZ axis, if it is at the positive or
negative UV axis.
if we consider +X as the first face here, we can see that positive U
relates to the positive Y axis.
so the sign i think would be the U sign multiplied by the face sign
it would clearly be simpler if it didn't scale it: then the U sign
would exactly match the axis sign.
i guess i'll remove the mul31s for now and let the internal links
represent the continuity of the surface
oh and it's 1954
1955
here's what i have now:
surfaces[idx] = square3_new(
add3(position, mul31(axes[axis], sign)),
axes[(axis+1)%3],
axes[(axis+2)%3]
);
for (int neighbor_axis = 0; neighbor_axis < 2; ++ neighbor_axis) {
for (int neighbor_dir = 0; neighbor_dir < 2; ++ neighbor_dir) {
int neighbor_idx = (
((axis+neighbor_axis)%3) * FACE_AXIS_STRIDE +
nieghbor_dir * SIGN_AXIS_STRDE
);
implement more here
}
}
1956 i fixed the spelling in nieghbor.
ok so now we have the idx, gotta assign the neighbor pointer to point
to the neighboring surface
1956 1957
whew! that was so hard to try :s
here it is as now, i'm sure there are more bugs to fix that will emerge:
surface ** surface_list = malloc(sizeof(surface*)*6);
pt3 axes[3];
transformationationaxesinto(&axes, orientation_and_size);
// iterate over 6 faces with idcs
// each face has a sign pair, and a direction.
const int FACE_AXIS_STRIDE = 1;
const int FACE_SIGN_STRIDE = 3;
for (int sign = 1; sign > -2; sign -= 2) {
for (int axis = 0; axis < 3; ++ axis) {
int idx = axis*FACE_AXIS_STRIDE+(sign+1)*SIGN_AXIS_STRIDE/2;
surface_list[idx] = &surfaces[idx];
surfaces[idx] = square3_new(
add3(position, mul31(axes[axis], sign)),
axes[(axis+1)%3],
axes[(axis+2)%3]
);
for (int neighbor_axis = 0; neighbor_axis < 2; ++ neighbor_axis) {
for (int neighbor_dir = 0; neighbor_dir < 2; ++ neighbor_dir) {
int neighbor_idx = (
((axis+neighbor_axis)%3) * FACE_AXIS_STRIDE +
neighbor_dir * SIGN_AXIS_STRDE
);
*surface_neighbor(surfaces[idx], neighbor_axis,
neighbor_dir) = surfaces[neighbor_idx];
}
}
// find neighbors maybe !
// 3 axes. opposing axis is not a neighbor.
// all other axes are neighbors, in each direction
// [wow this is hard to think-intend!
}
}