You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ThreeJS点击生成点仅首次生效问题求助

Hey there, let's break down why your single-click points aren't showing up after the first one, and how to fix it properly.

What's Causing the Issue?

  • Asynchronous Texture Loading
    Every time you call addPoint(), you're reloading the sprite texture with new THREE.TextureLoader().load(). This is an asynchronous operation—meaning the texture isn't ready when you create the THREE.Points object. The first click might work because by the time the renderer draws the next frame, the texture finishes loading and updates the material. But for subsequent clicks, the Points is created immediately with an unloaded (empty) texture. Your alphaTest: 0.5 setting then culls the fully transparent point, making it invisible.

  • Inefficient Object Creation + Single-Vertex Rendering
    Creating a brand new BufferGeometry, PointsMaterial, and Points object for every single click is terrible for performance (you’ll end up with hundreds of redundant objects) and triggers edge cases in Three.js. Single-vertex Points can sometimes be overlooked by the renderer or frustum culling, whereas a Points object with thousands of vertices (like your loop example) gets prioritized and renders correctly once the texture loads.

Fixes to Get Your Points Showing Up Every Time

1. Load the Texture Once (Not Per Click)

Move texture loading outside of addPoint() so it only happens once during initialization. This avoids async race conditions and redundant network requests.

2. Reuse a Single Points Object

Instead of creating a new Points for each click, maintain one global Points instance and dynamically add vertices to its geometry. This is far more efficient and eliminates the single-vertex rendering issue.

Here's the revised code:

// Global variables for texture and reusable point system
let spriteTexture;
let points;
let verticesArray = [];

// Initialize texture and point system when your scene is ready
function initPointSystem() {
    const loader = new THREE.TextureLoader();
    loader.load('textures/disc.png', (texture) => {
        spriteTexture = texture;
        createBasePoints();
    });
}

// Create the single, reusable Points object
function createBasePoints() {
    const geometry = new THREE.BufferGeometry();
    // Start with an empty vertex array
    geometry.setAttribute('position', new THREE.Float32BufferAttribute(verticesArray, 3));
    
    const material = new THREE.PointsMaterial({
        size: 1,
        sizeAttenuation: true,
        map: spriteTexture,
        alphaTest: 0.5,
        transparent: true
    });
    material.color.setHSL(1.0, 0.3, 0.7);
    
    points = new THREE.Points(geometry, material);
    group.add(points);
}

// Updated addPoint to add vertices to the existing system
function addPoint(coord) {
    // Push new vertex coordinates to our global array
    verticesArray.push(coord.x, coord.y, coord.z);
    
    // Update the buffer geometry with the new vertices
    points.geometry.setAttribute('position', new THREE.Float32BufferAttribute(verticesArray, 3));
    // Mark the position attribute as needing an update (critical for the renderer to pick up changes)
    points.geometry.attributes.position.needsUpdate = true;
}

// Call this when your scene is initialized
initPointSystem();

Why This Works

  • The texture is loaded once upfront, so it’s fully ready when we create the Points object.
  • We only have one Points instance, so every new vertex is added to the same geometry—no more single-vertex edge cases.
  • Updating the existing geometry instead of creating new objects keeps your scene performant even with hundreds of clicks.

内容的提问来源于stack exchange,提问作者rikicecchi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 18:57:44