2017-05-07 253 views
1

我正在使用THREE.js点,有时我需要它们具有不同的每点颜色。有时候,我也在修改他们的alpha值,所以我不得不编写自己的着色器程序。顶点颜色正在变成白色

在JavaScript我有以下代码:

let materials; 
if (pointCloudData.colors !== undefined) { 
    geometry.colors = pointCloudData.colors.map(hexColor => new THREE.Color(hexColor)); 
    // If the point cloud has color for each point... 
    materials = new THREE.ShaderMaterial({ 
     vertexColors: THREE.VertexColors, 
     vertexShader: document.getElementById('vertexshader').textContent, 
     fragmentShader: document.getElementById('fragmentshader').textContent, 
     transparent: true, 
    }); 
} else { 
    // Set color for the whole cloud 
    materials = new THREE.ShaderMaterial({ 
     uniforms: { 
      unicolor: { value: pointCloudData.color }, 
     }, 
     vertexShader: document.getElementById('vertexshader').textContent, 
     fragmentShader: document.getElementById('fragmentshader').textContent, 
     transparent: true, 
    }); 
} 

const pointCloud = new THREE.Points(geometry, materials); 

我基本上设置除非我已每点的颜色所限定的网格的颜色均匀的值 - 然后我设置vertexColors到的几何形状。我还检查了存储在geometry.colors中的值,它们是范围[0,1]中的正确RGB值。

我的Vertex Shader代码:

attribute float size; 
attribute float alpha; 

varying float vAlpha; 
varying vec3 vColor; 
void main() { 
    vAlpha = alpha; 

    #ifdef USE_COLOR 
     vColor = color; 
    #endif 

    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); 
    gl_PointSize = size * (300.0/-mvPosition.z); 
    gl_Position = projectionMatrix * mvPosition; 
} 

我的片段着色器代码:

uniform vec3 unicolor; 

varying vec3 vColor; 
varying float vAlpha; 
void main() { 
    #ifdef USE_COLOR 
     gl_FragColor = vec4(vColor, vAlpha); 
    #else 
     gl_FragColor = vec4(unicolor, vAlpha); 
    #endif 
} 

再次,如果顶点颜色设置我检查,然后将它传递给片段着色器,然后套每点。

由于某些原因,每个点设置颜色时,顶点都是白色的(截图:The white pixels should be green/red)。我远离WebGL的高级用户,任何帮助,将不胜感激。我做错了什么,我不知道?

回答

1

您创建自定义ShaderMaterial并在片段着色器使用这种模式:

#ifdef USE_COLOR 
    vColor = color; 
#endif 

因此,你需要指定material.defines像这样:

var defines = {}; 
defines[ "USE_COLOR" ] = ""; 

// points material 
var shaderMaterial = new THREE.ShaderMaterial({ 

    defines:  defines, 
    uniforms:  uniforms, 
    vertexShader: document.getElementById('vertexshader').textContent, 
    fragmentShader: document.getElementById('fragmentshader').textContent, 
    transparent: true 

}); 

你并不需要设置vertexColors: THREE.VertexColors。这只是内置材质使用的标志,用于提醒渲染器为您设置defines

three.js所r.85

+0

我做了修改,但我得到了相同的结果。 即使在之前,#ifdef代码部分也能正常工作。只是颜色总是白色的。出于某种原因,它被错误地传递给碎片着色器。 – bmakan

+0

欢迎使用stackoverflow。你设置'geometry.colors'意味着你正在使用'Geometry'而不是'BufferGeometry',在这种情况下这个答案是正确的。如果您使用'BufferGeometry',则需要设置属性。无论如何,您可以自由提供自己的答案以作进一步澄清,但最好接受帮助您的人的答案。 – WestLangley

0

OK,我想我想通了,因为它的工作现在。

我不得不设置颜色为几何属性:

const colors = new Float32Array(n * 3); 
for (let i = 0; i < n; i += 1) { 
    new THREE.Color(pointCloudData.colors[i]).toArray(colors, i * 3); 
} 
geometry.addAttribute('colors', new THREE.BufferAttribute(colors, 1)); 

我也使用WestLangley提供的建议,并除去vertexColors: THREE.VertexColors,部分从材料定义并设置限定,以及:

materials = new THREE.ShaderMaterial({ 
    defines: { 
     USE_COLOR: '', 
    }, 
    vertexShader: document.getElementById('vertexshader').textContent, 
    fragmentShader: document.getElementById('fragmentshader').textContent, 
    transparent: true, 
}); 

然后在我的顶点着色器我说:

attributes vec3 colors; 

获取从JavaScript传递的颜色。其余的都是一样的,我只是使用与上面发布的问题相同的代码将颜色传递给片段着色器。