在 threejs 可视化中从 webgl 上下文填充着色器属性

filling shader attributes from webgl context in threejs visualization

我正在使用一些现有的 webgl 教程学习着色器,我希望有一种方法可以将已编译的着色器程序附加到 threejs 着色器material,但我被卡住了.如果可能的话,最好使用 gl 方法设置属性和制服,然后在 material 上设置着色器程序。这是我试过的。

<!doctype html>
<html>
    <head>

        <script src="http://threejs.org/build/three.min.js"></script>
        <meta charset="utf-8" />
        <title>Sample Three.js</title>
        <style>
            #container {
                background: #000;
                width: 400px;
                height: 300px;
            }
        </style>
    </head>
    <body>


    </body>

    <script type="x-shader/x-vertex" id="vertexshader">
        // switch on high precision floats
        #ifdef GL_ES
        precision highp float;
        #endif
        uniform mat4 projectionmyMatrix;
        attribute vec3 vertexPos;
        attribute float displacement;
        uniform float amplitude;

        void main()
        {
            vec3 newPos = vertexPos;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(newPos,1.0);
        }

    </script>

    <script type="x-shader/x-fragment" id="fragmentshader">
        #ifdef GL_ES
        precision highp float;
        #endif

        void main( void ) {

           gl_FragColor = vec4( 1.0,1.0,1.0,1.0);

        }
    </script>

    <!-- End Shaders -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>

    <script type="text/javascript">
    // set the scene size
    var WIDTH = 800,
        HEIGHT = 600;

    // set some camera attributes
    var VIEW_ANGLE = 45,
        ASPECT = WIDTH / HEIGHT,
        NEAR = 1,
        FAR = 1000;

    // get the DOM element to attach to
    // - assume we've got jQuery to hand
    var $container = $('body');

    // create a WebGL renderer, camera
    // and a scene
    var renderer = new THREE.WebGLRenderer();
    var camera = new THREE.PerspectiveCamera(
        VIEW_ANGLE,
    ASPECT,
    NEAR,
    FAR  );
    var scene = new THREE.Scene();

    // the camera starts at 0,0,0 so pull it back
    camera.position.z = 300;

    // start the renderer
    renderer.setSize(WIDTH, HEIGHT);

    // attach the render-supplied DOM element
    $container.append(renderer.domElement);

    // set up the sphere vars
    var radius = 50, segments = 16, rings = 16;


    // create the sphere's material
    var shaderMaterial = new THREE.ShaderMaterial({
        vertexShader:   $('#vertexshader').text(),
        fragmentShader: $('#fragmentshader').text()
    });
    // create a new mesh with sphere geometry -
    // we will cover the sphereMaterial next!
    var sphere = new THREE.Mesh(
       new THREE.SphereGeometry(radius, segments, rings),
       shaderMaterial);

    //filling the attribute vertex array

    // add the sphere and camera to the scene
    scene.add(sphere);
    scene.add(camera);
    renderer.compile(scene,camera)

    var gl = renderer.getContext()
    var sq = createSquare(gl)
    var prg = shaderMaterial.program.program
    var posAttr = gl.getAttribLocation(prg,'vertexPos')


    // set the vertex buffer to be drawn
    gl.bindBuffer(gl.ARRAY_BUFFER, sq.buffer);

    // set the shader to use
    gl.useProgram(prg);

    // connect up the shader parameters: vertex position and projection/model matrices
    gl.vertexAttribPointer(posAttr, sq.vertSize, gl.FLOAT, false, 0, 0);

    renderer.compile(scene,camera)
    // create a rendering loop
    var frame = 0;
    function update() {
        frame += .01
        renderer.render(scene, camera);
        requestAnimationFrame(update)
    }
    requestAnimationFrame(update)

    </script>
</html>

我宁愿不必将教程翻译成制服,three.js 使用的属性语法如下所示

```

   var attributes = {
  displacement: {
    type: 'f', // a float
    value: [] // an empty array
  }
};
var uniforms = {
  amplitude: {
    type: 'f', // a float
    value: 1
  }
};

var vShader = $('#vertexshader');
var fShader = $('#fragmentshader');

// create the final material
var shaderMaterial =
    new THREE.MeshShaderMaterial({
      uniforms:       uniforms,
      attributes:     attributes,
      vertexShader:   vShader.text(),
      fragmentShader: fShader.text()
    });
...

不,既不推荐也不支持这种方法。除了使用原始 WebGL 上下文,您有两个选择:

  • 您可以使用 THREE.ShaderMaterial 自定义着色器定义。 three.js 自动提供一些 built-in 属性和制服(例如 modelViewMatrixprojectionMatrix),它们经常被顶点和片段着色器使用。官方doc page提供了很多资料
  • THREE.RawShaderMaterial 是一个更轻量级的选项,因为 three.js 不提供提到的 built-in 制服和属性。

以下两个基本示例显示了两种材料在最新版本 three.js (R91) 中的用法:

https://threejs.org/examples/#webgl_shader https://threejs.org/examples/#webgl_buffergeometry_rawshader

我建议使用这些示例,而不是可能已过时的教程。例如,属性不再是 ShaderMaterial 的参数。相反,属性数据是几何的一部分。