# @davepagurek/glsl-autodiff 中文文档

规范地址：https://npmcn.com/package/%40davepagurek/glsl-autodiff/

版本：0\.0\.20
npm 元数据更新时间：2023-06-09T17:47:29.610Z
中文译文更新时间：2026-11-12T06:22:58.770Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40davepagurek/glsl-autodiff
原文对照：https://npmcn.com/package/%40davepagurek/glsl-autodiff/?lang=original
项目主页：https://github.com/davepagurek/glsl-autodiff
源码仓库：https://github.com/davepagurek/glsl-autodiff

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：88.7 kB，13 个文件
- 模块格式：CommonJS
- TypeScript 类型：包内自带
- 运行依赖：1 个
- 首次发布：2021-07-09T15:39:46.752Z
- 最新版本发布：2023-06-09T17:47:29.507Z
- 近 30 天下载量：2780（2026-10-12 至 2026-11-10，npm 官方下载统计）
- 已发布版本数：20（近 12 个月 0 个）

## 中文简介

厌倦了做数学 让你的顶点遮平正常? 同样的。 使用此库来写入您的函数一次并自动生成衍生出!

## 安装

```sh
npm install @davepagurek/glsl-autodiff
```

也可以使用：`pnpm add @davepagurek/glsl-autodiff`、`yarn add @davepagurek/glsl-autodiff`、`bun add @davepagurek/glsl-autodiff`

## README

# glsl- 自定义

厌倦了做数学 让你的顶点遮平正常? 同样的。 使用此库来写入您的函数一次并自动生成衍生出!

-   [演示](https://npmcn.com/package/%40davepagurek/glsl-autodiff/#readme-demo)
    -   [启动码](https://npmcn.com/package/%40davepagurek/glsl-autodiff/#readme-starter-code)
-   [为什么?](https://npmcn.com/package/%40davepagurek/glsl-autodiff/#readme-why)
-   [API 使用量](https://npmcn.com/package/%40davepagurek/glsl-autodiff/#readme-api-usage)
    -   [投入和产出](https://npmcn.com/package/%40davepagurek/glsl-autodiff/#readme-inputs-and-outputs)
    -   [业务](https://npmcn.com/package/%40davepagurek/glsl-autodiff/#readme-operations)
    -   [其他设置](https://npmcn.com/package/%40davepagurek/glsl-autodiff/#readme-additional-settings)
    -   [进口JS/TS](https://npmcn.com/package/%40davepagurek/glsl-autodiff/#readme-importing-in-jsts-builds)
    -   [在浏览器中导入](https://npmcn.com/package/%40davepagurek/glsl-autodiff/#readme-importing-in-the-browser)
-   [捐款](https://npmcn.com/package/%40davepagurek/glsl-autodiff/#readme-contributing)

## 演示

![airplane-small](https://user-images.githubusercontent.com/5315059/129101559-4f394a4c-ea3d-489f-9796-cff224aa277d.gif)

[P5 编辑器中的活版](https://editor.p5js.org/davepagurek/sketches/sQZGnfyKt)

### 启动码

| 自动diff + 球形映射照明 | 自动diff + 球形映射照明 + 凸起映射 |
| --- | --- |
| [P5 编辑器模板](https://editor.p5js.org/davepagurek/sketches/PN4MnpC15) | [P5 编辑器模板](https://editor.p5js.org/davepagurek/sketches/hJEHTTXUN) |
| [代码模板](https://codepen.io/pen/?template=BaRbezz) | [代码模板](https://codepen.io/pen/?template=poPYmda) |

## 为什么?

有时候,我想取代 网状顶点在一个顶点的阴影。 这样做之后,一地表的常态应该改变:

![image](https://user-images.githubusercontent.com/5315059/129100445-7f48da08-df0f-4fd8-a5c5-16e169197ce4.png)

然而,每个顶点的常态不会自动更新! 手动更新顶点常态需要您接受位移函数的衍生. 这个库将这个过程自动化,这样可以减少时间,并减少用户出错的可能性. 如果你感兴趣,读 [更深入的博客文章](https://www.davepagurek.com/blog/realtime-deformation/) 说明为什么有必要这样做和如何运作.

## API 使用量

这暴露了一个 `gen` 函数生成 GLSL ,您可以在阴影码中切入。 在电话里 `gen()`,您提供了一个召回 收录 `ad`,AutoDiff引擎,并用来构建阴影码. 我们通过制作一个操作图来建立遮蔽器,我们通过该图输入实现产出。 每个函数调用都会创建代表此操作的对象. 一旦有了图表,我们就可以使用它自动计算出衍生物!

AutoDiff 引擎的方法设计类似您通常会如何写出一个阴影器,但使用方法链路而不是操作员符号,类似于如何写 [p5的矢量类作品.](https://p5js.org/reference/#/p5.Vector) 它看起来像这样的行动:

```js
import { gen } from `@davepagurek/glsl-autodiff'

const vert = `
void main(void) {
  vec4 objSpacePosition = vec4(aPosition, 1.0);

  float x = objSpacePosition.x;
  float y = objSpacePosition.y;
  ${gen((ad) => {
    const x = ad.param('x')
    const y = ad.param('y')
    const time = ad.param('time')
    const speedX = 1.5
    const speedY = 2.8

    let offset = ad.val(0)
    for (let i = 0; i < 3; i++) {
      offset = offset.add(ad.sin(
        ad.sum(
          offset.mult(0.5).add(x.mult(speedX)).add(y.mult(speedY)),
          time.mult(0.002),
        )
      ))
    }
    offset = offset.mult(0.1)
    offset.output('z')
    offset.outputDeriv('dzdx', x)
    offset.outputDeriv('dzdy', y)
  })}
  objSpacePosition.z = z;
  vec3 slopeX = vec3(1.0, 0.0, dzdx);
  vec3 slopeY = vec3(0.0, 1.0, dzdy);
  vNormal = uNormalMatrix * normalize(cross(slopeX, slopeY));

  vec4 worldSpacePosition = uModelViewMatrix * objSpacePosition;
  gl_Position = uProjectionMatrix * worldSpacePosition;
}
`
```

### 投入和产出

**参数** 是您在 AutoDiff 外部创建的变量,但是您想要在 AutoDiff 内部引用的变量。 根据其可变类型,采用以下方法之一来创建: 1

```typescript
interface AutoDiff {
  param(name: string): Param
  vec2Param: (name: string) => VecParam
  vec3Param: (name: string) => VecParam
  vec4Param: (name: string) => VecParam
}
```

**产出** 用于将AutoDiff内部的计算结果存储到AutoDiff外部可访问的名称。 还可以输出一个输入参数的计算衍生物.

```typescript
interface Op {
  output(name: string);
  outputDeriv(name: string, param: Param);
}
```

举例来说,我们可以使用 `param` 引用一个制服,用它做一些数学,并输出结果:

```js
const vert = `
// A uniform we want to reference
uniform vec3 position;

void main(void) {
  ${AutoDiff.gen((ad) => {
    // Get a computation graph node representing the uniform
    const position = ad.vec3Param('position')
    
    // Do stuff with it
    const offset = ad.sum(position.x(), position.y(), position.z())
    
    // Output it so the rest of the shader can reference it
    offset.output('offset')
  })}
  vec3 worldSpacePosition = position;
  worldSpacePosition.z += offset; // Use offset, an output, outside of AutoDiff
  gl_Position = uProjectionMatrix * vec4(worldSpacePosition, 1.0);
}
`
```

### 业务

考虑到任何平面图节点(`Op`),使用以下任何方法生成一个与同名GLSL操作相应的新节点:

```typescript
interface Op {
  neg(): Op; // Multiply by -1
  add(...params: Input[]): Op;
  sub(val: Input): Op;
  mult(...params: Input[]): Op;
  div(param: Input): Op;
  pow(param: Input): Op;
  sqrt(): Op;
  sin(): Op;
  cos(): Op;
  tan(): Op;
  mix(b: Input, amt: Input): Op;
  clamp(min: Input, max: Input): Op;
  min(...params: Input[]): Op;
  max(...params: Input[]): Op;
  ifElse(thenOp: Input, elseOp: Input): Op; // Ternary with the receiving Op being the condition
  vecIfElse(thenOp: VectorOp, elseOp: VectorOp): VectorOp; // Ternary but where the if/else values are vectors
}
```

说明a `Input` 要么是另一个节点,要么是数字字形.

给定矢量图形节点( Q)`VectorOp`,扩展 `Op`),使用下列任何方法再次生成一个带有计算结果的新节点:

```typescript
interface VectorOp {
  neg(): VectorOp;
  add(...params: VectorOp[]): VectorOp;
  scale(k: Input): VectorOp; // When multiplying by a scalar
  mult(...params: VectorOp[]): VectorOp; // When multiplying by another vector
  mix(other: VectorOp, amt: Input): VectorOp;
  clamp(min: VectorOp, max: VectorOp): VectorOp;
  min(...params: VectorOp[]): VectorOp;
  max(...params: VectorOp[]): VectorOp;
  dot(other: VectorOp): Op;
  length(): Op;
  dist(other: VectorOp): Op;
}
```

您也可以直接从自动编辑器的引擎中构造节点 `gen` 回调 :

```typescript
interface AutoDiff {
  // Create new values
  val: (n: number) => Op;
  vec2: (x: Input, y: Input) => Vec;
  vec3: (x: Input, y: Input, z: Input) => Vec;
  vec4: (x: Input, y: Input, z: Input, w: Input) => Vec;

  // Create a new operation with scalar inputs
  sum: (...params: Input[]) => any;
  prod: (...params: Input[]) => any;
  sqrt: (param: Input) => any;
  sin: (input: Input) => any;
  cos: (input: Input) => any;
  tan: (input: Input) => any;
  mix: (a: Input, b: Input, amt: Input) => any;
  clamp: (val: Input, min: Input, max: Input) => any;
  min: (...params: Input[]) => any;
  max: (...params: Input[]) => any;
  ifElse: (ifOp: Input, thenOp: Input, elseOp: Input) => any;
  
  // Create a new operation with vector inputs
  vecSum: (...params: VectorOp[]) => VectorOp;
  vecProd: (...params: VectorOp[]) => VectorOp;
  vecMix: (a: VectorOp, b: VectorOp, amt: Input) => VectorOp;
  vecClamp: (val: VectorOp, min: VectorOp, max: VectorOp) => VectorOp;
  vecMin: (...params: VectorOp[]) => VectorOp;
  vecMax: (...params: VectorOp[]) => VectorOp;
  dot: (a: VectorOp, b: VectorOp) => Op;
  length: (val: VectorOp) => Op;
  dist: (a: VectorOp, b: VectorOp) => Op;
}
```

### 其他设置

在极罕见的场合, 你写代码 Just WorksTM! 对于另外99%的时间, AutoDiff 包含调试选项, 您可以通过将额外的设置对象传递到 `gen` 函数 :

```typescript
gen: (
  cb: (ad: AD) => void,
  settings?: Partial<ADSettings>,
) => string;

type ADSettings = {
  maxDepthPerVariable: number;
  debug: boolean;
};
```

当你准备好 `debug: true`,在输出的 GLSL 中,每行直接来自您所写的代码,就会得到一个注释引用,其来源是:

| 投入 | 产出 |
| --- | --- |
| 
const vert = \`
void main(void) {
  vec4 objSpacePosition = vec4(aPosition, 1.0);
  float origZ = objSpacePosition.z;
  float x = objSpacePosition.x;
  float y = objSpacePosition.y;
  ${AutoDiff.gen((ad) => {
    const x = ad.param('x')
    const y = ad.param('y')
    const time = ad.param('time')
    const speedX = 1.5
    const speedY = 2.8

```
let offset = ad.val(0)
for (let i = 0; i < 3; i++) {
  offset = offset.add(ad.sin(
    ad.sum(
      offset.mult(0.5).add(x.mult(speedX)).add(y.mult(speedY)),
      time.mult(0.002),
    )
  ))
}
offset = offset.mult(0.1)
offset.output('z')
```

}, { debug: true, maxDepthPerVariable: 4 })}
objSpacePosition.z += z;
vec4 worldSpacePosition = uModelViewMatrix \* objSpacePosition;
gl\_Position = uProjectionMatrix \* worldSpacePosition;
}
\`

 | 

void main(void) {
  vec4 objSpacePosition = vec4(aPosition, 1.0);
  float origZ = objSpacePosition.z;
  float x = objSpacePosition.x;
  float y = objSpacePosition.y;

// From vert<@file:///Users/dpagurek/Documents/Projects/glsl-autodiff/test/sine\_plane/test.js:31:12
float \_glslad\_v14=(((0.0000\*0.5000)+(x\*1.5000))+(y\*2.8000))+(time\*0.0020);

// From vert<@file:///Users/dpagurek/Documents/Projects/glsl-autodiff/test/sine\_plane/test.js:30:23
float \_glslad\_v16=0.0000+(sin(\_glslad\_v14));

// From vert<@file:///Users/dpagurek/Documents/Projects/glsl-autodiff/test/sine\_plane/test.js:31:12
float \_glslad\_v27=(((\_glslad\_v16\*0.5000)+(x\*1.5000))+(y\*2.8000))+(time\*0.0020);

// From vert<@file:///Users/dpagurek/Documents/Projects/glsl-autodiff/test/sine\_plane/test.js:30:23
float \_glslad\_v29=\_glslad\_v16+(sin(\_glslad\_v27));

// From vert<@file:///Users/dpagurek/Documents/Projects/glsl-autodiff/test/sine\_plane/test.js:31:12
float \_glslad\_v40=(((\_glslad\_v29\*0.5000)+(x\*1.5000))+(y\*2.8000))+(time\*0.0020);
float z=((\_glslad\_v29+(sin(\_glslad\_v40)))\*0.1000);

objSpacePosition.z += z;
vec4 worldSpacePosition = uModelViewMatrix \* objSpacePosition;
gl\_Position = uProjectionMatrix \* worldSpacePosition;
}

 |

有时太过或太少 最终在一线,所以你也可以供应 `maxDepthPerVariable` 在创建中间变量之前提供最多数量的嵌入操作。 如果没有说明,我们使用 `maxDepthPerVariable: 8`。要缩合成尽可能少的行,请使用 `Infinity`。使每个操作都成为自己的变量,使用1.

### JS/TS的进口

将此库添加到您的工程中 :

```
yarn add @davepagurek/glsl-autodiff
```

然后导入 `gen` 方法 :

```typescript
import { gen } from '@davepagurek/glsl-autodiff'

const myShader = `
  // some shader code here
  ${gen((ad) => {
    // Use autodiff here
  })}
`
```

### 在浏览器中导入

下载库 [从 Github 发布标签](https://github.com/davepagurek/glsl-autodiff/releases/tag/v0.0.14) 并将此库添加到您的 HTML 文件 :

```html
<script type="text/javascript" src="autodiff.js"></script>
```

然后,使用全球 `AutoDiff` 变量,包括 `gen` 函数 :

```js
const myShader = `
  // some shader code here
  ${AutoDiff.gen((ad) => {
    // Use autodiff here
  })}
`
```

## 捐款

想帮忙吗? 有些事情我想在某个时候去做 [在“问题”标签中为后代写下](https://github.com/davepagurek/glsl-autodiff/issues) 我喜欢帮忙!

设置回放:

```
git clone git@github.com:davepagurek/glsl-autodiff.git
cd glsl-autodiff
yarn install
```

编译 `build/autodiff.js` 财务报告和审定财务报表 `build/autodiff.d.ts`数字 :

```
yarn build
```

将所有编译的代码推向 Github Pages 用于演示( 如果您是我或有写权限) :

```
yarn deploy
```

向国家预防机制发布新版本:

```
yarn publish
```

## 常见问题

### @davepagurek/glsl-autodiff 是什么？

厌倦了做数学 让你的顶点遮平正常? 同样的。 使用此库来写入您的函数一次并自动生成衍生出\!

### 如何安装 @davepagurek/glsl-autodiff？

在项目目录运行 npm install @davepagurek/glsl-autodiff，或使用 pnpm add / yarn add / bun add。

### @davepagurek/glsl-autodiff 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @davepagurek/glsl-autodiff 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @davepagurek/glsl-autodiff 可以商用吗？

@davepagurek/glsl-autodiff 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @davepagurek/glsl-autodiff 的下载量有多少？

根据 npm 官方下载统计，@davepagurek/glsl-autodiff 在 2026/10/12 – 2026/11/10 这 30 天内被下载 2,780 次，日均约 93 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @davepagurek/glsl-autodiff 还在维护吗？

最新版本 0\.0\.20 发布于 2023/06/10（3 年前）；至今共发布 20 个版本，其中过去 12 个月发布了 0 个；首次发布于 2021/07/09。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

