简体   繁体   English

Three.js:使用InstancedBufferGeometry + ShaderMaterial的每个四边形的自定义大小

[英]Three.js: Custom sizes for each quad using InstancedBufferGeometry + ShaderMaterial

I am trying to create a scene full of points, each with unique width and heights. 我正在尝试创建一个充满点的场景,每个点都有独特的宽度和高度。 However, I can't figure out how to get into the vertex shader to move the vertices to create the custom sizes. 但是,我不知道如何进入顶点着色器以移动顶点以创建自定义尺寸。 Here's the scene: 这里是场景:

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

My question is: how can I use the width and height attributes to make each point have the given (relative) proportions specified by its width and height values? 我的问题是:如何使用width和height属性使每个点具有由其width和height值指定的给定(相对)比例? Can I query the index of the vertex being drawn within its given instance? 我可以查询给定实例中绘制的顶点的索引吗? Any suggestions would be very helpful! 任何建议将非常有帮助!

Ah, it seems one can do the following in the vertex shader: 嗯,似乎可以在顶点着色器中执行以下操作:

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

Full snippet: 完整摘要:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM