我需要创建一个包含数千个简单网格的场景,所以我决定使用InstancedBufferGeometry。我从此示例中复制了大部分代码:https://threejs.org/examples/#webgl_buffergeometry_instancing_dynamic
实例化有效,但仅适用于示例中的THREE.RawShaderMaterial
:
instancedMaterial = new THREE.RawShaderMaterial( {
uniforms: {
map: { value: new THREE.TextureLoader().load( 'textures/grassAlpha.png' ) },
time: { value: 0 }
},
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );
着色器:
<script id="vertexShader" type="x-shader/x-vertex">
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform float time;
attribute vec3 position;
attribute vec3 offset;
attribute vec2 uv;
attribute vec4 orientation;
varying vec2 vUv;
void main() {
vec3 vPosition = position;
vec3 vcV = cross( orientation.xyz, vPosition );
vPosition = vcV * ( 2.0 * orientation.w ) + ( cross( orientation.xyz, vcV ) * 2.0 + vPosition );
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( offset + vPosition, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision highp float;
uniform sampler2D map;
varying vec2 vUv;
void main() {
vec4 texelColor = texture2D( map, vUv );
if ( texelColor.a < 0.4 ) discard;
gl_FragColor = texelColor;
}
</script>
但是如何使用THREE.MeshPhongMaterial
代替这个简单的着色器呢?如果我使用其他材质(例如basic或phong)创建网格,它就会消失(或者可能变得完全透明,但控制台中没有错误)。
答案 0 :(得分:1)
您可以使用https://blender.stackexchange.com/a/18428。代码看起来像这样,只有一个实例属性offset
。
material.onBeforeCompile = function ( shader ) {
shader.vertexShader = 'attribute vec3 offset;\n' + shader.vertexShader;
shader.vertexShader = shader.vertexShader.replace( '#include <begin_vertex>',
[
'vec3 transformed = vec3( position + offset );',
].join( '\n' )
);
materialShader = shader;
};
答案 1 :(得分:0)
存在一个npm包,旨在解决这个问题,并为此问题提供用户友好的抽象。
https://www.npmjs.com/package/three-instanced-mesh
It seems to be working with shadows fine.
注意:这是一个副作用,它使它可以与三个所提供的一切一起工作,它不是专门设计用阴影渲染,而是用深度效果正确渲染,所有材料和相机等。
onBeforeCompile
可能会破坏某些内容,具体取决于它的使用方式。它似乎更多的是设计而不是错误,只是要注意它:
我认为它是非确定性的 - 如果你将if else
放在那里,你可能会根据场景中网格的顺序编制一个不同的着色器。
material.clone()
不会克隆整个对象等。在接受的答案中发布的演示实际上就是这种行为的一个很好的例子。
(see this issue on github)。
另一个问题可能是你发现很难&#34;链&#34;需要发生的逻辑。如果您继承了某人已使用onBeforeCompile
decorate_material_written_by_another_dev( material ){
...
material.onBeforeCompile = shader => {} //oops, what if there is one in there already
...
}
接受的答案所指的链接中没有记录这种行为。
重申一下,问题就出现了:
我需要创建一个包含数千个简单网格的场景,
如果你想优化数以千计的简单网格,你指的是某种场景图
Scene
|-Mesh0000
|-Mesh0001
...
|-Mesh1000
理想情况下,您不希望与Mesh.position
,Mesh.scale
,Mesh.rotation
/ Mesh.quaternion
建立类似的界面,无论优化结果如何?< / p>
换句话说,你不应该使用字符串,着色器,甚至可能不是材料。
想象一下,如果你能做到这一点:
import { InstanceMesh, InstanceMaterial } from 'examples/instancing' //or npm module
const myInstanceMesh = new InstanceMesh(
new CubeGeometry(),
new InstanceMaterial(new MeshStandardMaterial())
)
myInstanceMesh.material.onBeforeCompile = onBeforeCompile_unrelated_to_instancing
如果实施该示例的人使用了onBeforeCompile
,则会失败。这就是为什么你没有看到这样的例子。