Three.js: 节点材料

创建于 2015-11-03  ·  161评论  ·  资料来源: mrdoob/three.js

你好。

我开始开发一个 THREE.NodeMaterial 来协调 3D 创作软件之间的差异材料。 在 SEA3D Studio 中,可以选择在 Albedo 中使用蒙版和各种混合模式、边缘着色器等创建图层,而无需自定义着色器代码。 我想用节点着色器把它带到 Three.JS。

我认为 MeshPhongMaterial、MeshPhysicalMaterial 和其他可以很容易地基于 NodeMaterial 通过一个接口来实现向后兼容或仅代理。

更新
http://sunag.github.io/sea3d/Labs/Three.JS-NodeMaterial/webgl_materials_nodes.html
http://sunag.github.io/sea3d/Labs/Three.JS-NodeMaterial/webgl_postprocessing_nodes.html

将 UV1 或 UV2 用于纹理的语法示例:

var usesUv2 = true;
var isLightmap = false;

var t = new THREE.NodeTexture( texture, new THREE.NodeUV( usesUv2 ) );

var nodemat = new THREE.NodePhongMaterial();
if (isLightmap) nodemat.light = t;
else nodemat.color = t;
nodemat.build(); // build shader

我也在制作一个编辑器,目前这将是界面。 颜色是反照率,变换是顶点位置。
editor

我还注意它可以用于延迟着色。 现在我将创建反射和折射输入。

将向 PR 分享新闻,欢迎提出建议、测试和改进:+1:

Enhancement

最有用的评论

好的,TS 支持已准备就绪,下一个版本R017 🙌

所有161条评论

有趣的!

@sunag我们对这样的事情非常感兴趣。 我能提供什么帮助? 我至少可以添加对标准的支持。

我对创建相当随意的图很感兴趣,以便中间节点也接受输入。 所以你可以有一个看起来像这样的图表:

纹理(tex1,uv1)
B 纹理(tex2, uv2)
C 混合(A、B、模式)
D 噪声(参数 1,参数 2)
E 混合(C,D,模式)

然后使用最终节点 E 作为材质的输入。

所以它是非常随意的,不仅限于纹理。

我的目标是在接下来的几周内帮助创建它,如果可能的话,希望在下周左右与您合作。 我正在考虑通过这里的 shadergraph 库执行此操作: https :

我正在阅读您的代码,它设计得非常好。 我有一些初步的反馈。 我可以使用您的代码作为基础开始 PR 开始合作吗?

(1)我会让材料解决参考文献。 基本上,引用会具有他们会要求其材料解析的名称,并且材料会返回有关如何访问该数据的代码片段。 这也将允许材料知道节点使用了哪些变量(统一/变化),因此它可以进行适当的优化。 这也允许不同的材料以不同的方式解析引用,从而使节点更具可移植性,而不必知道材料如何实现事物,尤其是在片段和顶点实现之间存在差异时。

(2) 我尝试使用我在灯光重构中创建的 GeometryContext 对象,它提供了对许多所需局部变量的一致访问。 但是当然这可以通过材料本身来解决。

(3) 我有 UV 只是另一个参考,这是由材料解决的。 而且我希望 NodeTexture 实际上应该采用节点输入,从而允许程序生成的 UV。

(4) 为了与 Three.JS 的其余部分保持一致,我会调用 NodeCube、NodeTextureCube。 我会删除关于如何从它实际进行光线投射的逻辑。 但是我喜欢标准立方体贴图的想法,所以我实际上不会在节点中放置镜面反射或漫反射的环境查询,而是在基本 phong 材质中放置它,并且您只能控制用于查询的法线,或者立方体贴图结果本身(从而使其成为程序确定的颜色。)这有意义吗? 因此,我将在材质中使用法线可插拔,并将立方体纹理可插拔(可通过方向和偏差/lod 查询,并返回颜色)。 因此,可以为辐照度贴图提供立方体纹理,为高光贴图提供另一个纹理。 我们可以用@tschw的cubeToUV2 函数替换真正的sampleCube 作为节点交换。

(5) 我会尝试添加一个 NodeFunction,它允许调用带有参数的任意函数作为 NodeOp 的补充(或者它们可以以某种方式合并。)

(6) 我会去掉所有冗长的 NodeNormal、NodeTransform、NormalMap 等单独的类,只使用一些简单的构造函数来创建一个 NodeReference,其名称由材料酌情解析。 NodeReference 可以解析着色器中的统一值、变量值以及计算值。

(7) 我不明白 NodeEnvironment 和 NodeCube 之间的区别。 我认为 NodeEnvironment 可能不完整?

(8) NodePhong 不是从 NodeMaterial 派生的,这令人困惑。 虽然我看到NodeMaterial是从ShaderMaterial派生的。 我想知道您是否将 ShaderMaterial、GraphMaterial(或 NodeGraphMaterial)的直接导数称为更有意义——因为所有节点一起形成一个图,并且图成为材料,而不是单个节点。

(9) 我建议使用一些更多样化的术语。 我将根节点称为 MaterialNode,并且可以从中派生出 PhongMaterialNode。 我有从 ValueNode 派生的 Vector3Node、FloatNode 等——不一定是常数,而只是一个值。 因此,可以将三个 FloatNode 通过管道传输到 Vector3Node。 我认为您可以有一个助手来声明这些一行左右的每一行,而不是目前的 10 行左右。

(10) 我会将名称“Node”从类名的开头移到后面,因为在 ThreeJS 项目的其余部分中也是如此。

(11) 我将创建新的 MaterialNode 类,它会用一个统一和变化的列表进行初始化。 默认情况下,能够解决此问题并跟踪已解决的问题,以便可以跟踪需要哪些功能。 因此,在派生的 PhongMaterialNode 中可以有一个有限的解决方案,该解决方案将解决特殊情况并依赖基础类来完成简单的(变化的、统一的)。

(12) 我对 NodePhong 和 NodePhongMaterial 之间的区别有点困惑。 直到现在我才意识到两者都有。

(13) 有这样的代码:

THREE.NodeGLPosition.prototype = Object.create( THREE.Node.prototype );
THREE.NodeGLPosition.prototype.constructor = THREE.NodeGLPosition;

THREE.NodeGL.prototype.generate = function( material, shader ) {

但是在这个片段上面你已经为NodeGL定义了generate而你没有为NodeGLPosition定义一个 - 因此我认为这是一个复制粘贴编辑错误。

(14) 我会去掉 NodeReflectUVW 和 NodeRefractVector,而只是让这个东西可以通过参考解析从材料中请求。 计算反射向量很简单。 我已将它添加到我未合并的实验 ThreeJS 分支中的GeometryContext中。

(15) 我实现反射和折射的方法是将它们作为材质的颜色输入。 可以用解析任何变量的简单方式解析 Refect、ReflectLOD 和 Refract、RefractLOD,然后将它们传递到一个纹理立方体等效(程序或基于采样立方体)中,然后将生成的颜色传递到材质中。 你是这样做的吗?

(16) 我对光输入感到困惑——通常没有可插拔的光,而是光参数在光类中完全定义。 我想您需要这种额外的灵活性吗? 你怎么设想。

@bhouston哇,非常感谢您的反馈。
我需要几个帖子来回答:)

我对创建相当随意的图很感兴趣,以便中间节点也接受输入。 所以你可以有一个看起来像这样的图表:
纹理(tex1,uv1)
B 纹理(tex2, uv2)
C 混合(A、B、模式)
D 噪声(参数 1,参数 2)
E 混合(C,D,模式)

目前的语法是这样的。 UV1 偏移动画示例:
我认为 NodeMaterial 到 MaterialNode 和 THREE.PhongMaterialNode 也会更好。

var uv2 = false;
var uv_offset = new THREE.NodeFloat(0);     
var uv = new THREE.NodeOperator( '+', new THREE.NodeUV( uv2 ), uv_offset);
var texture = new THREE.NodeTexture( imgTexture, uv );

nodematerial.color = t;

// onUpdate
uv_offset.number += .01;

我认为将您的建议颠倒顺序会变得更好(模式,A,B)到(A,B,模式)。 我正在创建反射贴图、立方体贴图和其他...

环境和立方体贴图不完整。

目前,由于格式转换器仍未完成,它可能会发生更多错误。 这由矢量转换负责。 例如 vec3 到 vec4 或 vec4。

https://github.com/sunag/sea3d/blob/gh-pages/Labs/Three.JS-NodeMaterial/index.html#L365

例如混合“纹理”:(我没有测试过这段代码)
它可以在同一个 THREE.NodeOperator 中实现

https://github.com/sunag/sea3d/blob/gh-pages/Labs/Three.JS-NodeMaterial/index.html#L1105

THREE.NodeBlend = function( a, b, mode ) {

    THREE.NodeInput.call( this, 'blend' );

    this.mode = mode;
    this.a = a;
    this.b = b;

};

THREE.NodeBlend.prototype = Object.create( THREE.NodeInput.prototype );
THREE.NodeBlend.prototype.constructor = THREE.NodeBlend;

THREE.NodeBlend.prototype.generate = function( material, shader, output ) {

    var a = this.a.build( material, shader, output );
    var b = this.b.build( material, shader, output );

    switch(this.mode)
    {
        case 'multiply':

            return this.format( '(' + a + '*' + b + ')', this.a.type, output);

            break;
    }

    return a;

};

.generate() 负责代码生成器。 如果您想在多个输入中使用而不损失性能,则计算代码存储在缓存中。

我仍然没有设置指针或常量进行优化......

编译是通过在 build() 中传播顶点和片段代码来完成的。

我可以把你当成合作者吗? 如果您想以任何方式编辑代码,我也会进行处理。

我可以把你当成合作者吗? 如果您想以任何方式编辑代码,我也会进行处理。

谢谢! 我会给你做 PR,这样你就可以批准这些更改。

我已将您(以及@mrdoob@WestLangley和 @tschw)添加到我的一个副项目中,该项目试图定义一组可在各种渲染之间转移的可重用节点和材质定义。 它可以映射到您创建的这个着色器图形系统上。

如果您不想,我认为您不必注意我刚刚让您访问的回购。 这是我有兴趣在此基础上实施的。

(2) 我尝试使用我在灯光重构中创建的 GeometryContext 对象,它提供了对许多所需局部变量的一致访问。 但是当然这可以通过材料本身来解决。

我希望这些灯是一个 LightNode。 我关心的是利用已经为 Three.JS 开发的代码。

(3) 我有 UV 只是另一个参考,这是由材料解决的。 而且我希望 NodeTexture 实际上应该采用节点输入,从而允许程序生成的 UV。

您可以将 UV 替换为 vec2 是这样吗?

(5) 我会尝试添加一个 NodeFunction,它允许调用带有参数的任意函数作为 NodeOp 的补充(或者它们可以以某种方式合并。)

这会很棒。 主要用于 BlendNode。

(6) 我会去掉所有冗长的 NodeNormal、NodeTransform、NormalMap 等单独的类,只使用一些简单的构造函数来创建一个 NodeReference,其名称由材料酌情解析。 NodeReference 可以解析着色器中的统一值、变量值以及计算值。

在这个思路中,我认为 MaterialNode 可以是材质 Phong 和 Physical 材质的基础。

(7) 我不明白 NodeEnvironment 和 NodeCube 之间的区别。 我认为 NodeEnvironment 可能不完整?

我仍然无法完成这些节点。

(8) NodePhong 不是从 NodeMaterial 派生的,这令人困惑。 虽然我看到NodeMaterial是从ShaderMaterial派生的。 我想知道您是否将 ShaderMaterial、GraphMaterial(或 NodeGraphMaterial)的直接导数称为更有意义——因为所有节点一起形成一个图,并且图成为材料,而不是单个节点。

NodeMaterial 将是根节点材质,需要为顶点和片段使用一个节点。 NodePhong 是 hibrid 的,NodePhongMaterial 只是一个代理类。 然后可以合并。

(9) 我建议使用一些更多样化的术语。 我将根节点称为 MaterialNode,并且可以从中派生出 PhongMaterialNode。 我有从 ValueNode 派生的 Vector3Node、FloatNode 等——不一定是常数,而只是一个值。 因此,可以将三个 FloatNode 通过管道传输到 Vector3Node。 我认为您可以有一个助手来声明这些一行左右的每一行,而不是目前的 10 行左右。

听起来不错。

(16) 我对光输入感到困惑——通常没有可插拔的光,而是光参数在光类中完全定义。 我想您需要这种额外的灵活性吗? 你怎么设想。

这将用于光照贴图或可能的 LightNode。

这将用于光照贴图或可能的 LightNode。

我喜欢可插拔光照贴图的想法,因为可以明确地为其定义 UV。 :)

@bhouston今天在此文件中修复了几处更正:但仍有很多工作要做。
https://github.com/sunag/sea3d/blob/gh-pages/Labs/Three.JS-NodeMaterial/three.node.js

这是我正在创建的游乐场:艺术:纹理和按钮是拖放,仅适用于 chrome

http://sea3d.poonya.com/flow/

太棒了,东西! 碉堡了! 它很美。

是否可以以我也可以贡献的方式共享代码? 作为公共公关还是什么?

您正在这里处理 Sea3D 项目,对吗?

https://github.com/sunag/sea3d/tree/gh-pages/Labs/Three.JS-NodeMaterial

所以我可以分叉它并开始贡献吗? 你会接受 PR 吗? 我们如何才能有效地协作。

我还没有问过,但@mrdoob可能(?)希望在 ThreeJS 项目本身中有这个。

确实!

所以我可以分叉它并开始贡献吗? 你会接受 PR 吗? 我们如何才能有效地协作。

当然,我认为你的帮助会很棒。 我还必须按照您的建议带来其他节点类型,例如饱和度、噪声。

您正在这里处理 Sea3D 项目,对吗?

我认为在使用示例为 Three.JS 制作 PR 时,所有这些都已定义。

@mrdoob你对材料名称 THREE.MaterialNode 或 THREE.NodeMaterial 有什么看法?

它是一种材料,所以它应该是THREE.NodeMaterial

边缘着色器示例
flow-rimshader-example

区域反射示例
flow-areareflection

这太棒了@sunag!

@bhouston谢谢! 您认为转换为 R74 会很困难吗?

这是令人印象深刻的工作! 让我想起了shaderforge

到目前为止做得很好!

@sunag这将是一些工作,但我想提供帮助,并且 R74 着色器代码中的大多数重大结构更改都是我的错。 :)

@GGAlanSmithee它也与 UE4 非常相似: https : //docs.unrealengine.com/latest/INT/Engine/Rendering/Materials/ExpressionReference/index.html

看起来很漂亮而且玩起来很有趣:我可以提供灵感吗 Blender3D 节点编辑器。 我发现它非常高效,甚至还有一些通过 Blender 节点系统在 PBR 上的精彩视频,以及哪些节点对于从头开始制作 PBR 最有用:

https://www.youtube.com/playlist?list=PLlH00768JwqG4__RRtKACofTztc0Owys8

这将是一些工作,但我想提供帮助,R74 着色器代码中的大部分重大结构变化都是我的错。 :)

@bhouston哇。 新的 r74 更改更加干净。 我完成了第一部分仍然缺少 StandardMaterial。 我在这里发布的任何问题:)谢谢
https://github.com/sunag/sea3d/commit/d544ad7993272348f8bbea2337cdceb52159a6a8

我们仍然缺少的另一件事是折射。 我真的很喜欢使用渲染缓冲区代替 Cubemap RTT 作为默认设置。 效率会高很多。

@GGAlanSmithee我有一些 ShaderFX 的参考资料,我是它的忠实粉丝。 Shader Forge 和 UE4 主要也是很好的参考。谢谢!

@richardanaya 精彩视频。 谢谢!

@mrdoob您建议将这些文件放在哪个文件夹中? 三.js 根( src/materials/node )或在示例中?
https://github.com/sunag/sea3d/tree/gh-pages/Labs/Three.JS-NodeMaterial/node

我仍然建议将其称为“材料图”或反向 ThreeJS 风格的“GraphMaterial”。 或者,如果您坚持使用术语“节点”,我将其称为“NodeBasedMaterial”。 这两个名称都清楚地表明材质包含节点,而不是节点本身。

我仍然建议将其称为“材料图”或反向 ThreeJS 风格的“GraphMaterial”。 或者,如果您坚持使用术语“节点”,我将其称为“NodeBasedMaterial”。 这两个名称都清楚地表明材质包含节点,而不是节点本身。

对我来说,两者看起来都不错。 我把决定留给@mrdoob你怎么看?

顺便说一句@sunag如果可能的话,我会坚持使用立方体贴图进行折射,它更容易、更准确。 我认为几乎其他人都是这样做的,我们也需要 RTT 的东西来进行准确的反射。 我认为它只需要以 128^2 或 256^2 进行快速渲染即可。

顺便说一句@sunag如果可能的话,我会坚持使用立方体贴图进行折射,它更容易、更准确。 我认为几乎其他人都是这样做的,我们也需要 RTT 的东西来进行准确的反射。 我认为它只需要以 128^2 或 256^2 进行快速渲染即可。

是的,我们可以让两者兼而有之。 将是性能 x 准确性之间的讨论。 仍然对于平面折射(玻璃、水),我建议使用缓冲区代替 CubeMap(在大多数情况下)。

@mrdoob您建议将这些文件放在哪个文件夹中? 三.js 根( src/materials/node )或在示例中?

我会把它放在例子中。 一旦它得到很好的定义,我们就可以稍后将它移动到 src 😊

我仍然建议将其称为“材料图”或反向 ThreeJS 风格的“GraphMaterial”。 或者,如果您坚持使用术语“节点”,我将其称为“NodeBasedMaterial”。

对我来说,两者看起来都不错。 我把决定留给@mrdoob你怎么看?

我有点喜欢NodeMaterial了...也许NodesMaterialNodeGraphMaterial ? @WestLangley 有什么建议吗?

我会重命名当前节点... NodeColor , NodeFloat , NodeTexture , ... 到ColorNode , FloatNode , TextureNode

http://sea3d.poonya.dev/flow/

我无法加载这个😐

我会把它放在例子中。 一旦它得到很好的定义,我们可以稍后将它移动到 src :blush:

@mrdoob会很棒。

我会重命名当前节点... NodeColor, NodeFloat, NodeTexture, ... 到 ColorNode, FloatNode, TextureNode

那我转发一下。

这是本地网址 :blush: ,试试这个:
http://sea3d.poonya.com/flow/

@WestLangley 有什么建议吗?

我建议THREE.FlowMaterial

我的第二个选择是THREE.CustomMaterial

作为一个完全随机的旁观者。 NodeMaterial 对我来说听起来很直观,因为这就是它们在 Blender3D 中的名称

如果@mrdoob喜欢 NodeMaterial,我们可以坚持下去。 :)

NodeMaterial就是这样😁

这个项目太棒了! 刚刚在 Twitter 上看到了演示,非常令人印象深刻。

我想知道节点是否应该进入三核。 它们非常特定于实现。 我也在为 ShaderFrog.com 构建一个 Three.js 着色器图形编辑器(尚未发布),我的解决方案是将 GLSL 代码和所有需要的元数据(如统一名称)导出到一个小的 JSON 文件中,然后加载它使用外部运行时库

screen shot 2015-11-20 at 12 05 26 pm

此图形编辑器可以通过分析其源代码来处理完整的着色器,这意味着不需要特定的着色器节点类型。 这个 NodeMaterial 类型也可以完全在 Three 的核心之外处理吗? 您真正需要输出的是RawShaderMaterial供某人在自己的项目中使用它。

这个 NodeMaterial 类型也可以完全在 Three 的核心之外处理吗? 您真正需要输出的只是一个 RawShaderMaterial,供某人在他们自己的项目中使用它。

@DelvarWorld嗨。 理论上是的,但是从原始数据制作一个好的着色器还为时过早。 当时最好有一个初始界面。 它还有助于与 Three.JS 的 Skin / Morph 和其他本地组件保持兼容。

我想注意一个小问题:
在“Flow”中,将节点拖到彼此之间时,连接器不会弹出到顶层。
也许这个问题正在等待图层或其他东西。

我想知道是否有办法统一这两种方法? 我对多层着色器感兴趣,为此您需要有多个 BSDF 来为最终结果做出贡献。 这意味着需要更多地分离着色模型——现在它在@sunag的当前设计中非常紧密地耦合@DelvarWorld那样原始。 我认为我们可以逐步转移到那里,所以@sunag是一个好的开始。

这不是一个完整的答案,但不久前我为包含元数据的便携式着色器格式创建了一个粗略的建议,例如统一名称、它们的类型、它们在 Three.js 中的类型等。 https://github.com /DelvarWorld/ShaderFrog-Runtime/blob/master/THREE_SHADER_FORMAT.md

在真实环境中运行着色器真正需要的是原始着色器源代码(因为 GPU 编译它),并且为了方便起见,用户可以使用什么值设置什么制服。 这个粗略的提议不包括任何以编程方式构建着色器的概念,它只是 GLSL 和元数据的简单交付。 它与 Three.js 兼容,因为你最终只需要将它放入RawShaderMaterial中。

目前没有办法在 Three.js 中使着色器可移植或从任何应用程序导出它们,这让我想到提出一个标准,我认为它可以解决我们两个问题,因为我们正在构建外部应用程序那到底是吐出了预定的材料。 这也意味着编译特定图形组合的实现细节由应用程序决定,而不是 Three.js。

这个提议的着色器标准在三中占有一席之地吗? 我不知道。 现在它对我来说可能比对 Three 的核心更有用,因为 Three 以自己的方式构建自己的着色器。

@DelvarWorld我确实开始了这个项目,以创建一组标准化的着色器图节点:

https://github.com/OpenMaterialGraph/OpenMaterialGraph

节点规格在这里:

https://github.com/OpenMaterialGraph/OpenMaterialGraph/tree/master/spec/nodes

此处的极简 BSDF 规范:

https://github.com/OpenMaterialGraph/OpenMaterialGraph/tree/master/spec/bsdfs

不过,这面向基于物理的渲染。

我的感觉是,需要有一个 ThreeJS 着色器的外壳,它的级别高于原始着色器,但低于 Phong 着色器。 基本上,默认着色器将能够执行变形目标、骨骼等。然后所有这些特定的照明方案着色器(基本、兰伯特、Phong、标准)将使用该模板。 现在有一个隐含的模板着色器(我们在每个着色器中包含相同的东西)——但我认为我们可以更清楚地说明在哪里插入东西。 您可以插入照明方案(phong、lambert、基本或多层),并且您可以将属性插入作为您的常规节点的那些照明方案。

@bhouston哦,不错,看起来我们有很多重叠的要求,又名默认值、显示名称、人类可读的描述等。我不知道未来会怎样,但对我来说使用格式更像你的建议。

正式的着色器格式很有意义。 不过,它应该与 lib 一起存在,以便它可以更轻松地发展。 对于对three.js 比较陌生的人,是否有任何具体原因不存在这样的东西? 如果没有别的,编辑应该会很有趣。

*编辑也许如果在three.js中使用规范会被其他渲染管道消耗掉它的目的。

现在它对我来说可能比对 Three 的核心更有用,因为 Three 以自己的方式构建自己的着色器。

一旦 NodeMaterial(*Flow) 是一种视觉语言,如果您在THREE.NodeGL.prototype.generate进行修改,您可以用其他语言生成相同的材料。 NodeBuilder 可以成为它的大门。 目前是节点之间数据的中介。

我清理了一个 NodeMaterial "raw" 的例子:它仍然会产生几个错误。
https://github.com/sunag/sea3d/blob/gh-pages/Labs/Three.JS-NodeMaterial/index.html#L179
https://github.com/sunag/sea3d/blob/gh-pages/Labs/Three.JS-NodeMaterial/node/NodeMaterial.js#L9

我想用粒子创建的根节点来推进这一点。 NodePass for Multi-Pass 和 NodeMaterialD 在 PR 之后我应该在几天内做什么。

我建议使用 THREE.ShaderFrogLoader 而不是运行时着色器。

在“Flow”中,将节点拖到彼此之间时,连接器不会弹出到顶层。

@MasterJames谢谢! 我会看着它。

:+1:

我开始创建示例。 我希望这周能结束。 :汗_微笑:
http://sunag.github.io/sea3d/Labs/Three.JS-NodeMaterial/webgl_materials_nodes.html

想法?

@sunag +1

+1!

这太棒了。 我会默认植物+墙壁纹理,而不是像云一样的位移。 :) 那太美了。

我会默认植物+墙壁纹理,而不是像云一样的位移。

你指的是“层”的例子? 但是我会为我们发布更多示例

gpu软体
soft-body

为了与不同的方法进行比较,Shader Frog 图形编辑器现已上线,并且处于“踢轮胎”阶段。 我想强调的是,它不需要对 Three.js 核心进行任何更改。

ShaderFrog 目前比传统的节点编辑器更强大。 它可以使用无限的节点类型,因为它可以解析和理解任何着色器。 例如,要仅将反射应用于对象的边缘,您可以简单地采用发光着色器,它是一个完全独立的着色器,带有片段和顶点着色器:

screen shot 2015-12-08 at 1 48 24 pm

...并将其乘以反射着色器...

screen shot 2015-12-08 at 1 49 39 pm

...使用着色器图...

screen shot 2015-12-08 at 1 50 40 pm

还有达达! 一个反射边缘着色器

例如,您还可以使用任何其他 shader 遮罩任意两个着色器,依此类推:

screen shot 2015-12-08 at 1 56 03 pm

请注意,此过程所需的唯一“节点类型”是乘法节点(ShaderFrog 中还有其他节点),它几乎完全独立于 GLSL。 ShaderFrog 可以与任何着色器一起使用,这就是它具有无限节点类型的原因。 这种先进的技术方法允许独立于 Three.js 更改的这种操作。

ShaderFrog 为 Three.js 提供一流的免费导出支持。 全部无需修改 Three.js 源代码。 Sea3D 是第三方产品,如 ShaderFrog。 将第三方产品机制放入 Three 的核心似乎是一种不公平的优势,我在政治上不理解。

@DelvarWorld我真的不认为基于节点的着色器构造抽象是第三方特定技术。 如果有的话,它允许更多的竞争对手参与基于节点的着色器技术,并从彼此工作的进一步利益中受益(更多节点、优化构造等)。

作为一个像我这样的图形程序员,他对着色器有较高的理解(通过 Blender 3D 等工具),但不是在低层次上,基于节点的抽象似乎是我使用我的 3D 建模知识以编程方式与着色器交互的好方法。 例如,我了解 PBR 的节点设置,但是如果我想在 GLSL 中编写它,上帝会帮助我。

@DelvarWorld太棒了。 我喜欢新编辑器。

@DelvarWorld +1 非常好! :-)

谢谢! :)

我真的不认为基于节点的着色器构造抽象是第三方特定技术。

例如,我了解 PBR 的节点设置

我在这里的反例的一部分是,您可以独立于 Three.js 免费获得这两种东西。 所有 ShaderFrog 着色器都是开源的,因此任何成为 PBR 实现一部分的节点也可以随着时间的推移学习、编辑和改进(以及与任何其他着色器组合,而不仅仅是 Three.js 核心中的某个子集)。 对我来说,所有这些都可以在没有三个更改的情况下完成的事实意味着它是不必要的,并且模糊了 Three.js 作为 webgl 包装器 API 和现在驱动实现特定功能之间的界限。 存储着色器节点数据是高度特定于应用程序的,据我所知,目前没有任何软件的通用节点编辑器标准格式? 强制执行一个可能对其他实现有害。

@DelvarWorld据我了解这一变化,ShaderFrog 仍将能够运行,并且如果需要,将继续能够超越 GraphMaterial。 我查看了 GraphMaterial 的示例源代码,我能够理解它的工作方式的简单性,甚至无需考虑第三方解决方案/编辑器。 作为一个图形开发者,我关心的是如何以编程方式制作出令人印象深刻的材料,我觉得这些是 ThreeJS 应有的关注。

我认为 NodeMaterial 和 Flow 有两个不同的侧重点。 Flow 和 ShaderFrog 都是目前处于封闭源代码中的可视化编辑器第三方解决方案(我认为主要是在美术师中)另外 NodeMaterial 是一个开源着色器编辑器,供程序员使用 Three.JS 完成。 我同意@richardanaya ,因为如果需要,ShaderFrog 可以超越 NodeMaterial。 就像我认为 Flow 不需要只是一个材质编辑器一样。 我真的希望 ShaderFrog 在未来能像往常一样有很大的改进。

wip:苛性碱-voronoi
http://sunag.github.io/sea3d/Labs/Three.JS-NodeMaterial/webgl_materials_nodes.html
caustic

@sunag我今晚正在浏览你的源代码。 我真的很喜欢它。 我今晚阅读的一些快速反馈:

  • 我希望早点看到 PR。 我可以搭把手。 :)
  • 允许任意属性而不仅仅是标准属性(uv、uv2、法线、位置等)可能很酷。我知道很多着色器都可以从切线 vec4s 中受益,不仅仅是 2 个 uvs 和多种颜色属性。 因此,我会将需求位置概括为一个 requestsAttributes 数组或其他东西。
  • 我建议将节点组织到主 NodeMaterial、BRDF(Phong、Standard 等)、纹理节点(NodeCubeTexture、NodeTexture)、访问器 (?) 节点(NodePosition、NodeNormal)、数学节点(NodeOperator 等)中。 )、实用程序节点 (NodeSwitch, ...) 和额外的 (?) (NodeVelocity, ...) 我认为这会很有帮助。
  • 为 Projection、View 和 World 矩阵提供矩阵访问器会很好。
  • 您缺少一些运算符: % ^ & << >> ~ |
  • 我不确定当类很小时我在 NodePhongMaterial 中看到值,我只是让用户必须使用 NodePhong 节点结合 NodeMaterial 创建它(虽然我仍然不喜欢这个名字,GraphMaterial 感觉很多对我来说更自然,但我可以忍受它。)
  • 我会调用 NodeTimer -> NodeTime ......但还是个人喜好。
  • 我想知道是否有某种方法可以像使用 NodeMath#、NodeOperator 那样将许多变量节点组合成一个节点。 这些看起来很相似:NodeViewPosition、NodeWorldPosition、NodeViewNormal、NodeTransformedNormal、NodeTransformedPosition、NodeProjectPosition...
  • 我想看到 NodeMath#、NodeOperator 的一组可选参数可以是列表的形式,以便人们可以轻松地用它填充下拉框。 现在,因为它们只是利用类的成员,所以识别它们有点困难。 我不确定一个仍然方便编码的好的解决方案。 也许只是在将它们定义为类成员之后将它们收集到一个列表中,所以只需添加这些列表?
  • NodeTransformedNormal、NodeTransformedPosition 对我来说很难在不看代码的情况下弄清楚它们是什么。 它们在世界空间、视图空间、对象空间中吗? “转换”是一个非常通用的术语,仅表示乘以矩阵。 我现在看看他们的代码......
  • 我将允许 NodeUV 和 NodeColor 采用索引,而不是分别限制为 2 和 1 通道。 我再次希望看到这些变得通用,实际上您传入一个字符串或多个预设中的一个,而不是将其硬编码到一组特定通道。 对于某些变量,您仍然可以有一些专用的代码路径,但是对于特殊情况处理无法识别的名称,它会回退到通用名称。

更多反馈:

  • 我想要一个包含多个 BRDF 的图,基本上是两个标准 BRDF,然后在它们之间进行能量保存。 一旦你获得了 PR,我想添加这个功能。 它将使系统更通用和更强大。

@bhouston哇! 谢谢!

修改了请求属性、文件夹组织、NodeTime、NodePosition、NodeNormal、NodeView。 也添加了 +3 示例。

在运算符和矩阵中,我们必须添加与integermatrix转换的兼容性。 为此,可以像在 float/vectors# 中那样以自动方式完成此操作。 我们有足够的工作来进行下一次更新.. :sweat_smile:

明天我会做PR。 我还得回顾一些事情。

@sunag :

我相信这是一个错误:

addGui( 'metalnessA', roughnessA.number, function( val ) {

                        roughnessA.number = val;

                    }, false, 0, 1 );

我相信这是一个错误:

谢谢!

我刚刚进入示例页面并看到 PBR 节点图 <3

尼斯!

我打算建议使用节点进行后期处理,但我正在等待第一部分完成。 妈的,太美了!

NodeMaterial 版本 5 + LightNode

http://sunag.github.io/sea3d/Labs/Three.JS-NodeMaterial/webgl_materials_nodes.html

皮肤
nodematerial-rev5-skin

卡通着色
nodematerial-rev5-toon

++ color-adjustmentplush示例。

尼采!

subsurface scattering :sweat_smile:

这是一种可以在未来更新中工作的着色器。

http://sunag.github.io/sea3d/Labs/Three.JS-NodeMaterial/webgl_materials_nodes.html

sss-img1
sss-img2

😮!

感谢出色的 NodeMaterial!

我有几个评论/错误:

  • 尾随空格中断函数节点
var n1 = new THREE.FunctionNode(" float mul_2_float(float x) { return x*2.0; }"); // problem
var n2 = new THREE.FunctionNode("float mul_2_float(float x) { return x*2.0; }"); // ok
  • 函数节点中 int 参数的问题

带有浮点参数的工作示例:

var floatFuncNode= new THREE.FunctionNode("float mul_2_float(float x) { return x*2.0; }");

var funcCallNode = new THREE.FunctionCallNode(floatFuncNode);
funcCallNode.inputs.x = new THREE.FloatNode(0.2);

var colorResNode = new THREE.OperatorNode(new THREE.ColorNode(0x00ff00),
    funcCallNode, THREE.OperatorNode.MUL);

var mat = new THREE.PhongNodeMaterial();
mat.color = colorResNode;

带有 int 参数的损坏示例:

var intFuncNode= new THREE.FunctionNode("float mul_2_int(int x) { return float(x)*2.0; }");

var funcCallNode = new THREE.FunctionCallNode(intFuncNode);
funcCallNode.inputs.x = new THREE.IntNode(1);

var colorResNode = new THREE.OperatorNode(new THREE.ColorNode(0x00ff00),
    funcCallNode, THREE.OperatorNode.MUL);

var mat = new THREE.PhongNodeMaterial();
mat.color = colorResNode;
  • 建议:在 FunctionCallNode 构造函数中传递函数参数
//current:
var funcCallNode = new THREE.FunctionCallNode(floatFuncNode);
funcCallNode.inputs.param1 = new THREE.FloatNode(1);
funcCallNode.inputs.param2 = new THREE.ColorNode(0x0f0f0f);

// proposed:
var funcCallNode = new THREE.FunctionCallNode(floatFuncNode, 
    { param1: new THREE.FloatNode(1), param2: new THREE.ColorNode(0x0f0f0f) } );

// and, i think suitable in some cases: 
var funcCallNode = new THREE.FunctionCallNode(floatFuncNode, 
    [ new THREE.FloatNode(1), new THREE.ColorNode(0x0f0f0f) ] );
  • PhongNodeMaterial 与凹凸贴图兼容吗?

还有一些注意事项:

  • “原始”NodeMaterial 中片段着色器中 PositionNode.LOCAL 的问题:
var material = new THREE.NodeMaterial(
        new THREE.RawNode( new THREE.PositionNode( THREE.PositionNode.PROJECTION ) ),
        new THREE.RawNode( new THREE.PositionNode( THREE.PositionNode.LOCAL ) )
    );

结果着色器:

varying vec3 vPosition;
void main(){
gl_Position = (projectionMatrix * modelViewMatrix * vec4( position, 1.0 ));
vPosition = transformed;
}
varying vec3 vPosition;
void main(){
gl_FragColor = vec4(vPosition,0.0);
}

可能“转换”的功能应该从 Phong/Standart 节点材料移动到 NodeMaterial

  • 常量节点使用
    var material = new THREE.NodeMaterial(
        new THREE.RawNode( 
            new THREE.OperatorNode(
                new THREE.PositionNode( THREE.PositionNode.PROJECTION ),
                new THREE.ConstNode("float TWO = 2.0;"),
                THREE.OperatorNode.MUL)
            ),
        new THREE.RawNode( new THREE.ColorNode( 0xff0000 ) )
    );

在这种情况下,结果着色器包含
gl_Position = ((projectionMatrix * modelViewMatrix * vec4( position, 1.0 ))*TWO);
但未声明两个常量。 是我的错误还是bug?
此外,ConstNode 对分号敏感,因此不会解析“float TWO = 2.0”。

谢谢@dimarudol ! 如果你想随时随手记笔记会尽快做出新的修订。

但未声明两个常量。 是我的错误还是bug?

我会考虑这种使用方式和材料,例如material.include( node )

当时尝试一个全局常量:

var TWO = new THREE.ConstNode("float TWO = 2.0;");
THREE.NodeLib.add( TWO ); // global

 var material = new THREE.NodeMaterial(
        new THREE.RawNode( 
            new THREE.OperatorNode(
                new THREE.PositionNode( THREE.PositionNode.PROJECTION ),
                TWO,
                THREE.OperatorNode.MUL)
            ),
        new THREE.RawNode( new THREE.ColorNode( 0xff0000 ) )
    );

@sunag ,我一直在玩Sea3d Flow,它看起来很酷。 只是想问一下是否有官方回购。
问候。

@rraallvv ,还没有,它已经准备好了。 我尽快发布消息。

谢谢@sunag ,非常感谢。

@sunag ! 你做得非常好!
我有一个问题:对于我的项目,使用您的节点结构会很棒,但我需要每个顶点的颜色(以及每个顶点的自定义浮点值),但是在您的节点系统中,您只将 colorNode 和 floatNode 应用于整个网格.. 你认为有没有办法轻松实现像bufferColorNode(使用THREE.BufferAttribute)这样的东西?

例如我有这个场景:

screenshot from 2016-08-31 16 27 06

每个顶点都有自己的颜色。 使用 THREE.BufferAttribute 和 THREE.ShaderMaterial 是可能的,但您的代码中没有等效项。

我需要类似的东西:
`let material = new THREE.StandardNodeMaterial();
让 texColorMap = new THREE.TextureNode( new THREE.TextureLoader().load("colorMap.jpg"));
让 customData = new THREE.BufferFloatNode(new Float32Array(...), "data"); // 第二个参数是属性的名称

让 colorMap = new THREE.FunctionNode([
“vec3 colorMap(sampler2D texColorMap,浮点数据){”,
" return vec3(texture2D(texColorMap, customFunc(data)));", // customFunc 根据数据返回一个 vec2
“}”
].join("n"));

让 colorMapCall = new THREE.FunctionCallNode(colorMap);
colorMapCall.inputs.texColorMap = texColorMap;

material.color = colorMapCall;
material.build();`

顺便说一句,似乎我不能为 FunctionNode 使用 sampler2D 参数......

我错过了什么吗?
如果需要,我想我可以提供帮助:)

@martinRenou谢谢! 嗯,现在可能是这样的:

bufferGeometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 4 ) );
...
colorMapCall.inputs.data = new THREE.ColorsNode(); // send color.x to float slot

我还没有想过用节点分配动态几何属性。 但我认为这是一个好主意......也许像THREE.BufferAttributeNode ......

@sunag感谢您的回答:)
我会试试的。 如果对你来说没问题,我将开始研究 THREE.BufferAttributeNode,现在我仍在阅读你的代码并试图理解它的结构。

  1. 关于 THREE.FunctionNode,正如我所说,我真的需要在我的参数中设置一个 sampler2D,因为它用作 colorMap .. 像素颜色使用 texture2D() 计算,texture2D() 的第二个参数使用我的自定义数据计算(例如温度)。
    我知道使用 vec3 参数的想法是为了对用户友好,但 FunctionNode 也可以支持 sampler2D 参数,你不觉得吗?
  2. 此外,THREE.FunctionNode 只在片段着色器中写入,但也能在顶点着色器中写入不是很好吗?

这将是我的用例,它被称为 IsoColor,因为颜色对应于数据(温度、压力...)红色 -> 高温,蓝色 -> 低温:
screenshot from 2016-09-01 17 29 58

  1. 我正在考虑编写一个 THREE.IsoColorNode(它将替换我的图表的 FunctionNode),以及其他对科学可视化非常有趣的节点。 你对此感兴趣吗? @mrdoob你也有兴趣吗?

关于 THREE.FunctionNode,正如我所说,我真的需要在我的参数中设置一个 sampler2D,因为它用作 colorMap .. 像素颜色使用 texture2D() 计算,texture2D() 的第二个参数使用我的自定义数据计算(例如温度)。 我知道使用 vec3 参数的想法是为了对用户友好,但 FunctionNode 也可以支持 sampler2D 参数,你不觉得吗?

我现在明白你的需要了! 我将为这个和@dimarudol 的其他笔记创建一个公关......

此外,THREE.FunctionNode 只在片段着色器中写入,但也能在顶点着色器中写入不是很好吗?

我没有测试过这个,但我想是的。

我添加了更多两个示例:

  • sampler2Dtriangle-blur示例中
  • 自定义BufferAttributecustom-attribute示例中

它正在工作,但我仍然会在代码中进行改进......

https://github.com/mrdoob/three.js/pull/9636

哇 ! 你真的做得很好,它对我也有用 :smile:

再次感谢您的工作!

@sunag

现在我们不能让 FunctionNode 具有“void”类型,因为我们需要将它作为参数(颜色、alpha...)发送到材质。 例如,如果我想实现一个裁剪平面 FunctionNode,我想要做的就是编写这样的着色器部分:

void clipPlane(vec4 plane){
 if(dot(position, plane.xyz) > plane.w) discard;
}

但这不可能将它提供给材料......一个解决方案是返回一个 alpha canal 的浮点数,但这不是干净和优化的。 难道你不认为给这样的材料添加一些空函数会很酷:

var clipPlane = new FunctionNode([
"void clipPlane(vec 4 plane){",
" if (dot(position, plane.xyz) > plane.w) discard;",
"}"].join("\n"));
var clipPlaneCall = new FunctionCallNode(clipPlane);
clipPlaneCall.inputs.plane = myVec4Node;

var threshold = new FunctionNode([
"void threshold(float upperBound, float lowerBound, float data){",
" if(data < lowerBound) discard;",
" if(data > upperBound) discard;",
"}"].join("\n"));
var thresholdCall = new FunctionCallNode(threshold);
thresholdCall.inputs.upperBound = myFloatNode1;
thresholdCall.inputs.lowerBound = myFloatNode2;
thresholdCall.inputs.data = myAttributeNode;

var myMaterial = new StandardNodeMaterial();
myMaterial.color = ...
myMaterial.alpha = ...

// voidFunctions is not a good name I'm not inspired...
myMaterial.voidFunctions = [clipPlaneCall, thresholdCall];

对于更“设计”的示例,如果我想用这种纹理在茶壶上打孔:
wood-hole-texture
我想做这样的事情:

var holes = new FunctionNode([
"void holes(vec3 texColor){",
" if (/*texColor too much dark*/) discard;",
"}"].join("\n"));
var holesCall = new FunctionCallNode(holes);
holesCall.inputs.texColor = new TextureNode(LoadTexture("holes-text.jpg"));

var myMaterial = new StandardNodeMaterial();
myMaterial.voidFunctions = [holesCall];
myMaterial.side = THREE.DoubleSide;

另一件事是我们无法控制着色器中函数的顺序。 如果我的函数不是可交换的,我就无法控制结果......

让我们看看这个例子:

var transparencyPlane = new FunctionNode([
"float transparencyPlane(vec 4 plane){",
" if (dot(position, plane.xyz) > plane.w) return 0.5.;",
" return 1.;",
"}"].join("\n"));
var transparencyPlaneCall = new FunctionCallNode(transparencyPlane);
transparencyPlaneCall.inputs.plane = myVec4Node;

var displacement = new FunctionNode([
"vec3 displacement(vec3 vector){",
" return position + vector;",
"}"].join("\n"));
var displacementCall = new FunctionCallNode(displacement);
displacementCall.inputs.vector = myVec3Node;

var myMaterial = new StandardNodeMaterial();
myMaterial.transform = displacementCall;
myMaterial.alpha = transparencyPlaneCall;

如果一个点在透明平面后面并且由于位移而超出,在“displacementCall”之前调用“transparencyPlaneCall”的情况下,alpha = 1.,在alpha = 0.5之后调用它的情况下。
所以我想设置函数调用的顺序...你知道我的意思吗?

@martinRenou

嗯,关于void函数可能是ProxyNode用于插槽,因为这需要遵循顺序或在代码的开头或结尾初始化,可能是functionsStartfunctionsEnd插槽...

如果alpha为 0,则使用alpha槽会自动取消。
https://github.com/mrdoob/three.js/blob/dev/examples/js/nodes/materials/PhongNode.js#L180

所以我想设置函数调用的顺序...

存在序列请参见此处:
https://github.com/mrdoob/three.js/blob/dev/examples/js/nodes/materials/PhongNode.js#L122

函数顺序是使用简单的dependencies算法自动完成的,应该将FunctionCall放在前一个插槽中,例如color是第一个specular是第二个。

这个例子是两个不同的着色器代码: fragmenttransparencyPlaneCallvertexdisplacementCall

这让我觉得使用变量( varying和 locals)来扩展而不是输入和 const 只会非常有趣。 也许VarNode ...

如果 alpha 为 0,则使用 alpha 槽会自动取消。

不好意思,没看到。

函数顺序是使用简单的依赖算法自动完成的,应该将 FunctionCall 放在前一个槽中,例如,颜色首先是高光,然后是第二。

我明白,实际上我只是想确保首先调用丢弃像素的函数。 如果您在我的函数之后丢弃它,那么使用 alpha 听起来不错:smiley:

这个例子是两个不同的着色器代码:片段到透明平面调用和顶点到位移调用。

对 ! 所以这不是一个很好的例子。 我的错。

完成 r6 - #9636

凉爽的 ! 感谢您的回答。

这让我觉得使用变量(变量和局部变量)来扩展而不是输入,而仅使用 const 会非常有趣。 也许是一个 VarNode...

听起来也不错,能够在顶点着色器中显式编写函数、使用 varNode 并将其与片段着色器中的函数一起使用可能会很有趣。 你不觉得吗?

@sunag
我认为在顶点着色器中使用 AttributeNode 和 FunctionNode 存在问题。

如果我有这样的代码:

var customData = new THREE.AttributeNode("data", "float");

var myFunc = new THREE.FunctionNode([
 "vec3 myFunc(float data){",
 " return vec3(data, 0., 0.);"
 "}"].join("\n"));
var myFuncCall = new THREE.FunctionCallNode(myFunc);
myFuncCall.inputs.data = customData;

material.transform = myFuncCall;

着色器按以下顺序编写:

...
varying float nVdata;
attribute float data;
...
float myFunc(float data){
 return return vec3(data, 0., 0.);
}

void main(){
...
transformed = myFunc(nVdata); // We use nVdata but it is not initialized
...
nVdata = data;
...
}

一个简单的解决方法是将 nVdata 初始化为 data ?

听起来也不错,能够在顶点着色器中显式编写函数、使用 varNode 并将其与片段着色器中的函数一起使用可能会很有趣。 你不觉得吗?

是的! 这个想法是使用varying作为VarNode与顶点/片段着色器更好地交流。 这非常适合keywords功能。

我创建了一个最小的varying示例,但还没有解决void function

我认为在顶点着色器中使用 AttributeNode 和 FunctionNode 存在问题。

固定 - https://github.com/mrdoob/three.js/pull/9681

@sunag ,我看到了你的变化示例,对我来说,像你那样将变量放在mtl.transform听起来很奇怪......也许你会在可以创建 void 函数时改变它?
但是,关键字功能 :smiley 听起来是个好主意:

事实上,我认为将这些变量放在mtl.varyings (mtl.variings 是一个数组)中是个好主意: mtl.varyings.push(myVar) 。 使用相同的想法,我们可以像这样在顶点和片段着色器中放置函数: mtl.vertexFunctions.push(myVertexFunctionCall) ,与mtl.fragmentFunctions

通过这种方式,我们可以对这些变量进行大量计算,然后将它们用于效果。 这些函数将是空函数。

就像上面的截图一样,节点在视觉上是连接的,我们如何用这个 API 在心理上重新创建它? 我看到构造函数接受其他节点。 这是一个节点的输出(传递给构造函数)是另一个节点的输入(它在其构造函数中接收节点)的方式吗? 一个节点是否最多有一个输出? 有多少节点可以通过构造函数输入到另一个节点,还是有限制?

@trusktr当然是有限的,这在构建时消耗更多的CPU和运行时消耗更多的GPU。 节点根据输入和输出值进行调整,例如floatvec2vec3的转换是自动的,如果多次使用则存储在缓存中以进行优化(见TempNode )。

在屏幕截图中,每个节点都是一个类,例如: PositionNode在显示中是:
https://github.com/mrdoob/three.js/blob/789efa65bafe022e178c7e93e0985a7607a54403/examples/js/nodes/accessors/PositionNode.js#L5

@mrdoob @sunag您是否愿意评论 NodeMaterial 代码的当前状态,以及它如何与three.js 路线图相适应?

理论上,我们现在可以将节点用于多种用途,例如:

  • 将 glTF spec/gloss PBR 材质实现为 NodeStandardSGMaterial。
  • 支持每张贴图的 UV 集和变换
  • 通过实例化简化内置材料的使用

但是很难证明在 GLTFLoader 中为所有节点文件添加依赖项是合理的。 如果没有更多的活跃使用,可能很难证明将节点放入src/*是合理的。 鸡蛋。 😅

了解 NodeMaterial 的长期计划,猜测哪些功能是(或不)相关的……这需要更多的开发吗? 其他贡献者可以做些什么来提供帮助吗?

@sunag是的,如果您此时有任何进一步的计划,我也很想知道。

理论上,我们现在可以将节点用于多种用途,例如:

  • 将 glTF spec/gloss PBR 材质实现为 NodeStandardSGMaterial。
  • 支持每张贴图的 UV 集和变换
  • 通过实例化简化内置材料的使用

这些特定问题现在有如何使用现有 API 解决的示例,而无需修改核心:

实例化:
https://github.com/mrdoob/three.js/pull/10750 (完全成熟,触及核心,但可能被猴子修补)
https://github.com/mrdoob/three.js/pull/14166 (简单,通过 onBeforeCompile 进行材料扩展)
https://github.com/mrdoob/three.js/pull/14012 (简单,通过 mokey-patching 扩展库)

per-map-uv 集
https://github.com/mrdoob/three.js/pull/14174

spec-gloss 作为它自己的类
https://github.com/mrdoob/three.js/pull/14099

也许它可以缓解将NodeMaterial纳入核心的紧迫感:)。

对于关注此主题的人, https://github.com/mrdoob/three.js/pull/14149 中有一些正在进行的讨论

加入来自 #14149 的线程:

tl;dr — 在我看来,NodeMaterial 是材质系统的一个非常有前途的下一步。 我怀疑 NodeMaterial 的采用目前受到以下几点限制:

  • 包含许多单独文件的摩擦
  • 缺少可视化编辑器
  • 相对较少的例子,文档

我会将 NodeMaterial 何时/是否应该在src/中的问题留给 @mrdoob@sunag ,但我认为我们应该(至少)解决上述三个问题。 了解其他人是否将 NodeMaterial 视为当前材质系统的替代品或完全替代品也会有所帮助。



临界质量似乎是由 GLTFLoader 利益相关者形成的,我的(主观)观察是,由于 onBeforeRender 的记录不正确(几个示例)和 onBeforeCompile 的记录更少(一个示例)而引起的需求。

@pailhead我开始维护 GLTFLoader 以解决 A-Frame 中的工作流问题,我也是其中的一名开发人员。 我同意更有用的材料系统是目标,而不是加载特定格式。 决定如何集成(或不集成)节点材料应基于three.js 库的最终用户的优点——特性、灵活性、可理解的API。

你是对的, onBeforeCompileonBeforeRender钩子是无限灵活的; 您可以操纵或替换底层着色器的程度没有实际限制。 但作为主要的材料 API,两者都存在类似的缺陷:

  1. 即使对于相对简单的功能,也将 WebGL 语法强制纳入材料 API
  2. 取决于核心材质着色器的字符串操作,随着时间的推移,对核心材质的更改变得更加困难,也更加脆弱
  3. 对艺术家来说不太平易近人
  4. 实际上不可序列化

从用户的角度来看,装饰器(例如#14206)肯定会改进这一点——但如果未来材料的功能开发将基于现有材料着色器之上越来越复杂的装饰器,那么在我看来,这是一个可维护性风险。

节点材质并不完美,但它们在其他图形工具中被广泛采用,并具有关键优势:

  1. 灵活可组合
  2. 保留来自库内部 WebGL 着色器的抽象层,而无需在需要时移除对普通着色器的访问
  3. 艺术家和游戏开发者广泛流行的材料表现形式
  4. 至少在某种程度上可序列化(尽管转换为其他格式仍然很困难)

这可能听起来像我说onBeforeCompile应该被弃用,我不是故意的 - 我很高兴看到它继续存在,并且欢迎使用示例。 但这不是我想将 A-Frame 或three.js 用户指向更多情况下不必要的API; 我认为它与其他 3D 工具中的材料系统相比不太好。

  • 包含许多单独文件的摩擦

这不应该是摩擦。 我认为做一些调查或其他事情会很有用,看看有多少人使用捆绑器和构建工具。 手动在 html 文件中导入 js 文件不应该是 2018 年真正的方法。这是我能找到的唯一数字,我认为可以假设所有这些用户都在使用它与 node.js 一起运行的东西。

我会付出更多的努力,在摇树上并正确地能够import/export这样做,而不是担心手动包含脚本文件时这会如何工作。

  • 缺少可视化编辑器
  • 相对较少的例子,文档

我认为这些应该在它成为核心之前发生。 镜面光泽材质应该是一个没有与GLTFLoader耦合的例子。 它在/src/examples的事实应该无关紧要?

@donmccurdy

你是对的 onBeforeCompile 和 onBeforeRender 钩子是无限灵活的; 您可以操纵或替换底层着色器的程度没有实际限制。

我实际上并不是在声称这一点,我声称像onBeforeRender这样的钩子允许采用不同的方法来构建代码,但是不应该像现在在GLTFLoader那样使用它

onBeforeCompile肯定有局限性,并且可能命名不当。 在这种情况下要指出的一件好事是最近的 PR #14214。 当我看到什么消失了( build()支持needsUpdate )我知道我会在那里看到onBeforeCompile 。 我将它用作onBeforeParse因为如果我不替换任何#include <foo>语句,它们仍然会在此函数之后和实际编译之前被解析。 在这个 PR 中,它被用作onWillRefreshMaterial

我试图传达的理念是,这些类型的回调可能应该有更多的粒度。 它们应该更多,并且在命名它们时应该非常小心。

#14214 是一个很好的例子,说明了为什么NodeMaterial不必在核心中。 至少没有与/renderer任何内容耦合,也没有与它捆绑在一起。

  1. 即使对于相对简单的功能,也将 WebGL 语法强制纳入材料 API

我之前听说过这个问题,但没有详细说明。 为什么这是个问题? 什么是“材料 API”? 我总是将其视为“这里有一些常见的表面着色材料”。

如果您想要动态贴图,我认为没有理由material.map或 'material.color' 不能采用NodeTextureGLSLTextureTextureTexture

myMaterial.color = new SomeNodeGraph() //outputs vec4 in the end

myMaterial.color = new GLSLInput() // inputs various documented variables, outputs some vec4

myMaterial.color = new THREE.Color()

myMaterial.color = new CustomColorGradientTopBottom() // dunno if its Node, GLSL, regular color whatever, i just know it's compatible with the slot
  1. 取决于核心材质着色器的字符串操作,随着时间的推移,对核心材质的更改变得更加困难,也更加脆弱

我的观点是,使用onBeforeCompile已经有些可能,但是使这些更改比您所描述的更难,更脆弱。 我已经在我的职业生涯中接触过这个,并且有一些依赖它的代码。 它是多么脆弱,造成了很大的压力:(

你指出的#14206 的装饰器因为这个 PR 已经停滞了一年多,而这个 PR 本身已经停滞了 3 年。 我的主观感觉是#14206 将使编写这些装饰器成为可能,不那么乏味,也不那么脆弱。 除非定义了这些幻影属性,否则这 30 行代码绝对不会影响任何事情。 如果我们已经得到一根绳子以onBeforeCompile的形式上吊,为什么不让它更人性化一点呢? :微笑:

最后,我想自己决定什么是可接受的脆弱程度,什么不是。

  1. 对艺术家来说不太平易近人

这就是为什么艺术家应该有一个可视化工具,以及某种格式来保存图表。 使用它们作为“烘焙”GLSL 或在运行时构建NodeMaterial的东西应该是给用户的选择。

美术师可以创建着色器,工程师可以要求对其进行“编译”以优化加载过程。 一个单独工作的艺术家可以只加载图表,假设由于某种原因更容易(“编译”需要更多的努力)。

另外,为什么以及如何在这里考虑艺术家? 有没有一些统计数据,一个普通的“艺术家”用户是什么样的,为什么他们使用three.js而不是unity,即。 它是什么样的管道。 是否有工程师参与,为什么不以某种方式与一些技术目录采用的three.js 进行通信的独立工具等。我假设每周 40k npm 下载量不是艺术家。 假设某些构建工具正在使用这种安装,并且极不可能手动导入。

关于这一点和第 2 点,我的用例不涉及艺术家,通常也不涉及其他用户。 我正在开发一个建立在内置材料之上的材料系统。 我使用我自己的带有切线属性、深度剥离、不同剪裁等的正常解包。我所关心的是在内部构造该代码,并将少量内部结构暴露给上述类。

  1. 实际上不可序列化

我对此知之甚少,我以前听说过这种论点。 如果有人可以指出有问题的区域,我会非常乐意查看一些代码。 由于我对这个问题的理解非常有限(几乎没有),我不明白为什么写它是不够的

"materialFoo": {
  "color":"#ff0000",
  "specularMap": "some_path.jpg",
  "glossiness": "0.5"
}

假设您有一个使用NodeMaterial构建的规范光泽材料,您不想序列化整个图形,只序列化输入? 无论SpecGloss材料的序列化是什么,它看起来都应该一样吗? 我可能在这里遗漏了很多,希望得到一些指点。

回复:序列化

是否足以添加:

https://github.com/mrdoob/three.js/blob/dev/src/materials/Material.js#L160

customSerializer( data )

然后像

SpecularGlossMaterial.prototype.toJSON = ()=>{
  Material.prototype.call(this, undefined, data =>{
    if ( this.roughness !== undefined ) data.roughness = this.roughness;
  })
}

specularMap实际上会被序列化,因为它是硬编码的:
https://github.com/mrdoob/three.js/blob/dev/src/materials/Material.js#L213

但这感觉有点奇怪, Material类似乎知道所有内置材料的内部结构?

@donmccurdy如果您想进行此讨论,最好在装饰器 PR #14206 中进行。 离线时,我可以在湾区的任何地方喝啤酒或喝咖啡参加工作会议:slightly_smiling_face:

同意多个文件_不应该_是摩擦,并且它本身不是将 NodeMaterial 放入src/的论据。 这只是 NodeMaterial 尚未大量使用的几个原因之一,还有其他方法可以解决这个问题。 我当然同意更多的文档是将 NodeMaterial 放入src/的先决条件,甚至是推动采用examples/js或单独的构建输出的先决条件。

我对NodeMaterial作为总体方向持乐观态度,尽管我怀疑在src/它有意义之前还需要一些其他东西。 我非常担心使用onBeforeCompile和字符串操作作为将新功能放入材质系统的路径,如上所述,尤其是当我们转向支持 WebGL2 和(最终) WebGPU 时。 这并不是说这两个选择是唯一的选择,但(两者中的)这些是我的想法。

在其他方面,我们似乎理解彼此的担忧和偏好,但仍然存在分歧。 我已经写完了我现在有时间写的所有内容,并将暂时搁置一段时间,让其他人参与进来。感谢您对此进行彻底和礼貌的讨论。 🙂

我想在漫反射纹理上放置一个带有乘法的环境遮挡纹理,所以我正在尝试这个:

const aoNode = new OperatorNode(
        new Math1Node( aoTexture, Math1Node.INVERT ),
        aoScale,
        OperatorNode.MUL
    );
material.ao = aoNode;

这是我的 AO 纹理
ao sx

不幸的是,我一直在我的模型上看到环境遮挡。

你有什么想法吗?
希望这是发布我的问题的正确位置。

谢谢!

我希望能够思考从现有基于节点的工具到 Threejs 材料的映射方向。 因此,我希望在 src/ 中看到 NodeMaterial 以及适当的文档。

@IARI

你能列出现有的基于节点的工具吗?

@donmccurdy

感谢您的答复 :)

不幸的是,我认为我们仍然不了解对方。 如果你有时间阅读这篇文章,这些东西:

我非常担心使用 onBeforeCompile 和字符串操作作为将新功能放入材质系统的路径,

onBeforeCompile太可怕了,我同意,我参与这些线程中的任何一个的唯一原因是我想要 #13198,我认为它优于onBeforeCompile的字符串操作。

这不应该成为向three.js 添加新功能的模式。 它应该允许用户向他们的应用程序添加新功能。 我很遗憾@bhouston没有分享任何关于维护叉子来做这些事情的发现。 我很好奇他们是否制作了一个更好的框架来更改着色器,或者实际上已经为该功能破解了核心。

在每通道 uv 变换的情况下,我会举一个例子,或者 npm 模块。 如果每周有 3 人下载它,那么它可能是不应该在核心中的东西。 如果有 20k 人下载它,那么three.js 最初应该是如何设计的。

onBeforeCompile似乎对节点材料至关重要, https://github.com/mrdoob/three.js/pull/14214因此它不仅用于字符串操作

我有onBeforeCompileNodeMaterial来做这些,我请求第三个选项。 比onBeforeCompile方便得多,比NodeMaterial小得多。

以最近的例子:
https://github.com/mrdoob/three.js/pull/14206

旧讨论:
https://github.com/mrdoob/three.js/pull/13198

@pailhead对于初学者,我会考虑一些基本的 Blender Cycles 节点。
我也会发现使用 Unity Shadergraph 很有趣。

@claudioviola您可以添加material.shadow或乘以漫反射material.color = diffuse * oclusion 。 间接光的遮挡, AmbientLightHemisphereLight ...

@IARI

我正在下载 7.5 gigs 的 Unity 来查看 ShaderGraph :slightly_smiling_face:: 我不确定它是否有资格作为构建着色器图的工具,我认为它是构建统一着色器图的工具。 是否有任何用于创作图形的独立工具? 我想看看这也保存了什么样的文件,以及它如何转移到 Three.js 和/src NodeMaterial /src

我认为@pailhead目前与 NodeMaterials 进入核心的这一举动是孤立的。 我认为与@pailhead争论几天对每个人都没有用。 我认为这个项目不应该受制于一个人。

这不是仓促的,也不是被迫的。 苏纳格多年前补充道。 现在需要这样做,而其他替代方案尚未解决(例如合并),所以让我们尝试这条路。

每个主要工具,3DS Max、UE4、Blender、Unity、Maya、Sketchfab 都使用着色器图。 认为three.js在这方面应该处于永久劣势似乎对three.js不公平。

我不确定这个基于图形的着色器系统此时是否完美,但是一旦它成为核心,我们都可以继续使用它。

我确实坚持我们会继续以某种方式支持 PhoneMaterial、StandardMaterial 等的 API,这样我们就不会破坏 95% 的three.js 项目,这样做是不负责任的。 使用这种简化的直接界面也很好。

我既没有能力也不想阻止它进入核心。 我只是希望它可以解除一些不相关的 PR,因为它已被称为阻止程序。 @bhouston ,也从来

当我作为一个饥饿的 3d 艺术家入不敷出时,我喜欢所有基于节点的东西。 Nuke 是我最喜欢的作曲家,我想学习如何制作这样的工具。 我只是希望这能特别解除这个#14231。 我正在将其用作自己的学习平台,但如果它具有破坏性,我将停止发布,谢谢。

@pailhead我从未使用过它,但您可能听说过 Substance Designer? 据我所知,该工具还超出了创作图形/着色器的范围——但它主要关注材料的程序设计——也许这是一个有趣的线索?

除此之外,我从头顶上不知道独立工具,但快速的谷歌搜索产生了这两个:

但是,也有这个用于 Threejs 节点的@mrdoob的推特帖子中找到了它——虽然它似乎从未更新过,但我想知道为什么......

该工具似乎已在此处引用,但我看不到导出任何内容的方法。 第一个链接看起来很棒,但输出非常粗糙,与 GLSL 相比可读性不高。 我想知道它是否可以用于重新组装NodeMeterial ,甚至ShaderMaterial

我查看了 unity,但实际上找不到着色器图形工具,

顺便说一句,如果我以某种方式阻止了它,请务必让它解除阻止。 PR是2015年的,我8天前第一次回复。

(对不起,这有点离题了..)
@pailhead对于 Unity 着色器图:您需要使用轻量级渲染管线模板启动一个统一项目。 确保打开 Unity Package Manager 并检查您使用的是最新版本的 Render-pipelines.light 包。
这是一个从设置新项目开始设置它的教程: https :

Sea3D Flow 材质节点编辑器 (http://sea3d.poonya.com/flow/) 是由@sunag 编写的,他是编写 NodeMaterial 的人。

非常感谢@sunag
我怎样才能获得间接光? 它是渲染器中的一个值还是我如何计算它?

我想仅对选定的对象应用后处理效果(即更改饱和度)。
但是,我找不到与节点屏蔽(如果没有其他方法)相关的任何内容。
目前我正在阅读(非节点)OutlinePass,它将一堆东西写入一堆缓冲区,我可以将其视为实现我想要的可行方法 - 但我对如何处理一无所知这与节点。

Sea3D Flow 材质节点编辑器将与three.js 编辑器一样独立,还是成为其中的一部分? 它仍然会被命名为 Sea3D 或其他与 Three.js 相关的东西吗? 感谢@sunag将该可视化编辑器发布到three.js 社区。

但我对如何用节点解决这个问题一无所知。

@IARI

您似乎了解 GLSL,因为您能够阅读 OutlinePass 并了解它的作用。 您似乎也足够了解它,以看到您无法使用节点来实现它。 我想如果你知道如何编码,你就会知道如何节点。 更重要的是,如果您不知道如何编码,您可能知道如何对其进行节点处理。 断线在哪里?

我根本没有看到 2016 年的这些帖子。 有趣的是看到Shader Frog。 我想知道这是否可以看作是 vim vs emacs 之类的。 我喜欢用 Sublime Text,你喜欢用别的东西。 一个喜欢用shaderfrog,另一个喜欢用three.js的Sea3D编辑器。

我喜欢 Shader Frog 只是输出一个着色器,但它不像 Sea3D 那样是开源的。

然后就是这个。

将第三方产品机制放入 Three 的核心似乎是一种不公平的优势,我在政治上不理解。

对我来说,所有这一切都可以在没有三个更改的情况下完成的事实意味着它是不必要的,并且模糊了 Three.js 作为 webgl 包装器 API 和现在驱动实现特定功能之间的界限。 存储着色器节点数据是高度特定于应用程序的,据我所知,目前没有任何软件的通用节点编辑器标准格式? 强制执行一个可能对其他实现有害。

@bhouston
我等不及NodeMaterial落地了,因为它可能会解锁其他 PR,生活可以恢复正常。 过去似乎有其他声音试图阻止这一点。

我认为@pailhead目前与 NodeMaterials 进入核心的这一举动是孤立的。
我认为这个项目不应该受制于一个人。

谢谢你。

我看不出有任何理由不能用与outlinepass 完全相同的方式使用节点来实现它——但是以一种可读、可理解和模块化的方式实现,以便部件可以重用。
为什么不应该有例如写入缓冲区和东西的输出节点。

而且我真的不太了解 glsl,而且我发现它 - 请原谅我的措辞 - 阅读和编写着色器代码非常痛苦。 最重要的是,如果将其包裹在 javascript 代码中的字符串中的愚蠢数组中,则它会更加痛苦。

你用的是 webpack 还是什么?

愚蠢的数组

如果您必须将其导入 .html 文件,那只会是愚蠢的。 当您使用 webpack 并且拥有现代 JS 语法时,您可以将 GLSL 保存在 .glsl、.vs、.fs 文件中,并具有语法高亮等功能。

着色器.fs:

void main(){
  gl_FragColor = vec4(1.);
} 

javascript(看妈妈,没有愚蠢的数组)

import mShader from './shader.fs'

我担心的是,我认为您的需求没有多大价值,因为您特别询问如何创建效果,而不是如何编写代码。 NodeMaterial为数以千计的“我如何遮蔽这种效果”的问题打开大门,这些问题只会有一个通用的答案:

使用节点,卢克!

不,必须在同一个文件中阅读(更不用说编写)两种不同语言的代码对我来说总是很痛苦。 同样,当您尝试研究 Threejs 示例着色器代码时,webpack 也无济于事,这些代码全部包裹在由换行符连接的丑陋字符串数组中。
无论如何,这个问题是关于节点系统的,我问了一个关于节点的简单问题 - 不是关于个人编码偏好的讨论 - 没有任何意义。

@IARI

抱歉,我不知何故在你的帖子中没有看到任何问号,所以我错过了你的问题。

这绝对不应该是关于个人编码偏好的讨论,但应该考虑存在不同的事实。 我也有点担心“我如何制作这个着色器”的问题。

以前,这个标准很高,人们只是放弃i don't know glsl或当他们看到“字符串中的愚蠢数组”时。 但是如果它更低,那么每个人都会尝试编写着色器。

我没有找到你的问题,但我很好奇它是什么。 是吗:

如何使用 NodeMaterial 制作 ToonShader?

在这种情况下,我很好奇答案是什么。

你不能,因为 NodeMaterial 不支持一些抽象。
您可以只使用 NodeMaterial 来连接节点

也许这个讨论可以从打破中受益? 这是一个很高的帖子数量,可以追溯到很久以前(2015 年)。 NodeMaterial 位于 /examples 中,因此您可以从中构建卡通着色器。 也许您可以专门为此打开另一个问题或在堆栈溢出上发帖,然后对话的其余部分可能会转移到一个新问题?

我们可以很高兴地在其他地方讨论这个问题,比如一些松弛的频道或其他什么——我真的觉得它不属于这里,但主要是会惹恼人们。

对于这种特殊情况,论坛可能比 slack 更好。

@pailhead ,整个讨论已经脱离了富有成效。 不妨关闭这个问题,并针对手头的实际问题制作一个新的问题。

@bhouston

同意,但我认为这是多个问题。

  • 如何实现节点材料
  • 是否应该阻止其他相关和不相关的 PR
  • 如何让不知道如何编写着色器的人实现某些着色器效果

如何使用 NodeMaterial 制作 ToonShader?
在这种情况下,我很好奇答案是什么。
你不能,因为 NodeMaterial 不支持一些抽象。
您可以只使用 NodeMaterial 来连接节点

哈哈。 我同意@bhouston...这只能是个玩笑。 在你说之前,你可能已经看到了webgl_materials_nodes的例子?

如果您想使用代码,请参阅使用FunctionNode表达式。

toon

@sunag我想你误解了我。 我很好奇为什么,如果它目前在/examples而不是/src中,这是否会成为一等公民。 这个问题似乎是由@AndrewRayCode在 2015 年提出的。

我只是说这个问题已经超负荷了,因为它可以追溯到 2015 年,并且讨论了各种不同的主题。 如果有人问“我如何制作whatever ”,他们将被称为堆栈溢出。

如果这将是对three.js 的大规模改革_(必须为此专门配置unity 的事实让我有些害怕)_ 那么我认为github 上应该有一个持续的问题专门用于解决此类问题 - usage of NodeMaterial 。 照原样,要求随机事物的人 (#14232) 被引用到此线程,这使通信变得混乱 :)

我最近不得不编写一个卡通着色器,但它基于线条,更具体地说是@WestLangley 的粗线条。 因此,即使需要“香椿”着色器,我的情况也会完全不同。 它还涉及将粗线移植到NodeMaterial ,这可能需要多长时间。 这些都是在这里令人费解的各种主题。

如果您想使用代码,请参阅使用 FunctionNode 的表达式。

如果我编写代码,我将使用崇高的文本, ShaderMaterial对我来说很好,不需要FunctionNode 。 如果我创建视觉效果,我可能会考虑使用可视化编辑器,但这是我自己的偏好。 我来这里只是因为这阻止了其他 PR :) 我不久前意识到,尽快降落实际上符合三个人的最佳利益。 解开这场谈话可能有助于加快事情的进展。 在这一点上,我同意@bhouston这应该是 yolod 尽快!

谢谢你。

声明:我对卡通着色器或类似的东西不感兴趣。
我正在实现一个系统,它允许不会编写代码的人在某些位置插入简单的预定义效果。

可悲的是,我恐怕现在没有时间研究如何编写节点,无论如何我必须赶上基本的 glsl 编码,所以现在我将实现没有节点的东西:它不会是可扩展的,它将使用多个渲染通道,其中单个渲染通道对于良好的节点实现可能就足够了,它的可读性会降低,......

总而言之,遗憾的是,我只是对一般主题不熟悉,需要做更多的基本了解,但根据我的了解,节点将是以真正优雅和可扩展的方式做到这一点的最佳方式。
我非常希望有一些关于节点实现的信息,比如博客文章或教程。

免责声明:我不要求任何东西,只是希望澄清我上面模糊的要求。
感谢你们所有人在这里所做的所有工作 - 这绝对是惊人的。

我在线程https://github.com/mrdoob/three.js/issues/14232 中被要求评论基于节点的着色器实现。 我认为这是非常贫穷的。 我喜欢这个想法,但在我看来实施是完全不够的,所以,既然我如此消极,我将提供一些具体的原因。

易懂

在阅读了 Nodes 和各种实用程序类的一些代码后 - 我可以肯定地说,理解它是一个巨大的挑战。

  • 变量名是非描述性的
  • 根本没有评论
  • 方法名称晦涩难懂或完全具有误导性。 (例如,您认为“构建”方法的作用是什么?- 猜一猜)

代码结构非常奇怪。 考虑这个片段:
https://github.com/mrdoob/three.js/blob/e2b49c017b2d1f37ab34317033a27df7b5a71d4d/examples/js/nodes/FunctionNode.js#L39 -L50

您可以通过以下方式实现相同的目标:

return this.inputs.find(input => input.name === name);

《新兴建筑》

什么是“节点”? 我要求定义数据结构,因为它似乎只是一个模糊的概念,因为不同的“节点”之间几乎没有共同点,它看起来像鸭子,如果它像节点一样嘎嘎叫 - 它就是节点。

关注点分离

你如何从NodeShaderMaterial ? 现在,它是来自每个节点、一些构建器、一些缓存、解析器等的各种逻辑部分之间的责任混合。这个过程没有明确的责任。 Node 使用 NodeBuilder? 什么...? 尽管 NodeBuilder 是一个生产或构建节点的工厂,但从我的名字来看,它实际上是一个辅助结构。 据我所知,这里有相当不同的工作要做:

  • 构建图表
  • 证实
  • 构建中间表示
  • 优化
  • 编译为 GLSL

根本不是您在当前代码中会发现的。

结论

如果没有好的文档和评论,我认为这个实现是完全不够的。 有了这些东西,那就是意大利面条式代码和缺乏设计的问题。 话虽如此 - 我承认它是一个强大的工具,也是一个非常有用的概念的有效实现。

@Usnul我们永远不会在 Three.JS 中这样编码“return this.inputs.find(input => input.name === name);”

原因是“=>”创建了一个必须在每个输入上调用的函数。 与 for 循环或 while 循环相比,JavaScript 中的函数调用非常慢。 因此,我们总是执行显式循环而不是面向回调的代码。 我知道它更冗长,但这是必要的。 所有三个..JS 都是这样的,并且是故意的。

@Usnul ,您的设计问题非常有用,那么您能帮助进行一些重构吗? 我想每个人都会感谢你的设计投入和贡献。 :)

原因是“=>”创建了一个必须在每个输入上调用的函数。 与 for 循环或 while 循环相比,JavaScript 中的函数调用非常慢。 因此,我们总是执行显式循环而不是面向回调的代码。 我知道它更冗长,但这是必要的。 所有三个..JS 都是这样的,并且是故意的。

这是一个公平的观点。 就我个人而言,我的哲学是性能和可读性应该在一个规模上而不是一个或另一个,但一致性是好的。 我对该特定示例的主要问题是它不是迭代数组的常用方法。 这是一个惯用的方法:

for(var i=0, count=array.length; i<count; i++){
    var element = array[i];
    ...
}

或者假设您有一段 50 行长的代码:

function complex(a){
  if(a){
      //do a ton of stuff
      ...
      return result;
  }
}

这不像:

function complex(a){
  if(!a){
      //omg! not A?!11 
      return;
  }
  //do a ton of stuff
  ...
  return result;
}

@Usnul你能帮助重构代码以将这些考虑在内吗? 我认为重构应该很容易,对吧? 我是 Code Complete 的忠实支持者,那本书对我影响很大。

@usnul如果你不喜欢这个,你可以自由重构这个吗? 它看起来像与否并不重要,重要的是它建立在此之上,这是我的理解。
我不知道折射器是否应该在示例中(或可能是另一个存储库)发生,还是应该像@bhouston建议的那样直接移到 src 中。

@IARI

我真的不太了解 glsl ,而且我发现它 - 请原谅我的措辞 -阅读和编写着色器代码非常痛苦

但根据我所知道的,节点将是以真正优雅和可扩展的方式做到这一点的最佳方式。

我也不能说我非常了解 GLSL,但我知道它足以解决我的问题。 据我所知,我基本同意@usnul在这里写的内容,以及@AndrewRayCode之前写的内容。 与 GLSL 相比,我发现节点的事情很

如果您不了解 GLSL,我认为很难将其与其他内容进行比较。 正如你自己写的那样,如果我们judge on what you know ,并且你自己说you don't know glsl我认为你的意见应该带有免责声明:)

就像我说:

日本是这个星球上最糟糕的地方……但我从未真正去过日本”。

谢谢你。

方法名称晦涩难懂或完全具有误导性。 (例如,您认为“构建”方法的作用是什么?- 猜一猜)

哇,我什至没有意识到下面是ShaderMaterial 。 我的猜测是,这完成了THREE.WebGLRenderer对着色器模板所做的所有事情。

我真的不太了解 glsl,而且我发现它 - 请原谅我的措辞 - 阅读和编写着色器代码非常痛苦。
但据我所知,节点将是以真正优雅和可扩展的方式做到这一点的最佳方式。

@pailhead他的意思是事物之间存在中间层次。

我不明白为什么这个警报。 @mrdoob除了一个很好的解决方案外,永远不会合并其他东西。 所有伟大的公关,来自NodeMaterial与否的任何人的改进对社区都非常有用。 如果这仍然没有在核心合并,那是因为我们需要做更多的工作来改进。

@sunag有什么特别的其他人可以帮助您完成这个项目吗? 如果您准备好文档并且可以查看它们,我愿意编写文档。

@sunag有什么特别的其他人可以帮助您完成这个项目吗? 如果您准备好文档并且可以查看它们,我愿意编写文档。

这会很棒。 毫无疑问,帮助很大。

基于节点的材质系统看起来很神奇,它会扩展表达的力量。

我们将如何从现有的材料系统切换到基于节点的核心材料系统? 我们会同时使用两个系统还是用节点一替换现有的系统?

抱歉,也许我认为我没有赶上这个线程,因为这个线程太大了......

我们会同时使用两个系统还是用节点一替换现有的系统?

我认为更换是最终目标,性能和维护都更好。 下一步是在核心中制作MeshStandardNodeMaterial和其他节点材料,在视觉、语法和性能方面与核心完全一样。

我必须在我的项目中显示 shadowMap。

我有一个使用 MeshStandardNodeMaterial 的具有定向光和 2 个几何体的场景。

我已开启
castShadow = 光为真
两个对象的 castShadow 和 receiveShadow 。
shadowEnabled = true 渲染器

为什么不起作用?
我是否必须使用 MeshStandardNodeMaterial 的 shadow 属性? 这是目的吗?

任何人都可以帮助我吗?
谢谢!

@克劳迪奥拉
支持问题请访问 stackoverflow 论坛。

@sunag你认为NodeMaterial是否足够稳定,所以我们可以从提供 TypeScript 声明文件开始? 如果您不打算在不久的将来进行重大的 API 更改,我将从这项任务开始,因为NodeMaterial是最后一组没有 TS 支持的模块。

@sunag你认为 NodeMaterial 足够稳定,所以我们可以从提供 TypeScript 声明文件开始吗? 如果您不打算在不久的将来进行重大的 API 更改,我将从这项任务开始,因为 NodeMaterial 是最后一组没有 TS 支持的模块。

@Mugen87是的,必须有更多的添加而不是更改。 添加 TS 支持会很棒。 👍

好的,TS 支持已准备就绪,下一个版本R017 🙌

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

Bandit picture Bandit  ·  3评论

akshaysrin picture akshaysrin  ·  3评论

jack-jun picture jack-jun  ·  3评论

donmccurdy picture donmccurdy  ·  3评论

filharvey picture filharvey  ·  3评论