如何在保持 WebGL GLSL 中心的同时缩放 3D 立方体?

How can I scale a 3D Cube while maintaining it's center in WebGL GLSL?

我有一个比例属性,就像我在三个 js 中应用于 instance buffered geometry 的不同实例一样。着色器看起来像这样:

attribute float scale;

uniform vec3 uMeshPosition;

void main() {
  vec3 pos = position;
  pos.x *= ( uMeshPosition.x - pows.x ) * scale + uMeshPosition.x;
  pos.z *=  ( uMeshPosition.z - pos.z ) * scale + uMeshPosition.z;
  pos.y *=  ( uMeshPosition.y - pos.y ) * scale + uMeshPosition.y;

  gl_Position = projectionMatrix * modelViewMatrix * vec4(pos,1.0);
}

Z是我的身高!!!

我希望缩放的立方体保持上面线框立方体指示的初始中心。

是否可以在不计算和应用缩放的情况下在所有 3 个轴上应用缩放 CPU?

更新:

我创建 Geometry 的方式,通常使用多个立方体,但对于此示例,它只是一个实例:

 const createInstancedGeometry = (instanceCount, sizeX = 1, sizeY = 1, sizeZ = 1) => {
  const geometry = new InstancedBufferGeometry()
  geometry.maxInstancedCount = instanceCount

  const shape = new BoxBufferGeometry(0.1 * sizeX, 0.1 * sizeY, 0.1 * sizeZ)
  shape.translate(0, 0.4, 0)

  const data = shape.attributes

  geometry.addAttribute('position', new BufferAttribute(new Float32Array(data.position.array), 3))
  geometry.addAttribute('uv', new BufferAttribute(new Float32Array(data.uv.array), 2))
  geometry.addAttribute('normal', new BufferAttribute(new Float32Array(data.normal.array), 3))
  geometry.setIndex(new BufferAttribute(new Uint16Array(shape.index.array), 1))
  shape.dispose()

  createInstancedAtrributes(geometry, instanceCount)

  return geometry
}

这是我设置着色器的方式,我还没有使用颜色。

const createShader = () => {
  const uniforms = {
    // uMap: { type: 't', value: null },
    uColor1: { type: 'c', value: new Color(0x961800) }, // red
    uColor2: { type: 'c', value: new Color(0x4b5828) }, // yellow
    uMeshPosition: { type: 'vec3', value: new Vector3(0, 0, 0) },
  }

  const shader = new ShaderMaterial({
    uniforms,
    vertexShader,
    fragmentShader,
    blending: AdditiveBlending,
    transparent: true,
    depthWrite: false,
  })

  return shader
}

我的 Particle Fire 的构造函数如下所示:

constructor({ sizeX = 1, sizeY = 1, sizeZ = 1 } = {}) {
    const instanceCount = 1
    const geometry = createInstancedGeometry(instanceCount, sizeX, sizeY, sizeZ)
    const material = createShader()

    const mesh = new Mesh(geometry, material)
    mesh.frustumCulled = false

    this.geometry = geometry
    this.material = material
    this.mesh = mesh

    mesh.up = new Vector3(0, 0, 1)
    mesh.position.set(2, 2, 1)
    mesh.rotateX(Math.PI / 2)

    this.instanceCount = instanceCount

    const lineGeo = new EdgesGeometry(geometry) // or WireframeGeometry
    const mat = new LineBasicMaterial({ color: 0xffffff, linewidth: 2 })
    const wireframe = new LineSegments(lineGeo, mat)
    this.mesh.add(wireframe)
  }

更新调用:

update() {
    const { instanceCount } = this
    const { scale, progress, randoms } = this.geometry.attributes
    const { uMeshPosition } = this.material.uniforms
    uMeshPosition.value = this.mesh.position

    for (let i = 0; i < instanceCount; i += 1) {
      let value = progress.array[i]
      value += 0.025

      if (value > 1) {
        value -= 1
        scale.setX(i, randomValueBetween(0.3, 2, 3))
        // randoms.setX(i, randomValueBetween(0, 1, 3))
      }

      // progress.setX(i, value)
    }


    scale.needsUpdate = true
    // randoms.needsUpdate = true
    // progress.needsUpdate = true
  }

我正在像这样将对象添加到场景中:

const pFire = new ParticleFire()
scene.add(pFire.mesh)

并像这样在渲染循环中更新它:

  pFire.update({ deltaTime })

  renderer.render(scene, cameraController.camera)

  requestAnimationFrame(animate)

cameraController.camera 是一个简单的摄像机控制器,作为我在场景中移动的 'character' 的子项添加到场景中。

  configuredCamera = new PerspectiveCamera(
    75, window.innerWidth / window.innerHeight, 0.1, 5000,
  )

THREE.Geometrytranslate 函数平移网格的每个顶点。所以它自己的网格被置换了,它的中心不再是 (0, 0, 0)。

您应该设置 (position) 的几何图形。参见 THREE.Object3D

这意味着您必须删除 shape.translate(0, 0.4, 0),并且必须在 geometry.position 之前完成整个放置。
然后网格不再移位,仅由 modelViewMatrix 放置。 GLS 着色器代码将起作用:

gl_Position = projectionMatrix * modelViewMatrix * vec4(pos * scale, 1.0);