# 摄像机
# 设置相机位置
#define PI 3.1415926535
#define TMIN 0.1
#define TMAX 20.0
#define RAYMARCH_TIME 128
#define PRECISION .001
vec2 fixUV(in vec2 c) {
return (2. * c - iResolution.xy) / min(iResolution.x, iResolution.y);
}
// 球体的符号距离函数
float sdfSphere(in vec3 p) { return length(p) - .5; }
// 光线步进
float rayMarch(in vec3 ro, in vec3 rd) {
float t = TMIN;
for (int i = 0; i < RAYMARCH_TIME && t < TMAX; i++) {
vec3 p = ro + t * rd; // 步进
float d = sdfSphere(p);
if (d < PRECISION) {
break;
}
t += d;
}
return t;
}
vec3 calcNormal(in vec3 p) {
const float h = 0.0001;
const vec2 k = vec2(1, -1);
return normalize(
k.xyy * sdfSphere(p + k.xyy * h) + k.yyx * sdfSphere(p + k.yyx * h) +
k.yxy * sdfSphere(p + k.yxy * h) + k.xxx * sdfSphere(p + k.xxx * h));
}
// 摄像机
mat3 setCamera(vec3 ta, vec3 ro, float cr) {
vec3 z = normalize(ta - ro);
vec3 cp = vec3(sin(cr), cos(cr), 0.);
vec3 x = normalize(cross(z, cp));
vec3 y = cross(x, z);
return mat3(x, y, z);
}
// 渲染 计算颜色
vec3 render(in vec2 uv) {
vec3 color = vec3(0.);
// 相机位置跟随时间变化
vec3 ro = vec3(2. * cos(iTime), 1., 2. * sin(iTime));
if (iMouse.z > 0.01) {
// 相机位置跟随鼠标位置变化
float theta = iMouse.x * 2. * PI / iResolution.x;
ro = vec3(2. * cos(theta),1., 2. * sin(theta));
}
vec3 light = vec3(1., 2., 0.); // 光源
vec3 ta = vec3(0.);
mat3 cam = setCamera(ta, ro, 0.);
vec3 rd = normalize(cam * vec3(uv, 1.));
float t = rayMarch(ro, rd);
if (t < TMAX) {
vec3 p = ro + t * rd; // 当前位置
vec3 n = calcNormal(p); // 法向量
float dif = clamp(dot(normalize(light - p), n), 0., 1.);
float amb = .5 + .5 * dot(n, vec3(0., 1., 0.)); // 环境光
color = amb * vec3(.25, .25, .25) + dif * vec3(1.); // 叠加
}
return color;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fixUV(fragCoord);
vec3 color = render(uv);
fragColor = vec4(color, 1.); // rgba
}