Three.js 使用着色器设置每个点云的颜色 Material
Three.js setting each pointCloud's color with Shader Material
我想做的是创建多个 PointCloud,并为每个点分配不同的颜色。对于 PointCloudMaterial,它的颜色 属性 似乎可以解决问题,但由于我使用的是 ShaderMaterial,我似乎无法弄清楚如何实现类似的结果。
[编辑:添加图像以澄清]
我正在使用 ShaderMaterial,因为我想缩放一些自定义属性并更改每个顶点的不透明度。
创建粒子云的函数:
function addParticleCloud(width, height, colorIn, particleCount) {
var geometry = new THREE.Geometry();
// add randomized vertex positions for geometry
for (var i = 0; i < particleCount; i++) {
var vertex = new THREE.Vector3();
vertex.x = Math.random() * width;
vertex.y = Math.random() * height;
vertex.z = z;
geometry.vertices.push(vertex);
}
var attributeCount = attributes.alpha.value.length;
var totalCount = attributeCount + geometry.vertices.length;
// change attributes per particle/vertex
for (var i = attributeCount; i < totalCount; i++) {
// random alpha
attributes.alpha.value[i] = Math.random();
// random scale
attributes.scale.value[i] = Math.random() * (250.0 - 100) + 100;
// TRIED TO CHANGE COLORS HERE, but every cloud created afterwards has the
// same color as the first one.
attributes.colorVal.value[i] = new THREE.Color(colorIn);
attributes.colorVal.needsUpdate = true;
// update attributeCount
attributeCount = attributes.alpha.value.length;
}
var material = new THREE.ShaderMaterial({
uniforms: uniforms,
attributes: attributes,
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
transparent: true,
});
// This is the kind of thing I'd like to be able to do
//material.color = new THREE.Color(colorIn);
var particles = new THREE.PointCloud(geometry, material);
scene.add(particles);
}
调用该函数的代码:
// [width, height, color]
var rectangles = [
[400, 200, 0xA3422C],
[40, 500, 0x0040f0],
[200, 200, 0x2CA35E],
[40, 500, 0x2C8DA3],
];
for (var i = 0; i < rectangles.length; i++) {
var sqWidth = rectangles[i][0];
var sqHeight = rectangles[i][3];
var rectColor = rectangles[i][2];
var particleCount = 100;
// Note: I've removed some parameters for clarity (xyz positions, etc.)
addParticleCloud(sqWidth, sqHeight, rectColor, particleCount);
}
顶点和片段着色器代码:
<script type="x-shader/x-vertex" id="vertexshader">
attribute float alpha;
attribute float scale;
attribute vec3 colorVal;
uniform float size;
varying float vAlpha;
varying vec3 vColor;
void main() {
vColor = colorVal;
vAlpha = alpha;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size * ( scale / length( mvPosition.xyz ) );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
varying float vAlpha;
varying vec3 vColor;
void main() {
gl_FragColor = vec4( vColor.rgb, vAlpha );
}
</script>
属性和制服:
// attributes
attributes = {
alpha: {type: 'f', value: []},
shouldFade: {type: 'b', value: []},
scale: {type: 'f', value: []},
colorVal: {type: "c", value: []},
};
// uniforms
uniforms = {
size: {type: "f", value: 100.0},
};
为每个 material 创建单独的制服和属性(这也将简化属性处理)
如果我没记错的话,你的属性和制服是全局变量,你正试图在 material 之间共享属性。
共享制服是可行的(当然除非您希望它们不同),但是属性与顶点具有一对一的相关性。每个顶点在添加顶点的索引处获取属性 - 在您的情况下,所有三个点云的顶点都引用属性第一部分中的值,因此具有相同的颜色。
我想做的是创建多个 PointCloud,并为每个点分配不同的颜色。对于 PointCloudMaterial,它的颜色 属性 似乎可以解决问题,但由于我使用的是 ShaderMaterial,我似乎无法弄清楚如何实现类似的结果。
[编辑:添加图像以澄清]
我正在使用 ShaderMaterial,因为我想缩放一些自定义属性并更改每个顶点的不透明度。
创建粒子云的函数:
function addParticleCloud(width, height, colorIn, particleCount) {
var geometry = new THREE.Geometry();
// add randomized vertex positions for geometry
for (var i = 0; i < particleCount; i++) {
var vertex = new THREE.Vector3();
vertex.x = Math.random() * width;
vertex.y = Math.random() * height;
vertex.z = z;
geometry.vertices.push(vertex);
}
var attributeCount = attributes.alpha.value.length;
var totalCount = attributeCount + geometry.vertices.length;
// change attributes per particle/vertex
for (var i = attributeCount; i < totalCount; i++) {
// random alpha
attributes.alpha.value[i] = Math.random();
// random scale
attributes.scale.value[i] = Math.random() * (250.0 - 100) + 100;
// TRIED TO CHANGE COLORS HERE, but every cloud created afterwards has the
// same color as the first one.
attributes.colorVal.value[i] = new THREE.Color(colorIn);
attributes.colorVal.needsUpdate = true;
// update attributeCount
attributeCount = attributes.alpha.value.length;
}
var material = new THREE.ShaderMaterial({
uniforms: uniforms,
attributes: attributes,
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
transparent: true,
});
// This is the kind of thing I'd like to be able to do
//material.color = new THREE.Color(colorIn);
var particles = new THREE.PointCloud(geometry, material);
scene.add(particles);
}
调用该函数的代码:
// [width, height, color]
var rectangles = [
[400, 200, 0xA3422C],
[40, 500, 0x0040f0],
[200, 200, 0x2CA35E],
[40, 500, 0x2C8DA3],
];
for (var i = 0; i < rectangles.length; i++) {
var sqWidth = rectangles[i][0];
var sqHeight = rectangles[i][3];
var rectColor = rectangles[i][2];
var particleCount = 100;
// Note: I've removed some parameters for clarity (xyz positions, etc.)
addParticleCloud(sqWidth, sqHeight, rectColor, particleCount);
}
顶点和片段着色器代码:
<script type="x-shader/x-vertex" id="vertexshader">
attribute float alpha;
attribute float scale;
attribute vec3 colorVal;
uniform float size;
varying float vAlpha;
varying vec3 vColor;
void main() {
vColor = colorVal;
vAlpha = alpha;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size * ( scale / length( mvPosition.xyz ) );
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
varying float vAlpha;
varying vec3 vColor;
void main() {
gl_FragColor = vec4( vColor.rgb, vAlpha );
}
</script>
属性和制服:
// attributes
attributes = {
alpha: {type: 'f', value: []},
shouldFade: {type: 'b', value: []},
scale: {type: 'f', value: []},
colorVal: {type: "c", value: []},
};
// uniforms
uniforms = {
size: {type: "f", value: 100.0},
};
为每个 material 创建单独的制服和属性(这也将简化属性处理)
如果我没记错的话,你的属性和制服是全局变量,你正试图在 material 之间共享属性。
共享制服是可行的(当然除非您希望它们不同),但是属性与顶点具有一对一的相关性。每个顶点在添加顶点的索引处获取属性 - 在您的情况下,所有三个点云的顶点都引用属性第一部分中的值,因此具有相同的颜色。