How to draw a "Christmas tree" in C language, I use the left and right mirror Sierpinski triangle, each layer minus a small block, and then dotted with symbols. A "Christmas tree" can produce different layers, as shown in the 5-layer result
#include <stdlib.h>
int main (int argc, char* argv[]) {
int n = argc > 1 atoi (argv[1]): 4;
for (int j = 1; J <= N; j +) {
int s = 1 << j, k = (1 << N)-S, x;
for (int y = s-j y >= 0; y--, putchar (' \ n ')) {for
(x = 0; x < y + K; + +) printf ("");
for (x = 0; x + y < s + x) printf ("%c", '! ' ^ y & x);
for (x = 1; x + y < s + +) printf ("%c", '! ' ^ Y & (S-y-x-1));
}
}
The basic code comes from the implementation of the Sierpinski triangle, and the idea of the character comes from the code golf-draw A Sierpinski triangle.
Update 1: The above is I try to use the least code to draw an abstract point of the Christmas tree, so the trunk is not. Then, I try to use a more realistic style. Because the tree is a relatively self-similar shape, this time using recursion to describe the trunks and branches.
n = 0, is to draw only one main trunk, the more the trunk of the higher the longer:
n = 1, using recursion to draw to both sides of the branch, rotate, the higher the portion shrinks smaller.
n = 2, it continues to divide into more fine-grained tree branches. n = 2, it continues to divide into more fine-grained tree branches.
n = 3 is almost enough detail. n = 3 is almost enough detail.
The code is a bit longer, so I don't "compress" it for easy understanding.
#include <math.h> #include <stdio.h> #include <stdlib.h> #define PI 3.14159265359 float sx, SY;
float sdcircle (float px, float py, float r) {Float dx = px-sx, dy = py-sy;
return sqrtf (DX * dx + dy * dy)-r;
float opunion (float d1, float D2) {return D1 < D2? D1:d2;} #define T px + scale * R * COSF (theta), py + scale * r * sin (theta) float f (float px, float py, float theta, float scale,
int n) {float d = 0.0f;
for (float r = 0.0f; r < 0.8f; R + + 0.02f) d = opunion (d, Sdcircle (T, 0.05f * scale * (0.95F-R)));
if (n > 0) for (int t =-1; t <= 1; t + + 2) {Float TT = theta + T * 1.8f;
float SS = scale * 0.9F;
for (float r = 0.2f; r < 0.8f; R + + 0.1f) {d = opunion (d, F (T, TT, SS * 0.5f, n-1));
SS *= 0.8f;
} return D;
int main (int argc, char* argv[]) {int n = argc > 1 atoi (argv[1]): 3; for (sy = 0.8f; sy > 0.0f; SY-= 0.02f, Putchar (' \ n ')) for (sx = -0.35f; SX < 0.35f; SX + + 0.01f) Putchar (f (0, 0, PI * 0.5f, 1.0f, N) < 0?
'*' : ' ');
}
This code is actually modeled with a circular distance field and is not optimized. This is a "naked tree", which could not be called "Christmas Tree".
Update 2: simply add the decorations and ribbons, the command line can choose magnification, the following figure is twice times larger.
//f () and the previous section along the upper int ribbon () {float x = (FMODF (sy, 0.1f)/0
.1f-0.5f) * 0.5f;
return SX >= x-0.05f && SX <= x + 0.05f;
int main (int argc, char* argv[]) {int n = argc > 1 atoi (argv[1]): 3; FLOAT zoom = argc > 2?
Atof (argv[2]): 1.0f; for (sy = 0.8f; sy > 0.0f; SY-= 0.02f/zoom, Putchar (' \ n ')) for (SX = -0.35f; sx < 0.35f; SX + = 0.01f/zoom)
{if (f (0, 0, PI * 0.5f, 1.0f, N) < 0.0f) {if (Sy < 0.1f) Putchar ('. ');
else {if (Ribbon ()) putchar (' = ');
else Putchar ("..... .............., ... #j &o" [rand ()% 32]);
} else Putchar ('); }
}
I think it's almost 2d. Next see if there is no time to try 3D.
Update 3: It's finally going to be a. Before each node is to the left and right branches, in three-dimensional we can be more free, I try to 6 branches in each node. Finally, a simple Lambertian shader (i.e. max (dot (N, L), 0) is used.
n = 1 is easier to see three-dimensional coloring:
But the n=3 was so messy that it was hard to discern:
It is estimated that it was made by aliasing. Because the illumination has already used the finite difference to calculate the normal, the performance is very poor, I no longer try to do supersampling to solve the aliasing problem. In addition, ambient occlusion may help with the problem, but more samples are needed.
Because the need for three-dimensional rotation, can not be as simple as two-dimensional use of an angle to represent rotation, so this code added a lot of matrix operations. Of course, it's OK to use a four dollar number.
#include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define PI 3.141592
65359f float SX, SY;
typedef float MAT[4][4];
typedef float VEC[4];
void scale (mat* m, float s) {Mat temp = {{s,0,0,0}, {0,s,0,0}, {0,0,s,0}, {0,0,0,1}};
memcpy (M, &temp, sizeof (Mat));
} void Rotatey (mat* m, float t) {float c = COSF (t), S = sinf (t);
Mat temp = {{c,0,s,0}, {0,1,0,0}, {-s,0,c,0}, {0,0,0,1}};
memcpy (M, &temp, sizeof (Mat));
} void Rotatez (mat* m, float t) {float c = COSF (t), S = sinf (t);
Mat temp = {{c,-s,0,0}, {s,c,0,0}, {0,0,1,0}, {0,0,0,1}};
memcpy (M, &temp, sizeof (Mat));
} void Translate (mat* m, float x, float y, float z) {Mat temp = {{1,0,0,x}, {0,1,0,y}, {0,0,1,z}, {0,0,0,1}};
memcpy (M, &temp, sizeof (Mat));
} void Mul (mat* m, Mat A, Mat b) {Mat temp;
for (int j = 0; J < 4; J +) for (int i = 0; i < 4; i++) {temp[j][i] = 0.0f;
for (int k = 0; k < 4; k++) Temp[j][i] + = a[j][k] * B[k][i];
memcpy (M, &temp, sizeof (Mat));
} void Transformposition (vec* R, Mat m, Vec v) {Vec temp = {0, 0, 0, 0};
for (int j = 0; J < 4; J +) for (int i = 0; i < 4; i++) Temp[j] + = m[j][i] * V[i];
memcpy (R, &temp, sizeof (VEC));
Float Transformlength (Mat m, float r) {return sqrtf (m[0][0] * m[0][0] + m[0][1] * m[0][1] + m[0][2] * m[0][2)) * R;
Float sphere (Vec C, float r) {Float dx = c[0]-sx, DY = c[1]-sy;
float a = dx * dx + dy * dy; Return a < R * r?
Sqrtf (R * r-a) + c[2]: -1.0f;
Float opunion (float z1, float z2) {return z1 > z2? z1:z2;}
Float f (Mat m, int n) {float z = -1.0f;
for (float r = 0.0f; r < 0.8f; R + + 0.02f) {Vec v = {0.0f, R, 0.0f, 1.0f};
Transformposition (&v, M, v);
z = opunion (z, Sphere (V, transformlength (M, 0.05f * (0.95F-R)));
} if (n > 0) {Mat ry, RZ, S, T, M2, M3;
Rotatez (&rz, 1.8f); for (int p = 0; p< 6;
p++) {Rotatey (&ry, p * (2 * PI/6));
Mul (&m2, Ry, RZ);
float SS = 0.45f;
for (float r = 0.2f; r < 0.8f; R + + 0.1f) {scale (&s, SS);
Translate (&t, 0.0f, R, 0.0f);
Mul (&m3, S, m2);
Mul (&M3, T, M3);
Mul (&M3, M, M3);
z = opunion (z, F (M3, n-1));
SS *= 0.8f;
}} return Z;
float F0 (float x, float y, int n) {sx = x;
sy = y;
Mat m;
Scale (&m, 1.0f);
Return f (m, n);
int main (int argc, char* argv[]) {int n = argc > 1 atoi (argv[1]): 3; FLOAT zoom = argc > 2?
Atof (argv[2]): 1.0f; for (float y = 0.8f; y > -0.0f y-= 0.02f/zoom, Putchar (' \ n ')) for (float x = -0.35f; x < 0.35f; x = 0.01f/
Zoom) {Float z = F0 (x, y, N);
if (Z > -1.0f) {float NZ = 0.001f;
float NX = F0 (x + NZ, y, n)-Z;
float NY = F0 (x, y + NZ, n)-Z;
float nd = SQRTF (NX * NX + NY * NY + NZ * NZ); Float D = (nx-ny + NZ)/SQRTF (3)/ND; D = d > 0.0f?
d:0.0f; D = d < 1.0f?
d:1.0f;
Putchar (".-:=+*#%@@" [(int) (d * 9.0f)]);
else Putchar (');
}
}
Update 4: the previous transformlength () was incorrectly written and corrected. In addition, consider lifting performance, it is generally necessary to some space split way to speed up the inspection, but here is just a tree-like scene structure, you can simply use bounding volume hierarchy, I used the sphere as a bounding volume. With just a few words of code, you can dramatically reduce the running time.
In addition, considering that too small blades are difficult to sample to get good results, I try to show the blades with a larger sphere (as in the sketch when considering the darker light of the whole rather than the light of each blade), I think the results are progressing.
Float f (Mat m, int n) {
//culling
{
Vec v = {0.0f, 0.5f, 0.0f, 1.0f};
Transformposition (&v, M, v);
if (Sphere (V, transformlength (M, 0.55f)) = = -1.0f)
return-1.0f;
}
float z = -1.0f;
if (n = = 0) {//Leaf
Vec v = {0.0f, 0.5f, 0.0f, 1.0f};
Transformposition (&v, M, v);
z = Sphere (V, transformlength (M, 0.3f));
}
else {//Branch
for (float r = 0.0f; r < 0.8f; R + + 0.02f) {
Vec v = {0.0f, R, 0.0f, 1.0f};
Transformposition (&v, M, v);
z = opunion (z, Sphere (V, transformlength (M, 0.05f * (0.95F-R))));
}
// ...
}
In fact, when I answered this question, I did not have a plan, but I tried it step-by-step. Now I think the code with this size probably can't make any progress. But today I saw the Christmas tree in the lobby, I think those decorations are still 挻 interesting, sometimes in addition to painting the whole, you can also draw part to see if it can be updated.
Merry Christmas!