【问题标题】:instancedBuffergeometry with spritesheet doesn't show up from threejs v117从threejs v117中没有显示带有spritesheet的instancedBuffergeometry
【发布时间】:2021-03-21 22:27:54
【问题描述】:

我正在使用 InstancedBufferGeometry 来绘制许多 .gltf 对象,并使用像 https://imgur.com/a/G9CBldQ 这样的 spritesheet 来应用多种纹理。

为了使用 spritesheet,我使用的是基于 MeshLambertMaterial 的材质,使用 onBeforeCompile 函数,并且在threejs v116之前,它工作得很好。

但是将threejs和GLTFLoader升级到v117后,什么都没有显示。

我正在像这样实现onBeforeCompile

class InstancedLambertMaterial extends THREE.MeshLambertMaterial {
  constructor(params) {
    super(params);
    this.spriteGrids = params?.spriteGrids;
    this.userData = {
      uniforms: {
        vUvScale: { value: 1 / Math.sqrt(params?.spriteGrids) }
      }
    };
  }
  onBeforeCompile(shader) {
    Object.assign(shader.uniforms, this.userData.uniforms);

    shader.vertexShader = `#define USE_INSTANCING_CUSTOM\n${shader.vertexShader}`;

    const instancedAttributes = `
attribute vec3 translation;
attribute vec4 orientation;
attribute vec3 scale;
attribute vec2 vUvOffsets;
varying vec2 v_vUvOffsets;
uniform float vUvScale;
`;
    shader.vertexShader = shader.vertexShader.replace('#include <common>', `${instancedAttributes}\n#include <common>`);

    const replacedProjectVertex = `
vec4 mvPosition = vec4( transformed, 1.0 );
#ifdef USE_INSTANCING
  mvPosition = instanceMatrix * mvPosition;
#endif
#ifdef USE_INSTANCING_CUSTOM
  vUv = uv;
  transformed *= scale;
  vec3 vcV = cross(orientation.xyz, transformed);
  transformed = vcV * (2.0 * orientation.w) + (cross(orientation.xyz, vcV) * 2.0 + transformed);
  mvPosition = vec4(translation + transformed, 1.0);
#endif
mvPosition = modelViewMatrix * mvPosition;
gl_Position = projectionMatrix * mvPosition;

#ifdef USE_INSTANCING_CUSTOM
    v_vUvOffsets = vUvOffsets;
#endif
    `;
    shader.vertexShader = shader.vertexShader.replace('#include <project_vertex>', replacedProjectVertex);

    shader.fragmentShader = `#define USE_SPRITESHEET\n${shader.fragmentShader}`;

    const spriteSheetUniforms = `
#include <map_pars_fragment>
#ifdef USE_SPRITESHEET
  uniform float vUvScale;
  varying vec2 v_vUvOffsets;
#endif
    `;
    shader.fragmentShader = shader.fragmentShader.replace('#include <map_pars_fragment>', spriteSheetUniforms);

    const spriteSheetTexelColorBranch = `
#ifdef USE_SPRITESHEET
  vec4 texelColor = texture2D( map, (vUv * vUvScale) + (v_vUvOffsets * vUvScale) );
  texelColor = mapTexelToLinear( texelColor );
  diffuseColor *= texelColor;
#endif
    `;
    shader.fragmentShader = shader.fragmentShader.replace('#include <map_fragment>', spriteSheetTexelColorBranch);

    this.userData = shader;
  }
}

并像这样准备每个转换属性并应用它。

const scales       = new THREE.InstancedBufferAttribute(new Float32Array(instances * 3), 3, false);
const translations = new THREE.InstancedBufferAttribute(new Float32Array(instances * 3), 3, false);
const orientations = new THREE.InstancedBufferAttribute(new Float32Array(instances * 4), 4, false);
const tex_vec      = new THREE.InstancedBufferAttribute(new Float32Array(instances * 2), 2, false);

我检查了着色器输出(通过故意提高着色器错误)并且看起来与绘制我的对象相关的没有任何更改。
我查看了relase notes of v117,但看起来与我的项目没有任何变化。
我希望能够为最新版本的threejs 执行这些代码。

我做了一个工作示例。两个代码都是一样的,除了threejs和GLTFLoader的版本。
这是 v116 的结果
https://jsfiddle.net/maemaemae3/o9t1wxrm/1/
和 v117
https://jsfiddle.net/maemaemae3/2cgym7n3/1/

【问题讨论】:

    标签: three.js


    【解决方案1】:

    问题出在这一行:

    const igeo = new THREE.InstancedBufferGeometry().copy(geometry);

    如果您这样做,InstancedBufferGeometry 的属性将变为 undefined,因为它们在 BufferGeometry 中不存在。 r117 中的重构使此错误可见。

    我已经通过恢复 instanceCount 属性修复了你的第二把小提琴:https://jsfiddle.net/9k4oqerc/

    【讨论】:

    • 非常感谢,已修复!我必须在旧版本中定义igeo.instanceCount = void 0;,因为如果我将小数字设置为instanceCount,则无法增加数字。但现在看来不需要了。此行为是否已修复?
    • 问题是你的复制操作使得属性instanceCountundefined。您应该手动复制缓冲区属性。
    猜你喜欢
    • 2021-07-26
    • 2012-01-10
    • 2021-04-18
    • 2013-03-24
    • 2014-06-14
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    • 1970-01-01
    相关资源
    最近更新 更多