[READ-ONLY] Mirror of https://github.com/flo-bit/shapecraft.
flo-bit.dev/shapecraft/
1.7 kB
46 lines
1import type { ColorInput, ColorFn, Vec3 } from '../core/types'
2import { parseColorToRgb, lerpColor } from './utils'
3
4export type GradientStop = [number, ColorInput]
5
6export function gradient(stops: GradientStop[]): (value: number) => [number, number, number] {
7 const sorted = [...stops].sort((a, b) => a[0] - b[0])
8
9 return function sampleGradient(value: number): [number, number, number] {
10 if (sorted.length === 0) return [1, 1, 1]
11 if (value <= sorted[0][0]) return parseColorToRgb(sorted[0][1])
12 if (value >= sorted[sorted.length - 1][0]) return parseColorToRgb(sorted[sorted.length - 1][1])
13
14 for (let i = 0; i < sorted.length - 1; i++) {
15 if (value >= sorted[i][0] && value <= sorted[i + 1][0]) {
16 const t = (value - sorted[i][0]) / (sorted[i + 1][0] - sorted[i][0])
17 return lerpColor(sorted[i][1], sorted[i + 1][1], t)
18 }
19 }
20 return parseColorToRgb(sorted[sorted.length - 1][1])
21 }
22}
23
24export function heightGradient(stops: GradientStop[]): ColorFn {
25 const grad = gradient(stops)
26 return function heightColorFn(position: Vec3): [number, number, number] {
27 return grad(position[1])
28 }
29}
30
31/**
32 * Color based on normal direction — lerps between downColor (facing down)
33 * and upColor (facing up). Useful for vegetation, terrain, etc.
34 */
35export function normalGradient(upColor: ColorInput, downColor: ColorInput): ColorFn {
36 const up = parseColorToRgb(upColor)
37 const down = parseColorToRgb(downColor)
38 return function normalColorFn(_position: Vec3, normal: Vec3): [number, number, number] {
39 const t = normal[1] * 0.5 + 0.5 // -1..1 → 0..1
40 return [
41 down[0] + (up[0] - down[0]) * t,
42 down[1] + (up[1] - down[1]) * t,
43 down[2] + (up[2] - down[2]) * t,
44 ]
45 }
46}