使用C語言繪製一個笑臉smile

首先我們繪製一個簡單的例子

#include <math.h>
#include <stdio.h>

int main() {
  double a, b;
  for (b = 1; b >= -1; b -= 0.05, putchar('\n'))
    for (a = -1; a <= 1; a += 0.025)
      putchar(" *"[ a * b + b * b < 1 && fabs(atan2(b, a)) > 0.5 && a * a + pow(b - 0.5, 2) > 0.02]);
}

運行後,可以在控制檯顯示出一個笑臉~~~

# if you do not have gcc, run `brew install gcc` to install 

gcc test1.c && ./a.out
gcc test2.c && ./a.out

然後我們可以循環生成多個笑臉(當然可以再加一個循環生成三重笑臉)

#include <math.h>
#include <stdio.h>

int func(double x, double y, int d) {
  return
    pow(x - 0.5, 2) + pow(y - 0.5, 2) < 0.25 && fabs(atan2(y - 0.5, x - 0.5)) > 0.5 && pow(x - 0.5, 2) + pow(y - 0.75, 2) > 0.005 && (d == 0 || f(fmod(x * 8, 1), fmod(y * 8, 1), d - 1));
}

int main() {
  double x, y;
  for (y = 1; y >= 0; y -= 1.0 / 160.0, putchar('\n'))
    for (x = 0; x <= 1; x += 1.0 / 320.0)
      putchar(" *"[func(x, y, 1)]);
        
}

後面是我們的終極3D笑臉

#include <math.h>
#include "svpng.inc"

typedef struct { float x, y, z; } V;
V make(float x, float y, float z) { V r = { x, y, z }; return r; }
V add(V a, V b) { return make(a.x + b.x, a.y + b.y, a.z + b.z); }
V sub(V a, V b) { return make(a.x - b.x, a.y - b.y, a.z - b.z); }
V mul(V v, float s) { return make(v.x * s, v.y * s, v.z * s); }
float dot(V a, V b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
float len(V v) { return sqrtf(dot(v, v)); };
V cross(V a, V b) { return make(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); }
V norm(V v) { return mul(v, 1.0f / len(v)); }
float min(float a, float b) { return a < b ? a : b; }
float max(float a, float b) { return a > b ? a : b; }

float map(V p) {
  V m1 = { cosf(1), 0, sinf(1) }, m2 = { cosf(1), 0, -sinf(1)};
  return min(max(len(p) - 1.0f, min(dot(p, m1), dot(p, m2))), p.z + 1.0f);
}

V normal(V p) {
  float e = 1e-6f;
  V dx = { e, 0, 0 }, dy = {0, e, 0}, dz = {0, 0, e };
  return norm(make(
    map(add(p, dx)) - map(sub(p, dx)),
    map(add(p, dy)) - map(sub(p, dy)),
    map(add(p, dz)) - map(sub(p, dz))));
}

V albedo(V p) {
  if (p.z + 1 < 1e-4f)
    return make(1, 1, 1); // ground
  else if (p.x * p.x + powf(p.z - 0.5, 2) < 0.02f)
    return make(0, 0, 0); // eye
  else
    return make(1, 1, 0); // main
}

#define S 1024
unsigned char img[S * S * 3], *c = img;

int main() {
  V eye = { 2, 3, 1 }, at = { 0, 0, 0 }, up = { 0, 0, 1 };
  V vz = norm(sub(at, eye)), vx = cross(up, vz), vy = cross(vz, vx);
  int x, y, i;
  for (y = S - 1; y >= 0; y--)
    for (x = 0; x < S; x++, c += 3) {
      float sx = ((float)x / S - 0.5f) * 3.0f;
      float sy = ((float)y / S - 0.5f) * 3.0f;
      V o = add(add(eye, mul(vx, sx)), mul(vy, sy));
      float t = 0;
      do {
        V p = add(o, mul(vz, t));
        float sd = map(p);
        if (sd < 1e-4f) {
          V n = normal(p), alb = albedo(p);
          float ao = 1, s = 0.5f;
          for (i = 1; i < 5; i++) {
            float d = i * 0.1f;
            ao = max(ao - (d - map(add(p, mul(n, d)))) * s, 0.1f);
            s *= 0.95f;
          }
          V r = mul(alb, (dot(n, norm(make(0, 1, 1))) * 0.5f + 0.5f) * ao * 255);
          c[0] = (unsigned char)r.x;
          c[1] = (unsigned char)r.y;
          c[2] = (unsigned char)r.z;
          break;
        }
        t += sd;
      } while (t < 100);
    }
  svpng(fopen("pacman.png", "wb"), S, S, img, 0);
}

是不是很厲害!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章