自定义 Threejs Mesh 类,InstancedBufferGeometry 未渲染

问题描述 投票:0回答:1

我正在尝试在 Threejs 中集成一个 webgl 高斯泼溅渲染器,为此我正在创建一个自定义网格类(根据文档这是可能的)。

创建类时,我获取数据,上传数据,然后创建实例化几何体:

const geometry = new THREE.InstancedBufferGeometry();
                geometry.instanceCount = count;
                geometry.setAttribute("splatPosition", new THREE.BufferAttribute(new Float32Array([-2, -2, 2, -2, 2, 2, -2, 2]), 2));

                const indexBuffer = new Uint32Array(count); // Buffer is updated on a later stage
                const indexAttrib = new THREE.InstancedBufferAttribute(indexBuffer, 1, false);
                indexAttrib.setUsage(THREE.DynamicDrawUsage);
                indexAttrib.needsUpdate = true;
                geometry.setAttribute("splatIndex", indexAttrib);

                this.geometry = geometry;

构造函数的开始:

        super(new THREE.SphereGeometry(0.5, 32, 32), new THREE.MeshStandardMaterial({color: 0x00ff00}));
        // this.renderOrder = -100; // Changes nothing
        this.frustumCulled = false;
        this.visible = true;
        this.castShadow = false;
        this.loaded = false;

材质创作:

const material = new THREE.RawShaderMaterial({
                    uniforms: {
                        focal: {type: 'v2', value: new THREE.Vector2()},
                        viewport: {type: 'v2', value: new THREE.Vector2()},
                        time: {type: 'f', value: 0},
                        opacity: {type: 'f', value: 1.0},
                        texture: {type: 't', value: null}
                    },
                    glslVersion: THREE.GLSL3,
                    vertexShader: vertexShaderSource,
                    fragmentShader: fragmentShaderSource,
                    side: THREE.DoubleSide,
                    blending: THREE.CustomBlending,
                    blendDst: THREE.OneMinusDstAlphaFactor,
                    blendDstAlpha: THREE.OneMinusDstAlphaFactor,
                    blendSrc: THREE.OneFactor,
                    blendSrcAlpha: THREE.OneFactor,
                    blendEquation: THREE.AddEquation,
                    depthTest: false,
                    depthWrite: false,
                    forceSinglePass: true,
                    transparent: false
                });

我的材料已正确编译,具有正确的属性并且制服已设置。我在 onBeforeRender 中更新了制服,这是正确调用的。但是,随后不会调用 opengl 来绘制模型。

请注意,如果我用球体和默认材质替换实例化几何体和着色器,则一切正常。我的节点也已正确添加到场景中。

用球体替换了自定义实例地理,本来不应该起作用,但它确实起作用了。尝试覆盖 InstancedMesh 而不是 Mesh,单独尝试 BufferGeometry。什么也没做。

three.js
1个回答
0
投票

使用自定义网格类将自定义 WebGL 高斯泼溅渲染器集成到 Three.js 中涉及正确创建和设置自定义着色器材质和实例化几何体。根据您的描述,听起来自定义实例几何体未渲染,即使材质和几何体设置似乎正确。

// Vertex Shader
const vertexShaderSource = `
#version 300 es
in vec2 splatPosition;
in float splatIndex;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main() {
    vec4 mvPosition = modelViewMatrix * vec4(splatPosition, 0.0, 1.0);
    gl_Position = projectionMatrix * mvPosition;
}
`;

// Fragment Shader
const fragmentShaderSource = `
#version 300 es
precision highp float;
uniform float time;
out vec4 outColor;
void main() {
    outColor = vec4(abs(sin(time)), 0.0, 0.0, 1.0);
}
`;

class CustomMesh extends THREE.Mesh {
    constructor(count) {
        const geometry = new THREE.InstancedBufferGeometry();
        geometry.instanceCount = count;
        geometry.setAttribute("splatPosition", new THREE.BufferAttribute(new Float32Array([-2, -2, 2, -2, 2, 2, -2, 2]), 2));

        const indexBuffer = new Uint32Array(count);
        const indexAttrib = new THREE.InstancedBufferAttribute(indexBuffer, 1, false);
        indexAttrib.setUsage(THREE.DynamicDrawUsage);
        geometry.setAttribute("splatIndex", indexAttrib);

        const material = new THREE.RawShaderMaterial({
            uniforms: {
                time: { type: 'f', value: 0 }
            },
            glslVersion: THREE.GLSL3,
            vertexShader: vertexShaderSource,
            fragmentShader: fragmentShaderSource,
            side: THREE.DoubleSide,
            blending: THREE.CustomBlending,
            blendDst: THREE.OneMinusDstAlphaFactor,
            blendDstAlpha: THREE.OneMinusDstAlphaFactor,
            blendSrc: THREE.OneFactor,
            blendSrcAlpha: THREE.OneFactor,
            blendEquation: THREE.AddEquation,
            depthTest: false,
            depthWrite: false,
            forceSinglePass: true,
            transparent: false
        });

        super(geometry, material);
        this.frustumCulled = false;
        this.visible = true;
        this.castShadow = false;
        this.loaded = false;
    }
}

// Scene setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 10);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const controls = new THREE.OrbitControls(camera, renderer.domElement);

const customMesh = new CustomMesh(10);
scene.add(customMesh);

const clock = new THREE.Clock();

function animate() {
    requestAnimationFrame(animate);

    // Update time uniform
    customMesh.material.uniforms.time.value = clock.getElapsedTime();

    controls.update();
    renderer.render(scene, camera);
}

animate();

window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});
© www.soinside.com 2019 - 2024. All rights reserved.