0

我有大量随机放置的圆圈保存在单个缓冲区几何中。我正在尝试根据来自它们中心的音频输入来缩放每一个,但它们会一直在场景中心进行缩放。它们不会变得更大的半径并保持静止,而是会变得更大,但也会远离中心。

uniform float scale;
varying vec3 color;
void main() 
{

  mat4 sPos = mat4(vec4(scale,0.0,0.0,0.0),
               vec4(0.0,scale,0.0,0.0),
               vec4(0.0,0.0,1.0,0.0),
               vec4(0.0,0.0,0.0,1.0));
  vec3 pos = position * normal;
  vec4 modelViewPosition = modelViewMatrix * sPos * vec4(pos, 1.0) ;

  gl_Position = projectionMatrix * modelViewPosition;
}

这就是我正在尝试的。是否有一个矩阵变换可以将原点移动到每个圆的中心而不会弄乱场景的其他方面?

小尺度值 小尺度值

较大的刻度值 较大的刻度值

4

1 回答 1

2

添加正常的 * 比例

uniform float scale;
varying vec3 color;
void main() 
{
  vec3 pos = position + normal * scale;
  vec4 modelViewPosition = modelViewMatrix * vec4(pos, 1.0) ;

  gl_Position = projectionMatrix * modelViewPosition;
}

例子:

const vs = `
uniform float scale;
void main() 
{
  vec3 pos = position + normal * scale;
  vec4 modelViewPosition = modelViewMatrix * vec4(pos, 1.0) ;
  gl_Position = projectionMatrix * modelViewPosition;
}
`;

const fs = `
void main() {
  gl_FragColor = vec4(1,0,0,1);
}
`;

const camera = new THREE.PerspectiveCamera(40, 1, 1, 1000);
camera.position.z = 400;

const scene = new THREE.Scene();

const uniforms = {
  scale: { value: 1 },
};

var shaderMaterial = new THREE.ShaderMaterial({
  uniforms:       uniforms,
  vertexShader:   vs,
  fragmentShader: fs,
});

const geometry = new THREE.BufferGeometry();
const numCircles = 20;
const numEdgePointsPerCircle = 36;
const numPointsPerCircle = numEdgePointsPerCircle * 3;
const totalPoints = numPointsPerCircle * numCircles;
const positions = new Float32Array(totalPoints * 3);
const normals = new Float32Array(totalPoints * 3);

const radius = 10;
let off = 0;

for (let c = 0; c < numCircles; ++c) {
  const cx = rand(-100, 100);
  const cy = rand(-100, 100);
  for (let p = 0; p < numEdgePointsPerCircle; ++p) {
    const a0 = (p + 0) * Math.PI * 2 / numEdgePointsPerCircle;
    const a1 = (p + 1) * Math.PI * 2 / numEdgePointsPerCircle;
    positions[off + 0] = cx;
    positions[off + 1] = cy;
    positions[off + 2] = 0;
    positions[off + 3] = cx + Math.cos(a0) * radius;
    positions[off + 4] = cy + Math.sin(a0) * radius;
    positions[off + 5] = 0;
    positions[off + 6] = cx + Math.cos(a1) * radius;
    positions[off + 7] = cy + Math.sin(a1) * radius;
    positions[off + 8] = 0;
    normals[off + 0] = 0;        
    normals[off + 1] = 0;        
    normals[off + 2] = 0;
    normals[off + 3] = Math.cos(a0);        
    normals[off + 4] = Math.sin(a0);        
    normals[off + 5] = 0;
    normals[off + 6] = Math.cos(a1);        
    normals[off + 7] = Math.sin(a1);        
    normals[off + 8] = 0;
    off += 9;
  }
}
 
geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.addAttribute('normal', new THREE.BufferAttribute(normals, 3));

const mesh = new THREE.Mesh( geometry, shaderMaterial );

scene.add(mesh);

const renderer = new THREE.WebGLRenderer({
  canvas: document.querySelector("canvas"),
});

function rand(min, max) {
  return min + Math.random() * (max - min);
}

function resize(renderer, camera, force) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (force || canvas.width !== width || canvas.height !== height) {
    renderer.setSize(width, height, false);  // pass false so three doesn't mess up the css
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  }
}

function render(time) {
  time *= 0.001;  // seconds
  
  resize(renderer, camera);
  
  uniforms.scale.value = Math.sin(time) * 5;
  
  renderer.render(scene, camera);

  requestAnimationFrame(render);
}
resize(renderer, camera, true);
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.min.js"></script>
<canvas></canvas>

仅使用中心点的示例

const vs = `
uniform float scale;
void main() 
{
  vec3 pos = position + normal * scale;
  vec4 modelViewPosition = modelViewMatrix * vec4(pos, 1.0) ;
  gl_Position = projectionMatrix * modelViewPosition;
}
`;

const fs = `
void main() {
  gl_FragColor = vec4(1,0,0,1);
}
`;

const camera = new THREE.PerspectiveCamera(40, 1, 1, 1000);
camera.position.z = 400;

const scene = new THREE.Scene();

const uniforms = {
  scale: { value: 1 },
};

var shaderMaterial = new THREE.ShaderMaterial({
  uniforms:       uniforms,
  vertexShader:   vs,
  fragmentShader: fs,
});

const geometry = new THREE.BufferGeometry();
const numCircles = 20;
const numEdgePointsPerCircle = 36;
const numPointsPerCircle = numEdgePointsPerCircle * 3;
const totalPoints = numPointsPerCircle * numCircles;
const positions = new Float32Array(totalPoints * 3);
const normals = new Float32Array(totalPoints * 3);

const radius = 10;
let off = 0;

for (let c = 0; c < numCircles; ++c) {
  const cx = rand(-100, 100);
  const cy = rand(-100, 100);
  for (let p = 0; p < numEdgePointsPerCircle; ++p) {
    const a0 = (p + 0) * Math.PI * 2 / numEdgePointsPerCircle;
    const a1 = (p + 1) * Math.PI * 2 / numEdgePointsPerCircle;
    positions[off + 0] = cx;
    positions[off + 1] = cy;
    positions[off + 2] = 0;
    positions[off + 3] = cx;
    positions[off + 4] = cy;
    positions[off + 5] = 0;
    positions[off + 6] = cx;
    positions[off + 7] = cy;
    positions[off + 8] = 0;
    normals[off + 0] = 0;        
    normals[off + 1] = 0;        
    normals[off + 2] = 0;
    normals[off + 3] = Math.cos(a0);        
    normals[off + 4] = Math.sin(a0);        
    normals[off + 5] = 0;
    normals[off + 6] = Math.cos(a1);        
    normals[off + 7] = Math.sin(a1);        
    normals[off + 8] = 0;
    off += 9;
  }
}
 
geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.addAttribute('normal', new THREE.BufferAttribute(normals, 3));

const mesh = new THREE.Mesh( geometry, shaderMaterial );

scene.add(mesh);

const renderer = new THREE.WebGLRenderer({
  canvas: document.querySelector("canvas"),
});

function rand(min, max) {
  return min + Math.random() * (max - min);
}

function resize(renderer, camera, force) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (force || canvas.width !== width || canvas.height !== height) {
    renderer.setSize(width, height, false);  // pass false so three doesn't mess up the css
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  }
}

function render(time) {
  time *= 0.001;  // seconds
  
  resize(renderer, camera);
  
  uniforms.scale.value = 10 + Math.sin(time) * 5;
  
  renderer.render(scene, camera);

  requestAnimationFrame(render);
}
resize(renderer, camera, true);
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.min.js"></script>
<canvas></canvas>

使用实例化的示例

const vs = `
attribute vec3 center;
uniform float scale;
void main() 
{
  vec3 pos = center + position * scale;
  vec4 modelViewPosition = modelViewMatrix * vec4(pos, 1.0) ;
  gl_Position = projectionMatrix * modelViewPosition;
}
`;

const fs = `
void main() {
  gl_FragColor = vec4(1,0,0,1);
}
`;

const camera = new THREE.PerspectiveCamera(40, 1, 1, 1000);
camera.position.z = 400;

const scene = new THREE.Scene();

const uniforms = {
  scale: { value: 1 },
};

var shaderMaterial = new THREE.ShaderMaterial({
  uniforms:       uniforms,
  vertexShader:   vs,
  fragmentShader: fs,
});

// Just need one circle and 1 center point per circle

const geometry = new THREE.InstancedBufferGeometry();
const numCircles = 20;
const numEdgePointsPerCircle = 36;
const numPointsPerCircle = numEdgePointsPerCircle * 3;
const centers = new Float32Array(numCircles * 3);
const positions = new Float32Array(numPointsPerCircle * 3);

const radius = 10;
let off = 0;

for (let c = 0; c < numCircles; ++c) {
  const cx = rand(-100, 100);
  const cy = rand(-100, 100);
  centers[c * 2 + 0] = cx;
  centers[c * 2 + 1] = cy;
}

for (let p = 0; p < numEdgePointsPerCircle; ++p) {
  const a0 = (p + 0) * Math.PI * 2 / numEdgePointsPerCircle;
  const a1 = (p + 1) * Math.PI * 2 / numEdgePointsPerCircle;
  positions[off + 0] = 0;        
  positions[off + 1] = 0;        
  positions[off + 2] = 0;
  positions[off + 3] = Math.cos(a0);        
  positions[off + 4] = Math.sin(a0);        
  positions[off + 5] = 0;
  positions[off + 6] = Math.cos(a1);        
  positions[off + 7] = Math.sin(a1);        
  positions[off + 8] = 0;
  off += 9;
}
 
geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.addAttribute('center', new THREE.InstancedBufferAttribute(centers, 3));

const mesh = new THREE.Mesh( geometry, shaderMaterial );

scene.add(mesh);

const renderer = new THREE.WebGLRenderer({
  canvas: document.querySelector("canvas"),
});

function rand(min, max) {
  return min + Math.random() * (max - min);
}

function resize(renderer, camera, force) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (force || canvas.width !== width || canvas.height !== height) {
    renderer.setSize(width, height, false);  // pass false so three doesn't mess up the css
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  }
}

function render(time) {
  time *= 0.001;  // seconds
  
  resize(renderer, camera);
  
  uniforms.scale.value = 10 + Math.sin(time) * 5;
  
  renderer.render(scene, camera);

  requestAnimationFrame(render);
}
resize(renderer, camera, true);
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.min.js"></script>
<canvas></canvas>

于 2017-08-10T09:11:44.577 回答