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

启动码
| 自动diff + 球形映射照明 | 自动diff + 球形映射照明 + 凸起映射 |
|---|---|
| P5 编辑器模板 | P5 编辑器模板 |
| 代码模板 | 代码模板 |
为什么?
有时候,我想取代 网状顶点在一个顶点的阴影。 这样做之后,一地表的常态应该改变:

然而,每个顶点的常态不会自动更新! 手动更新顶点常态需要您接受位移函数的衍生. 这个库将这个过程自动化,这样可以减少时间,并减少用户出错的可能性. 如果你感兴趣,读 更深入的博客文章 说明为什么有必要这样做和如何运作.
API 使用量
这暴露了一个 gen 函数生成 GLSL ,您可以在阴影码中切入。 在电话里 gen(),您提供了一个召回 收录 ad,AutoDiff引擎,并用来构建阴影码. 我们通过制作一个操作图来建立遮蔽器,我们通过该图输入实现产出。 每个函数调用都会创建代表此操作的对象. 一旦有了图表,我们就可以使用它自动计算出衍生物!
AutoDiff 引擎的方法设计类似您通常会如何写出一个阴影器,但使用方法链路而不是操作员符号,类似于如何写 p5的矢量类作品. 它看起来像这样的行动:
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
interface AutoDiff {
param(name: string): Param
vec2Param: (name: string) => VecParam
vec3Param: (name: string) => VecParam
vec4Param: (name: string) => VecParam
}
产出 用于将AutoDiff内部的计算结果存储到AutoDiff外部可访问的名称。 还可以输出一个输入参数的计算衍生物.
interface Op {
output(name: string);
outputDeriv(name: string, param: Param);
}
举例来说,我们可以使用 param 引用一个制服,用它做一些数学,并输出结果:
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操作相应的新节点:
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),使用下列任何方法再次生成一个带有计算结果的新节点:
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 回调 :
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 函数 :
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
|
void main(void) {
vec4 objSpacePosition = vec4(aPosition, 1.0);
float origZ = objSpacePosition.z;
float x = objSpacePosition.x;
float y = objSpacePosition.y;
|
有时太过或太少 最终在一线,所以你也可以供应 maxDepthPerVariable 在创建中间变量之前提供最多数量的嵌入操作。 如果没有说明,我们使用 maxDepthPerVariable: 8。要缩合成尽可能少的行,请使用 Infinity。使每个操作都成为自己的变量,使用1.
JS/TS的进口
将此库添加到您的工程中 :
yarn add @davepagurek/glsl-autodiff
然后导入 gen 方法 :
import { gen } from '@davepagurek/glsl-autodiff'
const myShader = `
// some shader code here
${gen((ad) => {
// Use autodiff here
})}
`
在浏览器中导入
下载库 从 Github 发布标签 并将此库添加到您的 HTML 文件 :
<script type="text/javascript" src="autodiff.js"></script>
然后,使用全球 AutoDiff 变量,包括 gen 函数 :
const myShader = `
// some shader code here
${AutoDiff.gen((ad) => {
// Use autodiff here
})}
`
捐款
想帮忙吗? 有些事情我想在某个时候去做 在“问题”标签中为后代写下 我喜欢帮忙!
设置回放:
git clone [email protected]:davepagurek/glsl-autodiff.git
cd glsl-autodiff
yarn install
编译 build/autodiff.js 财务报告和审定财务报表 build/autodiff.d.ts数字 :
yarn build
将所有编译的代码推向 Github Pages 用于演示( 如果您是我或有写权限) :
yarn deploy
向国家预防机制发布新版本:
yarn publish