【问题标题】:Three.js: Custom sizes for each quad using InstancedBufferGeometry + ShaderMaterialThree.js:使用 InstancedBufferGeometry + ShaderMaterial 为每个四边形自定义大小
【发布时间】:2019-05-22 06:30:21
【问题描述】:

我正在尝试创建一个充满点的场景,每个点都有独特的宽度和高度。但是,我不知道如何进入顶点着色器来移动顶点以创建自定义大小。场景如下:

// generate a scene object
var scene = new THREE.Scene();
scene.background = new THREE.Color(0xaaaaaa);

// generate a camera
var aspectRatio = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 10000);
camera.position.set(0, 1, -10);

// generate a renderer
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio); // <3 retina
renderer.setSize(window.innerWidth, window.innerHeight); // canvas size
document.body.appendChild(renderer.domElement);

// generate controls
var controls = new THREE.TrackballControls(camera, renderer.domElement);

// generate some lights
var ambientLight = new THREE.AmbientLight(0xeeeeee);
scene.add(ambientLight);

/**
* Add the points
**/

var BA = THREE.BufferAttribute;
var IBA = THREE.InstancedBufferAttribute;
var geometry  = new THREE.InstancedBufferGeometry();

var n = 10000, // number of observations
    rootN = n**(1/2),
    cellSize = 20,
    translations = new Float32Array(n * 3),
    widths = new Float32Array(n),
    heights = new Float32Array(n),
    translationIterator = 0,
    widthIterator = 0,
    heightIterator = 0;
for (var i=0; i<n*3; i++) {
  translations[translationIterator++] = (Math.random() * n) - (Math.random() * n);
  translations[translationIterator++] = (Math.random() * n) - (Math.random() * n);
  translations[translationIterator++] = (Math.random() * n) - (Math.random() * n);
  widths[widthIterator++] = Math.random() * 20;
  heights[heightIterator++] = Math.random() * 20;
}

// coordinates for template box
var size = 10,
    verts = [
  0, 0, 0, // lower left
  size, 0, 0, // lower right
  size, size, 0, // upper right
  0, size, 0, // upper left
]

var positionAttr = new BA(new Float32Array(verts), 3),
    translationAttr = new IBA(translations, 3, true, 1),
    widthAttr = new IBA(widths, 1, true, 1),
    heightAttr = new IBA(heights, 1, true, 1);

// we make two triangles but only use 4 distinct vertices in the object
// the second argument to THREE.BufferAttribute is the number of elements
// in the first argument per vertex
geometry.setIndex([0,1,2, 2,3,0])

geometry.addAttribute('position', positionAttr);
geometry.addAttribute('translation', translationAttr);
geometry.addAttribute('width', widthAttr);
geometry.addAttribute('height', heightAttr);

var material = new THREE.RawShaderMaterial({
  vertexShader: document.getElementById('vertex-shader').textContent,
  fragmentShader: document.getElementById('fragment-shader').textContent,
});
material.side = THREE.DoubleSide;
var mesh = new THREE.Mesh(geometry, material);
mesh.frustumCulled = false; // prevent the mesh from being clipped on drag
scene.add(mesh);

// render loop
function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
  controls.update();
};

// draw some geometries
var geometry = new THREE.TorusGeometry(10, 3, 16, 100);
var material = new THREE.MeshNormalMaterial({ color: 0xffff00 });

render();
html, body { width: 100vw; height: 100vh; background: #000; }
body { margin: 0; overflow: hidden; }
canvas { width: 100vw; height: 100vh; }
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js'></script>
<script src='https://threejs.org/examples/js/controls/TrackballControls.js'></script>

<script type='x-shader/x-vertex' id='vertex-shader'>
precision highp float;

uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;

uniform vec3 cameraPosition;

attribute vec3 position; // sets the blueprint's vertex positions
attribute vec3 translation; // x y translation offsets for an instance
attribute float width;
attribute float height;

void main() {
  // set point position
  vec3 pos = position + translation;
  vec4 projected = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
  gl_Position = projected;
}
</script>

<script type='x-shader/x-fragment' id='fragment-shader'>
precision highp float;

void main() {
  gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
</script>

我的问题是:如何使用宽度和高度属性使每个点具有由其宽度和高度值指定的给定(相对)比例?我可以查询在给定实例中绘制的顶点的索引吗?任何建议都会非常有帮助!

【问题讨论】:

    标签: javascript three.js geometry glsl


    【解决方案1】:

    啊,似乎可以在顶点着色器中执行以下操作:

    void main() {
      // set point position
      vec3 pos = position + translation;
      pos.x = pos.x * width;
      pos.y = pos.y * height;
    
      vec4 projected = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
      gl_Position = projected;
    }
    

    完整的sn-p:

    // generate a scene object
    var scene = new THREE.Scene();
    scene.background = new THREE.Color(0xaaaaaa);
    
    // generate a camera
    var aspectRatio = window.innerWidth / window.innerHeight;
    var camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 10000);
    camera.position.set(0, 1, -10);
    
    // generate a renderer
    var renderer = new THREE.WebGLRenderer({antialias: true});
    renderer.setPixelRatio(window.devicePixelRatio); // <3 retina
    renderer.setSize(window.innerWidth, window.innerHeight); // canvas size
    document.body.appendChild(renderer.domElement);
    
    // generate controls
    var controls = new THREE.TrackballControls(camera, renderer.domElement);
    
    // generate some lights
    var ambientLight = new THREE.AmbientLight(0xeeeeee);
    scene.add(ambientLight);
    
    /**
    * Add the points
    **/
    
    var BA = THREE.BufferAttribute;
    var IBA = THREE.InstancedBufferAttribute;
    var geometry  = new THREE.InstancedBufferGeometry();
    
    var n = 10000, // number of observations
        rootN = n**(1/2),
        cellSize = 20,
        translations = new Float32Array(n * 3),
        widths = new Float32Array(n),
        heights = new Float32Array(n),
        translationIterator = 0,
        widthIterator = 0,
        heightIterator = 0;
    for (var i=0; i<n*3; i++) {
      translations[translationIterator++] = (Math.random() * n) - (Math.random() * n);
      translations[translationIterator++] = (Math.random() * n) - (Math.random() * n);
      translations[translationIterator++] = (Math.random() * n) - (Math.random() * n);
      widths[widthIterator++] = Math.random() * 20;
      heights[heightIterator++] = Math.random() * 20;
    }
    
    // coordinates for template box
    var size = 10,
        verts = [
      0, 0, 0, // lower left
      size, 0, 0, // lower right
      size, size, 0, // upper right
      0, size, 0, // upper left
    ]
    
    var positionAttr = new BA(new Float32Array(verts), 3),
        translationAttr = new IBA(translations, 3, true, 1),
        widthAttr = new IBA(widths, 1, true, 1),
        heightAttr = new IBA(heights, 1, true, 1);
    
    // we make two triangles but only use 4 distinct vertices in the object
    // the second argument to THREE.BufferAttribute is the number of elements
    // in the first argument per vertex
    geometry.setIndex([0,1,2, 2,3,0])
    
    geometry.addAttribute('position', positionAttr);
    geometry.addAttribute('translation', translationAttr);
    geometry.addAttribute('width', widthAttr);
    geometry.addAttribute('height', heightAttr);
    
    var material = new THREE.RawShaderMaterial({
      vertexShader: document.getElementById('vertex-shader').textContent,
      fragmentShader: document.getElementById('fragment-shader').textContent,
    });
    material.side = THREE.DoubleSide;
    var mesh = new THREE.Mesh(geometry, material);
    mesh.frustumCulled = false; // prevent the mesh from being clipped on drag
    scene.add(mesh);
    
    // render loop
    function render() {
      requestAnimationFrame(render);
      renderer.render(scene, camera);
      controls.update();
    };
    
    // draw some geometries
    var geometry = new THREE.TorusGeometry(10, 3, 16, 100);
    var material = new THREE.MeshNormalMaterial({ color: 0xffff00 });
    
    render();
    html, body { width: 100vw; height: 100vh; background: #000; }
    body { margin: 0; overflow: hidden; }
    canvas { width: 100vw; height: 100vh; }
    <script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js'></script>
    <script src='https://threejs.org/examples/js/controls/TrackballControls.js'></script>
    
    <script type='x-shader/x-vertex' id='vertex-shader'>
    precision highp float;
    
    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;
    
    uniform vec3 cameraPosition;
    
    attribute vec3 position; // sets the blueprint's vertex positions
    attribute vec3 translation; // x y translation offsets for an instance
    attribute float width;
    attribute float height;
    
    void main() {
      // set point position
      vec3 pos = position + translation;
      vec4 projected = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
      gl_Position = projected;
    }
    </script>
    
    <script type='x-shader/x-fragment' id='fragment-shader'>
    precision highp float;
    
    void main() {
      gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
    }
    </script>

    【讨论】:

      猜你喜欢
      • 2017-06-12
      • 1970-01-01
      • 1970-01-01
      • 2016-03-08
      • 2018-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多