7 Vec3
mix() (in auto ref Vec3 v0
, in auto ref Vec3 v1
, RmFloat t
) {
9 immutable RmFloat t1
= rmFloat
!1.0-t
;
18 RmFloat
mix() (RmFloat v0
, RmFloat v1
, RmFloat a
) {
20 immutable RmFloat t1
= rmFloat
!1.0-t
;
25 // hermite interpolation
26 RmFloat
smoothstep() (RmFloat edge0
, RmFloat edge1
, RmFloat x
) {
27 static if (__VERSION__
> 2067) pragma(inline
, true);
28 immutable RmFloat t
= clamp((x
-edge0
)/(edge1
-edge0
), rmFloat
!0.0, rmFloat
!1.0);
29 return t
*t
*(rmFloat
!3.0-rmFloat
!2.0*t
);
33 RmFloat
clamp() (RmFloat x
, RmFloat minv
, RmFloat maxv
) {
34 //pragma(inline, true);
35 import std
.algorithm
: min
, max
;
36 return max(min(x
, maxv
), minv
);
40 RmFloat
fract() (RmFloat x
) {
41 //pragma(inline, true);
42 import std
.math
: floor
;
48 RmFloat
mod() (RmFloat x
, RmFloat y
) {
49 //pragma(inline, true);
50 import std
.math
: floor
;
51 // x minus the product of y and floor(x/y)
52 return x
-y
*floor(x
/y
);
56 // ////////////////////////////////////////////////////////////////////////// //
57 // raymarch composition functions
59 RmFloat
objopRep(string objfunc
) (in auto ref Vec3 pp
, in auto ref Vec3 c
) {
60 static if (__VERSION__
> 2067) pragma(inline
, true);
61 // the following MUST be `p`
62 immutable auto p
= Vec3(mod(p
.x
, c
.x
), mod(p
.y
, c
.y
), mod(p
.z
, c
.z
))-c
*rmFloat
!0.5;
63 return mixin(objfunc
);
66 RmFloat
objopScale(string objfunc
) (in auto ref Vec3 pp
, RmFloat s
) {
67 static if (__VERSION__
> 2067) pragma(inline
, true);
68 immutable auto p
= pp
/s
;
69 return mixin(objfunc
)*s
;
72 RmFloat
objopShift(string objfunc
) (in auto ref Vec3 pp
, in auto ref Vec3 sv
) {
73 static if (__VERSION__
> 2067) pragma(inline
, true);
74 immutable auto p
= pp
+sv
;
75 return mixin(objfunc
);
78 // rotation/translation
80 Vec3 objopTx(string objfunc) (in auto ref Vec3 pp, in auto ref Mat4 mt) {
81 immutable auto p = m.invert*pp;
82 return mixin(objfunc);
86 RmFloat
objopUnion() (RmFloat obj0
, RmFloat obj1
) {
87 static if (__VERSION__
> 2067) pragma(inline
, true);
88 return (obj0
< obj1 ? obj0
: obj1
); // min
91 RmFloat
objopSub() (RmFloat a
, RmFloat b
) {
92 static if (__VERSION__
> 2067) pragma(inline
, true);
93 return (a
> -b ? a
: -b
);
97 RmFloat
objopInter() (RmFloat a
, RmFloat b
) {
98 static if (__VERSION__
> 2067) pragma(inline
, true);
99 return (obj0
> obj1 ? obj0
: obj1
); // max
102 // returns object number
103 int objopUnion() (ref RmFloat dest
, RmFloat obj0
, RmFloat obj1
, int oid0
, int oid1
) {
104 static if (__VERSION__
> 2067) pragma(inline
, true);
114 // returns object number
115 int objopSub() (ref RmFloat dest
, RmFloat a
, RmFloat b
, int oid0
, int oid1
) {
116 static if (__VERSION__
> 2067) pragma(inline
, true);
127 // returns object number
128 int objopInter() (ref RmFloat dest
, RmFloat obj0
, RmFloat obj1
, int oid0
, int oid1
) {
129 static if (__VERSION__
> 2067) pragma(inline
, true);
140 // ////////////////////////////////////////////////////////////////////////// //
141 // raymarch composition functions that doesn't preserve distance
142 // you will probably need to decrease your step size, if you are using a raymarcher to sample this
143 // the displacement example below is using sin(20*p.x)*sin(20*p.y)*sin(20*p.z) as displacement pattern
145 RmFloat objopDisplace(string objfunc) (in auto ref Vec3 p) {
146 RmFloat d1 = mixin(objfunc);
147 RmFloat d2 = displacement(p);
153 // exponential smooth min (k = 32);
154 RmFloat
sminExp (RmFloat a
, RmFloat b
, RmFloat k
) {
155 import std
.math
: exp
, log
;
156 RmFloat res
= exp(-k
*a
)+exp(-k
*b
);
160 // power smooth min (k = 8);
161 RmFloat
sminPow (RmFloat a
, RmFloat b
, RmFloat k
) {
162 import std
.math
: pow
;
165 return pow((a
*b
)/(a
+b
), rmFloat
!1.0/k
);
168 // polynomial smooth min (k = 0.1);
170 RmFloat sminPoly (RmFloat a, RmFloat b, RmFloat k) {
171 import std.math : clamp, exp, log;
172 RmFloat h = clamp(rmFloat!0.5+rmFloat!0.5*(b-a)/k, rmFloat!0.0, rmFloat!1.0);
173 return mix(b, a, h)-k*h*(rmFloat!1.0-h);
177 RmFloat
objopBlend(alias sminfn
, string objfunc0
, string objfunc1
) (in auto ref Vec3 p
) {
178 RmFloat d1
= mixin(objfunc0
);
179 RmFloat d2
= mixin(objfunc1
);
180 return sminfn(d1
, d2
);
184 RmFloat
objopTwist (string objfunc
) (in auto ref Vec3 pp
) {
185 import std
.math
: cos
, sin
;
186 immutable RmFloat c
= cos(rmFloat
!10.0*pp
.z
+rmFloat
!10.0);
187 immutable RmFloat s
= sin(rmFloat
!10.0*pp
.z
+rmFloat
!10.0);
188 //immutable auto m = Mat2(c, -s, s, c);
196 // multiple matrix2 by vector2
197 //immutable auto p = Vec3(m*p.xz, p.y);
199 RmFloat v2x = mm.ptr[0].ptr[0]*pp.x+mm.ptr[0].ptr[1]*pp.z;
200 RmFloat v2y = mm.ptr[1].ptr[0]*pp.x+mm.ptr[1].ptr[1]*pp.z;
202 RmFloat v2x
= c
*pp
.x
-s
*pp
.y
;
203 RmFloat v2y
= s
*pp
.x
+c
*pp
.y
;
204 immutable auto p
= Vec3(v2x
, v2y
, pp
.z
);
205 return mixin(objfunc
);
209 // ////////////////////////////////////////////////////////////////////////// //
210 import std
.algorithm
: maxf
= max
, minf
= min
;
212 // raymarch object functions
213 // as our functions are very simple, use strings and `mixin` to simulate inlining ;-)
214 enum floorHeight
= rmFloat
!2.0;
215 enum objfuncFloor
= q
{(p
.y
+floorHeight
)};
217 // n must be normalized (invalid formula, broken by k8)
218 static immutable planeN
= Vec3(rmFloat
!0.0, rmFloat
!0.0, rmFloat
!0.0);
219 enum planeD
= rmFloat
!12.0;
220 enum objfuncPlane
= q
{(p
.dot(planeN
)+planeD
)};
222 enum torusOuterRadius
= rmFloat
!2.4;
223 enum torusRadius
= rmFloat
!0.6;
224 enum objfuncTorus
= q
{(Vec3
.length(p
.length
-torusOuterRadius
, p
.z
)-torusRadius
)};
227 enum shpereRadius
= rmFloat
!1.9;
228 enum objfuncSphere
= q
{(p
.length
-shpereRadius
)};
230 // round box, unsigned
231 static immutable roundboxSize
= Vec3(rmFloat
!2.0, rmFloat
!0.7, rmFloat
!2.0);
232 enum roundboxRadius
= rmFloat
!0.2;
233 enum objfuncRoundbox
= q
{((p
.abs
-roundboxSize
).minmax
!"max"(rmFloat
!0.0).length
-roundboxRadius
)};
235 // box, signed (interestingly, this is more complex than round box ;-)
236 static immutable boxSize
= Vec3(rmFloat
!2.0, rmFloat
!0.7, rmFloat
!2.0);
237 __gshared Vec3 boxTemp
;
238 enum objfuncBox
= q
{(boxTemp
= p
.abs
-boxSize
, minf(maxf(boxTemp
.x
, maxf(boxTemp
.y
, boxTemp
.z
)), rmFloat
!0.0)+boxTemp
.minmax
!"max"(rmFloat
!0.0).length
)};
241 static immutable boxuSize
= Vec3(rmFloat
!2.0, rmFloat
!0.7, rmFloat
!2.0);
242 enum objfuncBoxu
= q
{((p
.abs
-boxuSize
).minmax
!"max"(rmFloat
!0.0).length
)};
245 static immutable cylParams
= Vec3(rmFloat
!0.0, rmFloat
!0.0, rmFloat
!0.6); // x, y, width
246 enum objfuncCyl
= q
{(Vec3
.length(p
.x
-cylParams
.x
, p
.z
-cylParams
.y
)-cylParams
.z
)};