从它们的中心缩放BufferGeometry对象

时间:2017-08-10 03:11:09

标签: three.js shader glsles buffer-geometry

我在一个Buffer Geometry中有大量随机放置的圆圈。我试图根据来自中心的音频输入来缩放每一个,但是它们会在场景的中心继续缩放。而不是获得更大的半径并保持静止,它们变得更大,但也远离中心。

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

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

small scale value 小规模值

larger scale value 规模较大的值

1 个答案:

答案 0 :(得分:1)

添加正常*比例

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>