我有一个简单的模型,其中包含1000个球体实例。我正在尝试使用实例化来减少绘图调用的次数。但是,我无法更改各个子几何的透明度/不透明度。
我已经尝试了以下操作:
我能够使用
更改每个球体的透明度material.fragmentShader = "varying vec3 vColor;void main() { gl_FragColor = vec4( vColor, 0.2 );}";
但是,这会将每个球体的不透明度更改为0.2。
html文件类似于:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>A-Frame Instancing component</title>
<meta name="description" content="A-Frame Instancing component">
<script>
/*
var WebVRConfig = {
FORCE_ENABLE_VR: true,
BUFFER_SCALE: 1.0
};
*/
</script>
<script src="https://cdn.rawgit.com/aframevr/aframe/v0.4.0/dist/aframe-master.min.js"></script>
<script src="https://cdn.rawgit.com/donmccurdy/aframe-extras/v3.2.0/dist/aframe-extras.min.js"></script>
<script type="text/javascript" src="build/aframe-instancing.js"></script>
</head>
<body>
<a-scene stats>
<a-assets>
<img id="sky" src="https://cdn.rawgit.com/aframevr/aframe/master/examples/primitives/models/peach-gradient.jpg">
</a-assets>
<a-entity instancing="count:100"></a-entity>
<a-sky src="#sky"></a-sky>
<a-entity light="type:directional;color:#FFFFFF" position="-1 1 1"></a-entity>
</a-scene>
</body>
</html>
实现实例化的功能:
AFRAME.registerComponent('instancing', {
schema: {
count: {type: 'int', default: 10000}
},
var geometry = new THREE.InstancedBufferGeometry();
geometry.copy(new THREE.SphereBufferGeometry(5.0));
var translateArray = new Float32Array(count*3);
var vectorArray = new Float32Array(count*3);
var colorArray = new Float32Array(count*3);
geometry.addAttribute('translate', new THREE.InstancedBufferAttribute(translateArray, 3, 1));
geometry.addAttribute('vector', new THREE.InstancedBufferAttribute(vectorArray, 3, 1));
geometry.addAttribute('color', new THREE.InstancedBufferAttribute(colorArray, 3, 1));
var material = new THREE.ShaderMaterial({
uniforms: {
time: {value: 0}
},
vertexShader: [
'attribute vec3 translate;',
'attribute vec3 vector;',
'attribute vec3 color;',
'uniform float time;',
'varying vec3 vColor;',
'const float g = 9.8 * 1.5;',
'void main() {',
' vec3 offset;',
' offset.xz = vector.xz * time;',
' offset.y = vector.y * time - 0.5 * g * time * time;',
' gl_Position = projectionMatrix * modelViewMatrix * vec4( position + translate + offset, 1.0 );',
' vColor = color;',
'}'
].join('\n'),
fragmentShader: [
'varying vec3 vColor;',
'void main() {',
' gl_FragColor = vec4( vColor, 1 );',
'}'
].join('\n')
});
var mesh = new THREE.Mesh(geometry, material);
this.model = mesh;
el.setObject3D('mesh', mesh);
el.emit('model-loaded', {format:'mesh', model: mesh});
//try to change opacity here
material.fragmentShader = "varying vec3 vColor;void main() { gl_FragColor = vec4( vColor, 0.2 );}";
material.transparent = true;
//use the new opacity
var mesh1 = new THREE.Mesh(geometry1, material);
this.mesh = mesh1;
el.setObject3D('mesh', mesh1);
el.emit('model-loaded', {format:'mesh', model: mesh1});
}
});
}
]);
任何人都可以告诉我,如何更改仅一个球体的不透明度吗?预先谢谢你!
答案 0 :(得分:2)
您的颜色仅是RGB
的值,而不是RGBA
。更新您的color
属性以支持4个值,并更改关联的vec3
引用以使用vec4
。向量中的最后一个值将是您的alpha
(透明度)值。
您似乎已经知道如何将vertex shader
中的值发送到fragment shader
中,因此在此我不再赘述。但是在您的fragment shader
中,您可以直接使用颜色,因为gl_FragColor
希望设置为vec4
。
进一步的说明:
创建InstancedBufferAttribute
时,将为每个实例创建一个属性 。因此,您的color
属性当前每个实例仅包含RGB
个值。
在1
处(即0.2
)对w
或gl_FragColor = vec4( vColor, 1 );
进行硬编码,可以将其普遍应用于所有实例。因此,您需要根据每个实例定义alpha
值,而最简单的方法是通过已创建并实例化的color
属性。
//geometry.addAttribute('color', new THREE.InstancedBufferAttribute(colorArray, 3, 1)
geometry.addAttribute('color', new THREE.InstancedBufferAttribute(colorArray, 4, 1)
上面的代码为alpha值腾出了空间,您应该为每个球体提供该值。您的colorArray
将包含诸如[ R, G, B, A, R, G, B, A, ... ]
之类的数据。
然后,在您的着色器中...
// vertex shader
// ...
attribute vec4 color;
varying vec4 vColor;
// ...
void main(){
// ...
vColor = color;
// ...
}
// fragment shader
// ...
varying vec4 vColor;
// ...
void main(){
// ...
gl_FragColor = vColor;
}
现在,您为每个球体实例提供的alpha值将仅用于该实例。例如,如果您希望索引1处的球体是唯一的透明球体,则colorArray
缓冲区应如下所示:
colorArray = [
1.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 0.5,
1.0, 1.0, 1.0, 1.0,
// ...
];`
重要警告
此实现不会对实例进行深度排序,因此混合将取决于渲染顺序。您可以在以下问题中阅读有关此内容的更多信息: