将PointLight Info传递给具有three.js的自定义着色器

时间:2014-05-27 22:17:03

标签: javascript three.js glsl webgl

我想创建一个类似于undulating sphere中描述的Aerotwist Tutorial的效果。但是,在教程中,Paul在片段着色器中创建了一个假的GLSL硬编码光 - 而我想将信息从three.js PointLight实例传递到我的着色器,操纵顶点/法线,然后执行Phong着色。

我对在three.js中着色场景时对GPU考虑的各种级别的理解如下(例如,坚持使用Phong):

  1. 没有GPU考虑:使用MeshPhongMaterial并且不用担心着色器。这非常容易,但不会让你在GPU方面乱七八糟。
  2. 一些GPU考虑因素:使用ShaderLib Phong着色器。这允许您将着色计算推送到GPU,但由于它们是预先编写的,因此您无法对顶点位置,法线或照明计算进行任何自定义修改。
  3. 完整GPU管理:使用ShaderMesh并从头开始编写着色器。这为您提供了完全自定义,但也强制您明确传递着色器所需的属性和制服。
  4. Q1:上述理解是否准确?

    Q2:有没有办法在2级和3级之间做点什么?我希望能够自定义着色器来混淆顶点位置/法线,但是当一个非常好的着色器包含在three.js中时,我不想编写自己的Phong着色器。

    问题3:如果2级和3级之间没有这样的中间位置,我需要进入3级,那么最好的方法是什么?我是否将光的位置,强度等作为制服传递,进行顶点/正常修改,然后最后明确写出Phong着色计算?

2 个答案:

答案 0 :(得分:3)

用three.js做你要求的事情非常简单

我不确定Q []

中的位置

Q1

  1. 您仍在使用着色器,其他人为您编写了这些着色器。您只能访问该界面。在引擎盖下,调用MeshBasicMaterial这样的东西实际上可以根据你输入的内容编译一个不同的着色器。比如,它可能不会处理任何UVS,如果没有调用地图等,则不会将它们包含在着色器中。您仍然可以根据所调用的内容影响GPU。
  2. 如果你指的是着色器块,可以在这里破解东西,但这很麻烦。我的建议是研究代码,例如phong着色,并开始使用块来逐个构建自己的代码。看看会发生什么,发生什么。
  3. 无需传递属性。 THREE.ShaderMaterial并非完全从头开始构建。它仍然为您提供了相当多的东西,并且有许多属性可以设置为获得更多。一个的基本属性,为您设置,即。你没有声明“属性vec3位置”。如果您将照明标记勾选为West图示,则可以获取包含场景中所有灯光的数组,但是如果您正在构建粒子着色器或某些屏幕效果,则可以忽略它。几乎每个着色器都设置为读取一些基本属性,如“位置”'uv''正常'。您可以轻松地在程序网格上添加自己的网格,但在实际模型上,这并非易事。你默认得到一些制服,你得到整套MVP矩阵,'cameraPosition'等。从那里写一个phong着色器是很简单的。
  4. 现在你将如何做到这一点。假设您正在学习本教程,并且您有这个着色器:

    // same name and type as VS
    varying vec3 vNormal;
    
    void main() {
    
    
    //this is hardcoded you want to pass it from your environment
    vec3 light = vec3(0.5, 0.2, 1.0);//it needs to be a uniform
    
    // ensure it's normalized
    light = normalize(light);//you can normalize it outside of the shader, since it's a directional light
    
    // calculate the dot product of
    // the light to the vertex normal
    float dProd = max(0.0,
                    dot(vNormal, light));
    
    // feed into our frag colour
    gl_FragColor = vec4(dProd, // R
                      dProd, // G
                      dProd, // B
                      1.0);  // A
    
    }
    

    以下是您需要做的事情:

    GLSL

    uniform vec3 myLightPos;//comes in
    void main(){
        vec3 light = normalize(myLightPos);//but you better do this in javascript and just pass the normalized vec3
    }
    

    的Javascript

    new THREE.ShaderMaterial({
       uniforms:{
          myLightPos:{
             type:"v3",
             value: new THREE.Vector3()
          }
       },
       vertexShader: yourVertShader,
       fragmentShader: yourFragmentShader
    
    });
    

答案 1 :(得分:1)

Q1:正确。虽然,该主板上的一些用户已经发布了针对黑客攻击MeshPhongMaterial的解决方法,但这不是最初的意图。

Q2和Q3:查看ShaderLib.js,您将看到“法线贴图着色器”。这是一个完美的模板。是的,您可以复制/重命名并根据自己的喜好进行修改。

它使用基于Phong的照明模型,甚至可以为您访问场景灯。你这样称呼它:

var shader = THREE.ShaderLib[ "normalmap" ];

var uniforms = THREE.UniformsUtils.clone( shader.uniforms );

. . .

var parameters = {
    fragmentShader: shader.fragmentShader,
    vertexShader: shader.vertexShader,
    uniforms: uniforms,
    lights: true // set this flag and you have access to scene lights
};

var material = new THREE.ShaderMaterial( parameters );

请参阅以下示例:http://threejs.org/examples/webgl_materials_normalmap.htmlhttp://threejs.org/examples/webgl_materials_normalmap2.html

有关要遵循的编码模式,请参阅ShaderLib.jsShaderChunk.js

three.js r.67