Domain Repetition
Concept
To repeate something, the idea is to find a function that will repeat the coordinate system.
Using non continious function like #mod or #fract are the most easy way but the counterpart is it might generate #artefact. Code
Using uv.x, but can be replaced by higher dimentional vector.
Infinite
code:repetition.glsl
// Using uv.x, but can be expanded to higher dimentional vector
// Simple repetition trick but will have artefact
uv.x = fract(uv.x)-.5;
// Generatlisation
uv.x = mod(uv.x,X)-X/2;
// Smooth repetition
uv.x = asin(sin(uv.x)*.9);
// As function
vec2 smoothrepeat_asin_sin(vec2 p,float smooth_size,float size){
p/=size;
p=asin(sin(p)*(1.0-smooth_size));
return p*size;
}
// IQ Generalization
float opRep( in vec3 p, in vec3 c, in sdf3d primitive )
{
vec3 q = mod(p+0.5*c,c)-0.5*c;
return primitive( q );
}
// From blackle :
vec3 id = floor(p)+.5;
vec3 local_uv = p - id; // Equivalant to fract(uv)-.5 but you can change id to have other cells
Triangle sin repetiton
code:repetition.glsl
vec3 p = asin(sin(p));
// or as explain by wrighter
vec3 p = abs(fract(p)-.5)*4.-1.;
Finite
abs to do a simple repetition on a axe.
code:abs_repetition.glsl
// Simple method
uv.x = abs(uv.x) - .5;
code:clamp_repetition.glsl
// IQ Generalization
vec3 opRepLim( in vec3 p, in float c, in vec3 l, in sdf3d primitive )
{
vec3 q = p-c*clamp(round(p/c),-l,l);
return primitive( q );
}
Avoiding artefact
As already said, using non continuous function like #fract might generate artefact, especially if the element in each grid cell have a different processing, like position based on grid coordinate. One quick explaination why it generates artefact : Let's say we are in a grid at cell <0,0> :
- Step 1 : The ray arrive close to the sphere and is not close to it, so it continues with another loop. Notice that the distance for Step 2 is within the range of the cell coordinate.
- Step 2 : The ray is further that our sphere so it will continue. Notice now, the distance computed go beyond the Cell<0,0> boundaries. It's normal because from the raymarch loop perspective, there is no information about the other Cell<1,0>.
- Step 3: The ray is now on the Cell<1,0>, which could be fine if our sphere was in another place, like at the center of the grid cell. Unfortunatelly, wit hthe current position of the sphere, the raymarch loop is no inside the sphere. It's an overshoot and that's what produce artifact.
https://scrapbox.io/files/64b7807922f87c001cbd0f08.png
To avoid this problem, one idea is to avoid the ray to go "too far" so we reduce the probability to go.
Limit the steps
It could be as simple as having a limit on the step of the marching loop ( min(sdf,LIMIT) ) or reduce the marching step ( sdf=sdf*.7 ) . It's a excellent quick win, but it doesn't solve the problem as it might occurs and it consume more resources as the marching loop will take more time.
Compute the next grid cell
It's also possible to compute the adjacents cells, with the drasw back that it asks to compute the sdf 8 times more.
It's somehow a simpliofication of this part of Art of Code video.
https://youtu.be/3CycKKJiwis?t=1089
Blackle here explains a way to reduce this extra cost to only focus on the next adjacent grid cell.
https://www.youtube.com/watch?v=I8fmkLK1OKg&feature=youtu.be
Repetition article from IQ
Reference
Repetition From 0b5vr
code:glsl
/** Result of the gridTraversal3 */
struct GridTraversal3Result {
/** Center of the cell */
vec3 cell;
/** Distance to the bound */
float dist;
/** Normal of the bound */
vec3 normal;
};
GridTraversal3Result gridTraversal3( vec3 ro, vec3 rd, vec3 size ) {
GridTraversal3Result result;
result.cell = floor( ( ro + rd * 1E-3 ) / size + 0.5 ) * size;
vec3 src = -( ro - result.cell ) / rd;
vec3 dst = abs( 0.5 * size / rd );
vec3 bv = src + dst;
result.dist = min( min( bv.x, bv.y ), bv.z );
result.normal = step( bv, vec3( result.dist ) );
return result;
}
Angular Modulo
code:moda.glsl
void moda (inout vec2 p, float rep)
{
float per = TAU/rep;
// calculate angle in polar coord
float a = atan(p.y,p.x);
// repet the angle
a = mod(a, per)-per*0.5;
// polar to euler coord
p = vec2(cos(a),sin(a))*length(p);
}
https://www.youtube.com/watch?v=2te8heN4CHo&t=701s