Three.js自定义着色器与纹理

时间:2016-09-09 13:24:33

标签: opengl-es three.js fragment-shader vertex-shader texture2d

我想编写一个使用three.js操纵我的图像的自定义着色器。 为此我想创建一个图像作为纹理的平面。之后我想移动顶点以扭曲图像。

(如果这是绝对错误的方法,请告诉我)。

首先我有我的着色器:

    <script type="x-shader/x-vertex" id="vertexshader">
        attribute vec2 a_texCoord;
        varying vec2 v_texCoord;

        void main() {
            // Pass the texcoord to the fragment shader.
            v_texCoord = a_texCoord;

            gl_Position = projectionMatrix *
                          modelViewMatrix *
                          vec4(position,1.0);
        }
    </script>

    <script type="x-shader/x-fragment" id="fragmentshader">
        uniform sampler2D u_texture;
        varying vec2 v_texCoord;

        void main() {
            vec4 color = texture2D(u_texture, v_texCoord);
            gl_FragColor = color;
        }

    </script>

我真的不明白texture2D在做什么,但我发现在其他代码片段中。 这个样本我想要的是:只用“底层”图像(=纹理)的颜色为顶点(gl_FracColor)着色。

在我的代码中,我使用平面设置了一个普通的三个场景:

    // set some camera attributes
    var VIEW_ANGLE = 45,
        ASPECT = window.innerWidth/window.innerHeight,
        NEAR = 0.1,
        FAR = 1000;

    var scene = new THREE.Scene();


    var camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
    camera.position.set(0, 0, 15);

    var vertShader = document.getElementById('vertexshader').innerHTML;
    var fragShader = document.getElementById('fragmentshader').innerHTML;

    var texloader = new THREE.TextureLoader();
    var texture = texloader.load("img/color.jpeg");

    var uniforms = {
        u_texture: {type: 't', value: 0, texture: texture},

    };


    var attributes = {
        a_texCoord: {type: 'v2', value: new THREE.Vector2()}
    };

    // create the final material
    var shaderMaterial = new THREE.ShaderMaterial({
        uniforms:       uniforms,
        vertexShader:   vertShader,
        fragmentShader: fragShader
    });

    var renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild(renderer.domElement);

    var plane = {
        width: 5,
        height: 5,
        widthSegments: 10,
        heightSegments: 15
    }

    var geometry = new THREE.PlaneBufferGeometry(plane.width, plane.height, plane.widthSegments, plane.heightSegments)

    var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
    var plane = new THREE.Mesh( geometry, shaderMaterial );
    scene.add(plane);

    plane.rotation.y += 0.2;

    var render = function () {
        requestAnimationFrame(render);

        // plane.rotation.x += 0.1;

        renderer.render(scene, camera);
    };

    render();

不幸的是,运行该代码后,我只看到一个黑色的窗口。虽然我知道如果我在创建网格时使用material作为材质,我可以清楚地看到它。 所以它必须是shaderMaterial或着色器。

问题:

  • 我是否必须定义统一u_texture和属性 我的着色器中的a_texCoord材质制服和属性?并做 他们必须有完全相同的名字?
  • 反正有多少个顶点?我会为图像中的每个像素获取顶点吗?或者飞机的每个角落只有4个?
  • a_texCoord有什么价值?如果我写的话,什么都没发生:

    var attributes = {
        a_texCoord: {type: 'v2', value: new THREE.Vector2(1,1)}
    };
    
  • 或者我是否必须使用一些映射(内置三个地图的东西)?但是我怎么会改变顶点位置呢?

有人可以解释一下这个问题吗?

2 个答案:

答案 0 :(得分:1)

我通过改变它来实现它:

class StarBarExtension extends \Twig_Extension
{
    protected $doctrine; 
    private $RequestStack;


    public function __construct(RegistryInterface $doctrine, RequestStack $RequestStack)
    {
        $this->doctrine = $doctrine;
        $this->requestStack = $RequestStack;
    }

    public function getFunctions() {
      return array(
           'starBar' => new \Twig_Function_Method($this, 'myStarBar'),
      );
    }

    public function myStarBar($numStar, $mediaId, $starWidth) {

    $cookies = $this->requestStack->getCurrentRequest()->cookies->get('LilmodLemaedNote'.$mediaId);

    $nbrPixelsInDiv = $numStar * $starWidth; // Calculate the DIV width in pixel

    **$query = $this->get('doctrine_mongodb')->getRepository('PortailBundle:Notes')->findOneBy(array('ARTICLE' =>$mediaId));**

对此:

    var uniforms = {
        u_texture: {type: 't', value: 0, texture: texture},
    };

无论如何,所有其他问题仍然是开放的,答案非常感谢。 (顺便问一下:为什么降级某人?)

答案 1 :(得分:1)

  

我是否必须定义统一的u_texture和属性a_texCoord   在我的着色器材质制服和属性?他们必须这样做   有完全相同的名字?

是的,是的。制服被定义为着色器材质的一部分,而属性已从版本72中的着色器材质移动到BufferGeometry类(我假设您使用的是最新版本,所以这里是你的方式今天这样做):

var geometry = new THREE.PlaneBufferGeometry(...);

// first, create an array to hold the a_texCoord-values per vertex
var numVertices = (plane.widthSegments + 1) * (plane.heightSegments + 1);
var texCoordBuffer = new Float32Array(2 * numVertices);

// now register it as a new attribute (the 2 here indicates that there are
// two values per element (vec2))    
geometry.addAttribute('a_texCoord', new THREE.BufferAttribute(texCoordBuffer, 2));

如您所见,该属性仅在其与着色器代码中指定的名称完全相同时才起作用。

我不确切地知道你打算用它做什么,但听起来很可疑,就像你想拥有紫外线坐标一样。如果是这种情况,如果您查看THREE.PlaneBufferGeometry课程,可以节省很多工作。它已经提供了一个名为uv的属性,可能正是您正在寻找的属性。因此,您只需将着色器代码中的属性名称更改为

即可
attribute vec2 uv;
  

反正有多少个顶点?我会为每个人获得一个顶点吗?   图像中的像素?或者飞机的每个角落只有4个?

根据heightSegmentswidthSegments参数创建顶点。因此,如果将两者都设置为5,则会有(5 + 1)*(5 + 1)= 36个顶点(+1因为只有1个段的线有两个顶点等)和5 * 5 * 2 = 50个三角形(共有150个指数)。

需要注意的另一件事是PlaneBufferGeometry是一个索引几何体。这意味着每个顶点(以及每个其他属性值)仅存储一次,尽管它由多个三角形使用。有一个特殊的索引属性,它包含用于创建哪些三角形的顶点信息。

  

a_texCoord有什么价值?如果我写的话,什么都没发生:......

我希望上述内容有助于回答这个问题。

  

或者我是否必须使用一些映射(内置三个地图的东西)?

我建议你使用上面描述的uv属性。但你绝对不必。

  

但我怎么会改变顶点位置呢?

至少有两种方法可以做到这一点:在顶点着色器中或通过javascript。后者可以在这里看到:http://codepen.io/usefulthink/pen/vKzRKr?editors=1010 (更新几何的相关部分从第84行开始)。