三.js:使用InstancedBuffergeometry ShaderMaterial的每个四边形的自定义尺寸



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

// 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>

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

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

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;
}

完整片段:

// 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>

最新更新