Updated (multi) indirect draw example

This commit is contained in:
saschawillems 2016-08-01 21:43:47 +02:00
parent be68bc0a5a
commit 444c4b9c24
23 changed files with 1565 additions and 214 deletions

View file

@ -115,6 +115,13 @@ Also shows how to use multiple descriptor sets simultaneously with the new GLSL
Shows the use of instancing for rendering many copies of the same mesh using different attributes and textures. A secondary vertex buffer containing instanced data, stored in device local memory, is used to pass instance data to the shader via vertex attributes with a per-instance step rate. The instance data also contains a texture layer index for having different textures for the instanced meshes. Shows the use of instancing for rendering many copies of the same mesh using different attributes and textures. A secondary vertex buffer containing instanced data, stored in device local memory, is used to pass instance data to the shader via vertex attributes with a per-instance step rate. The instance data also contains a texture layer index for having different textures for the instanced meshes.
<br><br> <br><br>
## [Indirect drawing](indirectdraw/)
<img src="./screenshots/indirectdraw.jpg" height="96px" align="right">
This example renders thousands of instanced objects with different geometries using only one single indirect draw call. Unlike direct drawing function, indirect drawing functions take their draw commands from a buffer object containing information like index cound, index offset and number of instances to draw.
Shows how to generate and render such an indirect draw command buffer that is staged to the device. Indirect draw buffers are the base for generating and updating draw commands on the GPU using shaders.
## [Multi sampling](multisampling/) ## [Multi sampling](multisampling/)
<img src="./screenshots/multisampling.png" height="96px" align="right"> <img src="./screenshots/multisampling.png" height="96px" align="right">

View file

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor>
<author>Blender User</author>
<authoring_tool>Blender 2.77.0 commit date:2016-03-18, commit time:12:34, hash:22a2853</authoring_tool>
</contributor>
<created>2016-07-30T14:13:52</created>
<modified>2016-07-30T14:13:52</modified>
<unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_cameras>
<camera id="Camera-camera" name="Camera">
<optics>
<technique_common>
<perspective>
<xfov sid="xfov">49.13434</xfov>
<aspect_ratio>1.777778</aspect_ratio>
<znear sid="znear">0.1</znear>
<zfar sid="zfar">100</zfar>
</perspective>
</technique_common>
</optics>
<extra>
<technique profile="blender">
<YF_dofdist>0</YF_dofdist>
<shiftx>0</shiftx>
<shifty>0</shifty>
</technique>
</extra>
</camera>
</library_cameras>
<library_lights>
<light id="Lamp-light" name="Lamp">
<technique_common>
<point>
<color sid="color">1 1 1</color>
<constant_attenuation>1</constant_attenuation>
<linear_attenuation>0</linear_attenuation>
<quadratic_attenuation>0.00111109</quadratic_attenuation>
</point>
</technique_common>
<extra>
<technique profile="blender">
<adapt_thresh>0.000999987</adapt_thresh>
<area_shape>1</area_shape>
<area_size>0.1</area_size>
<area_sizey>0.1</area_sizey>
<area_sizez>1</area_sizez>
<atm_distance_factor>1</atm_distance_factor>
<atm_extinction_factor>1</atm_extinction_factor>
<atm_turbidity>2</atm_turbidity>
<att1>0</att1>
<att2>1</att2>
<backscattered_light>1</backscattered_light>
<bias>1</bias>
<blue>1</blue>
<buffers>1</buffers>
<bufflag>0</bufflag>
<bufsize>2880</bufsize>
<buftype>2</buftype>
<clipend>30.002</clipend>
<clipsta>1.000799</clipsta>
<compressthresh>0.04999995</compressthresh>
<dist sid="blender_dist">29.99998</dist>
<energy sid="blender_energy">1</energy>
<falloff_type>2</falloff_type>
<filtertype>0</filtertype>
<flag>0</flag>
<gamma sid="blender_gamma">1</gamma>
<green>1</green>
<halo_intensity sid="blnder_halo_intensity">1</halo_intensity>
<horizon_brightness>1</horizon_brightness>
<mode>8192</mode>
<ray_samp>1</ray_samp>
<ray_samp_method>1</ray_samp_method>
<ray_samp_type>0</ray_samp_type>
<ray_sampy>1</ray_sampy>
<ray_sampz>1</ray_sampz>
<red>1</red>
<samp>3</samp>
<shadhalostep>0</shadhalostep>
<shadow_b sid="blender_shadow_b">0</shadow_b>
<shadow_g sid="blender_shadow_g">0</shadow_g>
<shadow_r sid="blender_shadow_r">0</shadow_r>
<sky_colorspace>0</sky_colorspace>
<sky_exposure>1</sky_exposure>
<skyblendfac>1</skyblendfac>
<skyblendtype>1</skyblendtype>
<soft>3</soft>
<spotblend>0.15</spotblend>
<spotsize>75</spotsize>
<spread>1</spread>
<sun_brightness>1</sun_brightness>
<sun_effect_type>0</sun_effect_type>
<sun_intensity>1</sun_intensity>
<sun_size>1</sun_size>
<type>0</type>
</technique>
</extra>
</light>
</library_lights>
<library_images/>
<library_geometries>
<geometry id="Circle-mesh" name="Circle">
<mesh>
<source id="Circle-mesh-positions">
<float_array id="Circle-mesh-positions-array" count="195">0 0 0 0 1 0 -0.09801709 0.9951847 0 -0.1950903 0.9807853 0 -0.2902846 0.9569404 0 -0.3826835 0.9238795 0 -0.4713968 0.8819212 0 -0.5555703 0.8314696 0 -0.6343933 0.7730105 0 -0.7071068 0.7071068 0 -0.7730104 0.6343933 0 -0.8314696 0.5555703 0 -0.8819212 0.4713968 0 -0.9238795 0.3826834 0 -0.9569404 0.2902846 0 -0.9807853 0.1950902 0 -0.9951847 0.09801697 0 -1 -1.62921e-7 0 -0.9951847 -0.09801733 0 -0.9807853 -0.1950905 0 -0.9569402 -0.2902849 0 -0.9238794 -0.3826837 0 -0.8819211 -0.4713971 0 -0.8314694 -0.5555706 0 -0.7730102 -0.6343936 0 -0.7071065 -0.7071071 0 -0.6343929 -0.7730108 0 -0.5555698 -0.83147 0 -0.4713962 -0.8819215 0 -0.3826828 -0.9238798 0 -0.290284 -0.9569405 0 -0.1950896 -0.9807854 0 -0.09801638 -0.9951848 0 8.02678e-7 -1 0 0.09801793 -0.9951847 0 0.1950911 -0.9807851 0 0.2902855 -0.9569401 0 0.3826843 -0.9238792 0 0.4713976 -0.8819208 0 0.5555711 -0.8314691 0 0.6343941 -0.7730098 0 0.7071076 -0.707106 0 0.773011 -0.6343926 0 0.83147 -0.5555697 0 0.8819215 -0.4713963 0 0.9238797 -0.3826831 0 0.9569404 -0.2902845 0 0.9807853 -0.1950904 0 0.9951847 -0.09801739 0 1 -4.64912e-7 0 0.9951848 0.09801644 0 0.9807854 0.1950895 0 0.9569407 0.2902836 0 0.9238801 0.3826823 0 0.881922 0.4713954 0 0.8314706 0.5555689 0 0.7730116 0.6343919 0 0.7071083 0.7071053 0 0.634395 0.773009 0 0.5555723 0.8314682 0 0.4713991 0.88192 0 0.382686 0.9238784 0 0.2902876 0.9569395 0 0.1950935 0.9807847 0 0.09802055 0.9951844 0</float_array>
<technique_common>
<accessor source="#Circle-mesh-positions-array" count="65" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Circle-mesh-normals">
<float_array id="Circle-mesh-normals-array" count="3">0 0 1</float_array>
<technique_common>
<accessor source="#Circle-mesh-normals-array" count="1" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Circle-mesh-map-0">
<float_array id="Circle-mesh-map-0-array" count="384">0.5 0.5 0.5 1 0.4509914 0.9975923 0.5 0.5 0.4509914 0.9975923 0.4024549 0.9903926 0.5 0.5 0.4024549 0.9903926 0.3548577 0.9784702 0.5 0.5 0.3548577 0.9784702 0.3086583 0.9619398 0.5 0.5 0.3086583 0.9619398 0.2643016 0.9409607 0.5 0.5 0.2643016 0.9409607 0.2222148 0.9157348 0.5 0.5 0.2222148 0.9157348 0.1828033 0.8865053 0.5 0.5 0.1828033 0.8865053 0.1464466 0.8535534 0.5 0.5 0.1464466 0.8535534 0.1134948 0.8171967 0.5 0.5 0.1134948 0.8171967 0.08426517 0.7777852 0.5 0.5 0.08426517 0.7777852 0.05903935 0.7356984 0.5 0.5 0.05903935 0.7356984 0.03806024 0.6913417 0.5 0.5 0.03806024 0.6913417 0.02152979 0.6451423 0.5 0.5 0.02152979 0.6451423 0.009607315 0.5975452 0.5 0.5 0.009607315 0.5975452 0.00240761 0.5490085 0.5 0.5 0.00240761 0.5490085 0 0.4999999 0.5 0.5 0 0.4999999 0.00240761 0.4509913 0.5 0.5 0.00240761 0.4509913 0.009607374 0.4024547 0.5 0.5 0.009607374 0.4024547 0.02152985 0.3548575 0.5 0.5 0.02152985 0.3548575 0.0380603 0.3086581 0.5 0.5 0.0380603 0.3086581 0.05903941 0.2643015 0.5 0.5 0.05903941 0.2643015 0.08426529 0.2222147 0.5 0.5 0.08426529 0.2222147 0.1134949 0.1828032 0.5 0.5 0.1134949 0.1828032 0.1464467 0.1464464 0.5 0.5 0.1464467 0.1464464 0.1828035 0.1134946 0.5 0.5 0.1828035 0.1134946 0.2222151 0.08426499 0.5 0.5 0.2222151 0.08426499 0.2643019 0.05903923 0.5 0.5 0.2643019 0.05903923 0.3086586 0.03806006 0.5 0.5 0.3086586 0.03806006 0.354858 0.02152973 0.5 0.5 0.354858 0.02152973 0.4024552 0.009607255 0.5 0.5 0.4024552 0.009607255 0.4509918 0.00240761 0.5 0.5 0.4509918 0.00240761 0.5000004 0 0.5 0.5 0.5000004 0 0.549009 0.00240767 0.5 0.5 0.549009 0.00240767 0.5975456 0.009607434 0.5 0.5 0.5975456 0.009607434 0.6451428 0.02152997 0.5 0.5 0.6451428 0.02152997 0.6913422 0.03806042 0.5 0.5 0.6913422 0.03806042 0.7356988 0.05903959 0.5 0.5 0.7356988 0.05903959 0.7777855 0.08426547 0.5 0.5 0.7777855 0.08426547 0.8171971 0.1134951 0.5 0.5 0.8171971 0.1134951 0.8535538 0.146447 0.5 0.5 0.8535538 0.146447 0.8865055 0.1828037 0.5 0.5 0.8865055 0.1828037 0.915735 0.2222151 0.5 0.5 0.915735 0.2222151 0.9409608 0.2643018 0.5 0.5 0.9409608 0.2643018 0.9619398 0.3086584 0.5 0.5 0.9619398 0.3086584 0.9784702 0.3548578 0.5 0.5 0.9784702 0.3548578 0.9903926 0.4024548 0.5 0.5 0.9903926 0.4024548 0.9975923 0.4509913 0.5 0.5 0.9975923 0.4509913 1 0.4999998 0.5 0.5 1 0.4999998 0.9975924 0.5490083 0.5 0.5 0.9975924 0.5490083 0.9903927 0.5975447 0.5 0.5 0.9903927 0.5975447 0.9784703 0.6451418 0.5 0.5 0.9784703 0.6451418 0.9619401 0.6913412 0.5 0.5 0.9619401 0.6913412 0.940961 0.7356978 0.5 0.5 0.940961 0.7356978 0.9157353 0.7777845 0.5 0.5 0.9157353 0.7777845 0.8865059 0.8171959 0.5 0.5 0.8865059 0.8171959 0.8535541 0.8535527 0.5 0.5 0.8535541 0.8535527 0.8171975 0.8865045 0.5 0.5 0.8171975 0.8865045 0.7777861 0.9157341 0.5 0.5 0.7777861 0.9157341 0.7356995 0.9409601 0.5 0.5 0.7356995 0.9409601 0.691343 0.9619392 0.5 0.5 0.691343 0.9619392 0.6451438 0.9784697 0.5 0.5 0.6451438 0.9784697 0.5975468 0.9903923 0.5 0.5 0.5975468 0.9903923 0.5490103 0.9975922 0.5 0.5 0.5490103 0.9975922 0.5 1</float_array>
<technique_common>
<accessor source="#Circle-mesh-map-0-array" count="192" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="Circle-mesh-vertices">
<input semantic="POSITION" source="#Circle-mesh-positions"/>
</vertices>
<polylist count="64">
<input semantic="VERTEX" source="#Circle-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Circle-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Circle-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>0 0 0 1 0 1 2 0 2 0 0 3 2 0 4 3 0 5 0 0 6 3 0 7 4 0 8 0 0 9 4 0 10 5 0 11 0 0 12 5 0 13 6 0 14 0 0 15 6 0 16 7 0 17 0 0 18 7 0 19 8 0 20 0 0 21 8 0 22 9 0 23 0 0 24 9 0 25 10 0 26 0 0 27 10 0 28 11 0 29 0 0 30 11 0 31 12 0 32 0 0 33 12 0 34 13 0 35 0 0 36 13 0 37 14 0 38 0 0 39 14 0 40 15 0 41 0 0 42 15 0 43 16 0 44 0 0 45 16 0 46 17 0 47 0 0 48 17 0 49 18 0 50 0 0 51 18 0 52 19 0 53 0 0 54 19 0 55 20 0 56 0 0 57 20 0 58 21 0 59 0 0 60 21 0 61 22 0 62 0 0 63 22 0 64 23 0 65 0 0 66 23 0 67 24 0 68 0 0 69 24 0 70 25 0 71 0 0 72 25 0 73 26 0 74 0 0 75 26 0 76 27 0 77 0 0 78 27 0 79 28 0 80 0 0 81 28 0 82 29 0 83 0 0 84 29 0 85 30 0 86 0 0 87 30 0 88 31 0 89 0 0 90 31 0 91 32 0 92 0 0 93 32 0 94 33 0 95 0 0 96 33 0 97 34 0 98 0 0 99 34 0 100 35 0 101 0 0 102 35 0 103 36 0 104 0 0 105 36 0 106 37 0 107 0 0 108 37 0 109 38 0 110 0 0 111 38 0 112 39 0 113 0 0 114 39 0 115 40 0 116 0 0 117 40 0 118 41 0 119 0 0 120 41 0 121 42 0 122 0 0 123 42 0 124 43 0 125 0 0 126 43 0 127 44 0 128 0 0 129 44 0 130 45 0 131 0 0 132 45 0 133 46 0 134 0 0 135 46 0 136 47 0 137 0 0 138 47 0 139 48 0 140 0 0 141 48 0 142 49 0 143 0 0 144 49 0 145 50 0 146 0 0 147 50 0 148 51 0 149 0 0 150 51 0 151 52 0 152 0 0 153 52 0 154 53 0 155 0 0 156 53 0 157 54 0 158 0 0 159 54 0 160 55 0 161 0 0 162 55 0 163 56 0 164 0 0 165 56 0 166 57 0 167 0 0 168 57 0 169 58 0 170 0 0 171 58 0 172 59 0 173 0 0 174 59 0 175 60 0 176 0 0 177 60 0 178 61 0 179 0 0 180 61 0 181 62 0 182 0 0 183 62 0 184 63 0 185 0 0 186 63 0 187 64 0 188 0 0 189 64 0 190 1 0 191</p>
</polylist>
</mesh>
</geometry>
</library_geometries>
<library_controllers/>
<library_visual_scenes>
<visual_scene id="Scene" name="Scene">
<node id="Camera" name="Camera" type="NODE">
<matrix sid="transform">0.6858805 -0.3173701 0.6548619 7.481132 0.7276338 0.3124686 -0.6106656 -6.50764 -0.01081678 0.8953432 0.4452454 5.343665 0 0 0 1</matrix>
<instance_camera url="#Camera-camera"/>
</node>
<node id="Lamp" name="Lamp" type="NODE">
<matrix sid="transform">-0.2908646 -0.7711008 0.5663932 4.076245 0.9551712 -0.1998834 0.2183912 1.005454 -0.05518906 0.6045247 0.7946723 5.903862 0 0 0 1</matrix>
<instance_light url="#Lamp-light"/>
</node>
<node id="Circle" name="Circle" type="NODE">
<matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
<instance_geometry url="#Circle-mesh" name="Circle"/>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#Scene"/>
</scene>
</COLLADA>

1015
data/models/plants.dae Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,2 +0,0 @@
glslangvalidator -V indirectdraw.vert -o indirectdraw.vert.spv
glslangvalidator -V indirectdraw.frag -o indirectdraw.frag.spv

View file

@ -0,0 +1,28 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (binding = 2) uniform sampler2D samplerColor;
layout (location = 0) in vec3 inNormal;
layout (location = 1) in vec3 inColor;
layout (location = 2) in vec2 inUV;
layout (location = 3) in vec3 inViewVec;
layout (location = 4) in vec3 inLightVec;
layout (location = 0) out vec4 outFragColor;
void main()
{
// Last array layer is terrain tex
vec4 color = texture(samplerColor, inUV);
vec3 N = normalize(inNormal);
vec3 L = normalize(inLightVec);
vec3 V = normalize(inViewVec);
vec3 R = reflect(-L, N);
vec3 ambient = vec3(0.65);
vec3 diffuse = max(dot(N, L), 0.0) * inColor;
vec3 specular = pow(max(dot(R, V), 0.0), 16.0) * vec3(0.1);
outFragColor = vec4((ambient + diffuse) * color.rgb + specular, 1.0);
}

Binary file not shown.

View file

@ -0,0 +1,42 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
// Vertex attributes
layout (location = 0) in vec4 inPos;
layout (location = 1) in vec3 inNormal;
layout (location = 2) in vec2 inUV;
layout (location = 3) in vec3 inColor;
layout (binding = 0) uniform UBO
{
mat4 projection;
mat4 modelview;
} ubo;
layout (location = 0) out vec3 outNormal;
layout (location = 1) out vec3 outColor;
layout (location = 2) out vec2 outUV;
layout (location = 3) out vec3 outViewVec;
layout (location = 4) out vec3 outLightVec;
out gl_PerVertex
{
vec4 gl_Position;
};
void main()
{
outColor = inColor;
outUV = inUV * 32.0;
vec4 pos = vec4(inPos.xyz, 1.0);
gl_Position = ubo.projection * ubo.modelview * pos;
vec4 wPos = ubo.modelview * vec4(pos.xyz, 1.0);
vec4 lPos = vec4(0.0, -5.0, 0.0, 1.0);
outLightVec = lPos.xyz - pos.xyz;
outViewVec = -pos.xyz;
}

Binary file not shown.

View file

@ -7,28 +7,24 @@ layout (binding = 1) uniform sampler2DArray samplerArray;
layout (location = 0) in vec3 inNormal; layout (location = 0) in vec3 inNormal;
layout (location = 1) in vec3 inColor; layout (location = 1) in vec3 inColor;
layout (location = 2) in vec3 inEyePos; layout (location = 2) in vec3 inUV;
layout (location = 3) in vec3 inLightVec; layout (location = 3) in vec3 inViewVec;
layout (location = 4) in vec3 inUV; layout (location = 4) in vec3 inLightVec;
layout (location = 0) out vec4 outFragColor; layout (location = 0) out vec4 outFragColor;
void main() void main()
{ {
vec4 color = texture(samplerArray, inUV) * vec4(inColor, 1.0); vec4 color = texture(samplerArray, inUV);
if (color.a < 0.5)
{
discard;
}
vec3 N = normalize(inNormal); vec3 N = normalize(inNormal);
vec3 L = normalize(vec3(1.0)); vec3 L = normalize(inLightVec);
vec3 ambient = vec3(0.65);
vec3 Eye = normalize(-inEyePos); vec3 diffuse = max(dot(N, L), 0.0) * inColor;
vec3 Reflected = normalize(reflect(-inLightVec, inNormal)); outFragColor = vec4((ambient + diffuse) * color.rgb, 1.0);
vec4 IAmbient = vec4(vec3(0.1), 1.0);
vec4 IDiffuse = vec4(1.0) * max(dot(inNormal, inLightVec), 0.0);
float specular = 0.75;
vec4 ISpecular = vec4(0.5, 0.5, 0.5, 1.0) * pow(max(dot(Reflected, Eye), 0.0), 32.0) * specular;
outFragColor = vec4((IAmbient + IDiffuse) * color + ISpecular);
} }

View file

@ -12,22 +12,20 @@ layout (location = 3) in vec3 inColor;
// Instanced attributes // Instanced attributes
layout (location = 4) in vec3 instancePos; layout (location = 4) in vec3 instancePos;
layout (location = 5) in vec3 instanceRot; layout (location = 5) in vec3 instanceRot;
layout (location = 6) in vec3 instanceColor; layout (location = 6) in float instanceScale;
layout (location = 7) in float instanceScale; layout (location = 7) in int instanceTexIndex;
layout (location = 8) in int instanceTexIndex;
layout (binding = 0) uniform UBO layout (binding = 0) uniform UBO
{ {
mat4 projection; mat4 projection;
mat4 view; mat4 modelview;
float time;
} ubo; } ubo;
layout (location = 0) out vec3 outNormal; layout (location = 0) out vec3 outNormal;
layout (location = 1) out vec3 outColor; layout (location = 1) out vec3 outColor;
layout (location = 2) out vec3 outEyePos; layout (location = 2) out vec3 outUV;
layout (location = 3) out vec3 outLightVec; layout (location = 3) out vec3 outViewVec;
layout (location = 4) out vec3 outUV; layout (location = 4) out vec3 outLightVec;
out gl_PerVertex out gl_PerVertex
{ {
@ -36,8 +34,9 @@ out gl_PerVertex
void main() void main()
{ {
outColor = instanceColor; outColor = inColor;
outUV = vec3(inUV, instanceTexIndex); outUV = vec3(inUV, instanceTexIndex);
outUV.t = 1.0 - outUV.t;
mat4 mx, my, mz; mat4 mx, my, mz;
@ -51,8 +50,8 @@ void main()
mx[3] = vec4(0.0, 0.0, 0.0, 1.0); mx[3] = vec4(0.0, 0.0, 0.0, 1.0);
// rotate around y // rotate around y
s = sin(instanceRot.y + ubo.time); s = sin(instanceRot.y);
c = cos(instanceRot.y + ubo.time); c = cos(instanceRot.y);
my[0] = vec4(c, 0.0, s, 0.0); my[0] = vec4(c, 0.0, s, 0.0);
my[1] = vec4(0.0, 1.0, 0.0, 0.0); my[1] = vec4(0.0, 1.0, 0.0, 0.0);
@ -74,10 +73,10 @@ void main()
vec4 pos = vec4((inPos.xyz * instanceScale) + instancePos, 1.0) * rotMat; vec4 pos = vec4((inPos.xyz * instanceScale) + instancePos, 1.0) * rotMat;
outEyePos = vec3(ubo.view * pos); gl_Position = ubo.projection * ubo.modelview * pos;
gl_Position = ubo.projection * ubo.view * pos; vec4 wPos = ubo.modelview * vec4(pos.xyz, 1.0);
vec4 lPos = vec4(0.0, -5.0, 0.0, 1.0);
vec4 lightPos = vec4(0.0, 0.0, 0.0, 1.0) * ubo.view; outLightVec = lPos.xyz - pos.xyz;
outLightVec = normalize(lightPos.xyz - outEyePos); outViewVec = -pos.xyz;
} }

View file

@ -0,0 +1,17 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (binding = 2) uniform sampler2D samplerColor;
layout (location = 0) in vec2 inUV;
layout (location = 0) out vec4 outFragColor;
void main()
{
const vec4 gradientStart = vec4(0.93, 0.9, 0.81, 1.0);
const vec4 gradientEnd = vec4(0.35, 0.5, 1.0, 1.0);
outFragColor = mix(gradientStart, gradientEnd, min(0.5 - inUV.t, 0.5)/0.15 + 0.5);
}

Binary file not shown.

View file

@ -0,0 +1,28 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
// Vertex attributes
layout (location = 0) in vec4 inPos;
layout (location = 2) in vec2 inUV;
layout (binding = 0) uniform UBO
{
mat4 projection;
mat4 modelview;
} ubo;
layout (location = 0) out vec2 outUV;
out gl_PerVertex
{
vec4 gl_Position;
};
void main()
{
outUV = vec2(inUV.s, 1.0-inUV.t);
// Skysphere always at center, only use rotation part of modelview matrix
gl_Position = ubo.projection * mat4(mat3(ubo.modelview)) * vec4(inPos.xyz, 1.0);
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

101
indirectdraw/README.md Normal file
View file

@ -0,0 +1,101 @@
# Indirect drawing
<img src="../screenshots/indirectdraw.jpg" height="256px">
## Synopsis
Issue multiple instanced draws for different meshes in one single draw call using indirect draw commands.
## Requirements
The example requires a GPU that supports the [`multiDrawIndirect`](http://vulkan.gpuinfo.org/listreports.php?feature=multiDrawIndirect) feature. If this feature is not available, the `drawCount` parameter for the `vkCmdDrawIndexedIndirect` call must be 1.
When issuing many draw counts also make sure to stay within the limitations of [`maxDrawIndirectCount`](http://vulkan.gpuinfo.org/listreports.php?limit=maxDrawIndirectCount).
## Description
This example demonstrates the use of indirect draw commands. In addition to draw functions like [`vkCmdDraw`](https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkCmdDraw.html) and [`vkCmdDrawIndexed`](https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkCmdDrawIndexed.html), where the parameters that specify what is drawn are passed directly to the function ("direct drawing"), there also exist indirect drawing commands.
[`vkCmdDrawIndirect`](https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkCmdDrawIndirect.html) and [`vkCmdDrawIndexedIndirect`](https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkCmdDrawIndexedIndirect.html) take the draw commands from a buffer object that contains descriptions on the draw commands to be issued, including instance and index counts, vertex offsets, etc. This also allows to draw multiple geometries with a single draw command as long as they're backed up by the same vertex (and index) buffer.
This adds several new possibilities of generating (and updating) actual draw commands, as that buffer can be generated and updated offline with no need to actually update the command buffers that contain the actual drawing functions.
Using indirect drawing you can generate the draw commands offline ahead of time on the CPU and even update them using shaders (as they're stored in a device local buffer). This adds lots of new possibilites to update draw commands without the CPU being involved, including GPU-based culling.
The example generates a single indirect buffer that contains draw commands for 12 different plants at random position, scale and rotation also using instancing to render the objects multiple times. The whole foliage (and trees) seen in the screen are drawn using only one draw call.
The different plant meshes are loaded from a single file and stored inside a single index and vertex buffer, index offsets are stored inside the indirect draw commands.
For details on the use of instancing (and instanced vertex attributes), see the [instancing example](../instancing)
## Points of interest
### Preparing the indirect draw
The example generates the indirect drawing buffer right at the start. First step is to generate the data for the indirect draws. Vulkan has a dedicated struct for this called `VkDrawIndexedIndirectCommand` and the example uses a `std::vector<VkDrawIndexedIndirectCommand>` to store these before uploading them to the GPU:
```cpp
void prepareIndirectData()
{
...
uint32_t m = 0;
for (auto& meshDescriptor : meshes.plants.meshDescriptors)
{
VkDrawIndexedIndirectCommand indirectCmd{};
indirectCmd.instanceCount = OBJECT_INSTANCE_COUNT;
indirectCmd.firstInstance = m * OBJECT_INSTANCE_COUNT;
indirectCmd.firstIndex = meshDescriptor.indexBase;
indirectCmd.indexCount = meshDescriptor.indexCount;
indirectCommands.push_back(indirectCmd);
m++;
}
...
}
```
The meshDescriptor is generated by the mesh loader and contains the index base and count of that mesh inside the global index buffer containing all plant meshes for the scenery.
The indirect draw command for the second plant mesh looks like this:
```cpp
indirectCmd.indexCount = 1668;
indirectCmd.instanceCount = 2048;
indirectCmd.firstIndex = 960;
indirectCmd.vertexOffset = 0;
indirectCmd.firstInstance = 2048;
```
Which will result in 2048 instances of the index data starting at index 960 (using 1668 indices) being drawn, the first instance is also important as the shader is using it for the instanced attributes of that object (position, rotation, scale).
Once we have filled that vector we need to create the buffer that the GPU uses to read the indirect commands from:
```cpp
VK_CHECK_RESULT(vulkanDevice->createBuffer(
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
&indirectCommandsBuffer,
stagingBuffer.size));
vulkanDevice->copyBuffer(&stagingBuffer, &indirectCommandsBuffer, queue);
```
To use a buffer for indirect draw commands you need to specify the ```VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT``` usage flag at creation time. As the buffer is never again changed on the host side we stage it to the GPU to maximize performance.
### Rendering
Issuing the actual indirect draw command is pretty straightforward:
```cpp
void buildCommandBuffers()
{
...
for (int32_t i = 0; i < drawCmdBuffers.size(); ++i)
{
vkCmdDrawIndexedIndirect(drawCmdBuffers[i], indirectCommandsBuffer.buffer, 0, indirectDrawCount, sizeof(VkDrawIndexedIndirectCommand));
}
}
```
We just pass the buffer handle to the buffer containing the indirect draw commands and the number of drawCounts.
The non-indirect, non-instanced equivalent of this would be:
```cpp
for (auto indirectCmd : indirectCommands)
{
for (uint32_t j = 0; j < indirectCmd.instanceCount; j++)
{
vkCmdDrawIndexed(drawCmdBuffers[i], indirectCmd.indexCount, 1, indirectCmd.firstIndex, 0, indirectCmd.firstInstance + j);
}
}
```
### Acknowledgements
- Plant and foliage models by [Hugues Muller](http://www.yughues-folio.com/)

View file

@ -6,13 +6,16 @@
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
* *
* Summary: * Summary:
* Use a device local buffer that stores draw commands for instanced rendering of different meshes. * Use a device local buffer that stores draw commands for instanced rendering of different meshes stored
* in the same buffer.
* *
* Indirect drawing offloads draw command generation and offers the ability to update them on the GPU * Indirect drawing offloads draw command generation and offers the ability to update them on the GPU
* without the CPU having to touch the buffer again, also reducing the number of drawcalls. * without the CPU having to touch the buffer again, also reducing the number of drawcalls.
* *
* The example shows how to setup and fill such a buffer on the CPU side, stages it to the device and * The example shows how to setup and fill such a buffer on the CPU side, stages it to the device and
* shows how render it using only one draw command. * shows how to render it using only one draw command.
*
* See readme.md for details
* *
*/ */
@ -39,6 +42,8 @@
// Number of instances per object // Number of instances per object
#define OBJECT_INSTANCE_COUNT 2048 #define OBJECT_INSTANCE_COUNT 2048
// Circular range of plant distribution
#define PLANT_RADIUS 25.0f
// Vertex layout for this example // Vertex layout for this example
std::vector<vkMeshLoader::VertexLayout> vertexLayout = std::vector<vkMeshLoader::VertexLayout> vertexLayout =
@ -59,18 +64,20 @@ public:
} vertices; } vertices;
struct { struct {
vkMeshLoader::MeshBuffer example; vkMeshLoader::MeshBuffer plants;
vkMeshLoader::MeshBuffer ground;
vkMeshLoader::MeshBuffer skysphere;
} meshes; } meshes;
struct { struct {
vkTools::VulkanTexture colorMap; vkTools::VulkanTexture colorMap;
vkTools::VulkanTexture ground;
} textures; } textures;
// Per-instance data block // Per-instance data block
struct InstanceData { struct InstanceData {
glm::vec3 pos; glm::vec3 pos;
glm::vec3 rot; glm::vec3 rot;
glm::vec3 color;
float scale; float scale;
uint32_t texIndex; uint32_t texIndex;
}; };
@ -84,7 +91,6 @@ public:
struct { struct {
glm::mat4 projection; glm::mat4 projection;
glm::mat4 view; glm::mat4 view;
float time = 0.0f;
} uboVS; } uboVS;
struct { struct {
@ -92,13 +98,17 @@ public:
} uniformData; } uniformData;
struct { struct {
VkPipeline solid; VkPipeline plants;
VkPipeline ground;
VkPipeline skysphere;
} pipelines; } pipelines;
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout;
VkDescriptorSet descriptorSet; VkDescriptorSet descriptorSet;
VkDescriptorSetLayout descriptorSetLayout; VkDescriptorSetLayout descriptorSetLayout;
VkSampler samplerRepeat;
uint32_t objectCount = 0; uint32_t objectCount = 0;
// Store the indirect draw commands containing index offsets and instance count per object // Store the indirect draw commands containing index offsets and instance count per object
@ -106,19 +116,23 @@ public:
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
{ {
zoom = -12.0f;
rotationSpeed = 0.25f;
enableTextOverlay = true; enableTextOverlay = true;
title = "Vulkan Example - Indirect rendering"; title = "Vulkan Example - Indirect rendering";
camera.type = Camera::CameraType::firstperson;
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f);
camera.setRotation(glm::vec3(-12.0f, 159.0f, 0.0f));
camera.setTranslation(glm::vec3(0.4f, 1.25f, 0.0f));
camera.movementSpeed = 5.0f;
srand(time(NULL)); srand(time(NULL));
} }
~VulkanExample() ~VulkanExample()
{ {
vkDestroyPipeline(device, pipelines.solid, nullptr); vkDestroyPipeline(device, pipelines.plants, nullptr);
vkDestroyPipeline(device, pipelines.ground, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
vkMeshLoader::freeMeshBufferResources(device, &meshes.example); vkMeshLoader::freeMeshBufferResources(device, &meshes.plants);
textureLoader->destroyTexture(textures.colorMap); textureLoader->destroyTexture(textures.colorMap);
instanceBuffer.destroy(); instanceBuffer.destroy();
indirectCommandsBuffer.destroy(); indirectCommandsBuffer.destroy();
@ -140,7 +154,7 @@ public:
VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo(); VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo();
VkClearValue clearValues[2]; VkClearValue clearValues[2];
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 0.0f } }; clearValues[0].color = { { 0.18f, 0.27f, 0.5f, 0.0f } };
clearValues[1].depthStencil = { 1.0f, 0 }; clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = vkTools::initializers::renderPassBeginInfo(); VkRenderPassBeginInfo renderPassBeginInfo = vkTools::initializers::renderPassBeginInfo();
@ -165,38 +179,47 @@ public:
VkRect2D scissor = vkTools::initializers::rect2D(width, height, 0, 0); VkRect2D scissor = vkTools::initializers::rect2D(width, height, 0, 0);
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.solid);
VkDeviceSize offsets[1] = { 0 }; VkDeviceSize offsets[1] = { 0 };
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);
// Plants
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.plants);
// Binding point 0 : Mesh vertex buffer // Binding point 0 : Mesh vertex buffer
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &meshes.example.vertices.buf, offsets); vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &meshes.plants.vertices.buf, offsets);
// Binding point 1 : Instance data buffer // Binding point 1 : Instance data buffer
vkCmdBindVertexBuffers(drawCmdBuffers[i], INSTANCE_BUFFER_BIND_ID, 1, &instanceBuffer.buffer, offsets); vkCmdBindVertexBuffers(drawCmdBuffers[i], INSTANCE_BUFFER_BIND_ID, 1, &instanceBuffer.buffer, offsets);
vkCmdBindIndexBuffer(drawCmdBuffers[i], meshes.example.indices.buf, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(drawCmdBuffers[i], meshes.plants.indices.buf, 0, VK_INDEX_TYPE_UINT32);
// One draw call for an arbitrary number of ojects // One draw call for an arbitrary number of ojects
// Index offsets and instance count are taken from the indirect buffer // Index offsets and instance count are taken from the indirect buffer
vkCmdDrawIndexedIndirect(drawCmdBuffers[i], indirectCommandsBuffer.buffer, 0, indirectDrawCount, sizeof(VkDrawIndexedIndirectCommand)); vkCmdDrawIndexedIndirect(drawCmdBuffers[i], indirectCommandsBuffer.buffer, 0, indirectDrawCount, sizeof(VkDrawIndexedIndirectCommand));
// Ground
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.ground);
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &meshes.ground.vertices.buf, offsets);
vkCmdBindIndexBuffer(drawCmdBuffers[i], meshes.ground.indices.buf, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(drawCmdBuffers[i], meshes.ground.indexCount, 1, 0, 0, 0);
// Skysphere
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.skysphere);
vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &meshes.skysphere.vertices.buf, offsets);
vkCmdBindIndexBuffer(drawCmdBuffers[i], meshes.skysphere.indices.buf, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(drawCmdBuffers[i], meshes.skysphere.indexCount, 1, 0, 0, 0);
vkCmdEndRenderPass(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]);
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
} }
} }
void loadMeshes() void loadAssets()
{ {
loadMesh(getAssetPath() + "models/basicmeshes.dae", &meshes.example, vertexLayout, 0.1f); loadMesh(getAssetPath() + "models/plants.dae", &meshes.plants, vertexLayout, 0.0025f);
} loadMesh(getAssetPath() + "models/plane_circle.dae", &meshes.ground, vertexLayout, PLANT_RADIUS + 1.0f);
loadMesh(getAssetPath() + "models/skysphere.dae", &meshes.skysphere, vertexLayout, 512.0f);
void loadTextures() textureLoader->loadTextureArray(getAssetPath() + "textures/texturearray_plants_bc3.ktx", VK_FORMAT_BC3_UNORM_BLOCK, &textures.colorMap);
{ textureLoader->loadTexture(getAssetPath() + "textures/ground_dry_bc3.ktx", VK_FORMAT_BC3_UNORM_BLOCK, &textures.ground);
textureLoader->loadTextureArray(
getAssetPath() + "textures/texturearray_rocks_bc3.ktx",
VK_FORMAT_BC3_UNORM_BLOCK,
&textures.colorMap);
} }
void setupVertexDescriptions() void setupVertexDescriptions()
@ -270,20 +293,15 @@ public:
vkTools::initializers::vertexInputAttributeDescription( vkTools::initializers::vertexInputAttributeDescription(
INSTANCE_BUFFER_BIND_ID, 5, VK_FORMAT_R32G32B32_SFLOAT, offsetof(InstanceData, rot)) INSTANCE_BUFFER_BIND_ID, 5, VK_FORMAT_R32G32B32_SFLOAT, offsetof(InstanceData, rot))
); );
// Location 6: Color
vertices.attributeDescriptions.push_back(
vkTools::initializers::vertexInputAttributeDescription(
INSTANCE_BUFFER_BIND_ID, 6, VK_FORMAT_R32G32B32_SFLOAT, offsetof(InstanceData, color))
);
// Location 6: Scale // Location 6: Scale
vertices.attributeDescriptions.push_back( vertices.attributeDescriptions.push_back(
vkTools::initializers::vertexInputAttributeDescription( vkTools::initializers::vertexInputAttributeDescription(
INSTANCE_BUFFER_BIND_ID, 7, VK_FORMAT_R32_SFLOAT, offsetof(InstanceData, scale)) INSTANCE_BUFFER_BIND_ID, 6, VK_FORMAT_R32_SFLOAT, offsetof(InstanceData, scale))
); );
// Location 7: Texture array layer index // Location 7: Texture array layer index
vertices.attributeDescriptions.push_back( vertices.attributeDescriptions.push_back(
vkTools::initializers::vertexInputAttributeDescription( vkTools::initializers::vertexInputAttributeDescription(
INSTANCE_BUFFER_BIND_ID, 8, VK_FORMAT_R32_SINT, offsetof(InstanceData, texIndex)) INSTANCE_BUFFER_BIND_ID, 7, VK_FORMAT_R32_SINT, offsetof(InstanceData, texIndex))
); );
vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo(); vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo();
@ -299,7 +317,7 @@ public:
std::vector<VkDescriptorPoolSize> poolSizes = std::vector<VkDescriptorPoolSize> poolSizes =
{ {
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1),
vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1), vkTools::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2),
}; };
VkDescriptorPoolCreateInfo descriptorPoolInfo = VkDescriptorPoolCreateInfo descriptorPoolInfo =
@ -315,16 +333,21 @@ public:
{ {
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings =
{ {
// Binding 0 : Vertex shader uniform buffer // Binding 0: Vertex shader uniform buffer
vkTools::initializers::descriptorSetLayoutBinding( vkTools::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_VERTEX_BIT,
0), 0),
// Binding 1 : Fragment shader combined sampler // Binding 1: Fragment shader combined sampler (plants texture array)
vkTools::initializers::descriptorSetLayoutBinding( vkTools::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
1), 1),
// Binding 1: Fragment shader combined sampler (ground texture)
vkTools::initializers::descriptorSetLayoutBinding(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_SHADER_STAGE_FRAGMENT_BIT,
2),
}; };
VkDescriptorSetLayoutCreateInfo descriptorLayout = VkDescriptorSetLayoutCreateInfo descriptorLayout =
@ -352,26 +375,26 @@ public:
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
VkDescriptorImageInfo texDescriptor =
vkTools::initializers::descriptorImageInfo(
textures.colorMap.sampler,
textures.colorMap.view,
VK_IMAGE_LAYOUT_GENERAL);
std::vector<VkWriteDescriptorSet> writeDescriptorSets = std::vector<VkWriteDescriptorSet> writeDescriptorSets =
{ {
// Binding 0 : Vertex shader uniform buffer // Binding 0: Vertex shader uniform buffer
vkTools::initializers::writeDescriptorSet( vkTools::initializers::writeDescriptorSet(
descriptorSet, descriptorSet,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0, 0,
&uniformData.scene.descriptor), &uniformData.scene.descriptor),
// Binding 1 : Color map // Binding 1: Plants texture array combined
vkTools::initializers::writeDescriptorSet( vkTools::initializers::writeDescriptorSet(
descriptorSet, descriptorSet,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1, 1,
&texDescriptor) &textures.colorMap.descriptor),
// Binding 2: Ground texture combined
vkTools::initializers::writeDescriptorSet(
descriptorSet,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
2,
&textures.ground.descriptor)
}; };
vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL);
@ -388,7 +411,7 @@ public:
VkPipelineRasterizationStateCreateInfo rasterizationState = VkPipelineRasterizationStateCreateInfo rasterizationState =
vkTools::initializers::pipelineRasterizationStateCreateInfo( vkTools::initializers::pipelineRasterizationStateCreateInfo(
VK_POLYGON_MODE_FILL, VK_POLYGON_MODE_FILL,
VK_CULL_MODE_BACK_BIT, VK_CULL_MODE_NONE,
VK_FRONT_FACE_CLOCKWISE, VK_FRONT_FACE_CLOCKWISE,
0); 0);
@ -426,19 +449,14 @@ public:
dynamicStateEnables.size(), dynamicStateEnables.size(),
0); 0);
// Instacing pipeline
// Load shaders
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
shaderStages[0] = loadShader(getAssetPath() + "shaders/indirectdraw/indirectdraw.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getAssetPath() + "shaders/indirectdraw/indirectdraw.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
VkGraphicsPipelineCreateInfo pipelineCreateInfo = VkGraphicsPipelineCreateInfo pipelineCreateInfo =
vkTools::initializers::pipelineCreateInfo( vkTools::initializers::pipelineCreateInfo(
pipelineLayout, pipelineLayout,
renderPass, renderPass,
0); 0);
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
pipelineCreateInfo.pVertexInputState = &vertices.inputState; pipelineCreateInfo.pVertexInputState = &vertices.inputState;
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
pipelineCreateInfo.pRasterizationState = &rasterizationState; pipelineCreateInfo.pRasterizationState = &rasterizationState;
@ -450,29 +468,43 @@ public:
pipelineCreateInfo.stageCount = shaderStages.size(); pipelineCreateInfo.stageCount = shaderStages.size();
pipelineCreateInfo.pStages = shaderStages.data(); pipelineCreateInfo.pStages = shaderStages.data();
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.solid)); // Indirect (and instanced) pipeline for the plants
shaderStages[0] = loadShader(getAssetPath() + "shaders/indirectdraw/indirectdraw.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getAssetPath() + "shaders/indirectdraw/indirectdraw.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.plants));
// Ground
shaderStages[0] = loadShader(getAssetPath() + "shaders/indirectdraw/ground.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getAssetPath() + "shaders/indirectdraw/ground.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
rasterizationState.cullMode = VK_CULL_MODE_BACK_BIT;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.ground));
// Skysphere
shaderStages[0] = loadShader(getAssetPath() + "shaders/indirectdraw/skysphere.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getAssetPath() + "shaders/indirectdraw/skysphere.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
rasterizationState.cullMode = VK_CULL_MODE_FRONT_BIT;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.skysphere));
} }
// Prepare (and stage) a buffer containing the indirect draw commands // Prepare (and stage) a buffer containing the indirect draw commands
void prepareIndirectData() void prepareIndirectData()
{ {
VkDrawIndexedIndirectCommand dic{}; indirectCommands.clear();
dic.firstInstance = 0;
dic.instanceCount = OBJECT_INSTANCE_COUNT;
dic.firstIndex = 0; // Create on indirect command for each mesh in the scene
dic.indexCount = 36; uint32_t m = 0;
indirectCommands.push_back(dic); for (auto& meshDescriptor : meshes.plants.meshDescriptors)
{
VkDrawIndexedIndirectCommand indirectCmd{};
indirectCmd.instanceCount = OBJECT_INSTANCE_COUNT;
indirectCmd.firstInstance = m * OBJECT_INSTANCE_COUNT;
indirectCmd.firstIndex = meshDescriptor.indexBase;
indirectCmd.indexCount = meshDescriptor.indexCount;
dic.firstInstance += OBJECT_INSTANCE_COUNT; indirectCommands.push_back(indirectCmd);
dic.firstIndex = 36;
dic.indexCount = 2880;
indirectCommands.push_back(dic);
dic.firstInstance += OBJECT_INSTANCE_COUNT; m++;
dic.firstIndex = 2916; }
dic.indexCount = 186;
indirectCommands.push_back(dic);
indirectDrawCount = static_cast<uint32_t>(indirectCommands.size()); indirectDrawCount = static_cast<uint32_t>(indirectCommands.size());
@ -496,19 +528,7 @@ public:
&indirectCommandsBuffer, &indirectCommandsBuffer,
stagingBuffer.size)); stagingBuffer.size));
// Copy to staging buffer vulkanDevice->copyBuffer(&stagingBuffer, &indirectCommandsBuffer, queue);
VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
VkBufferCopy copyRegion = {};
copyRegion.size = indirectCommandsBuffer.size;
vkCmdCopyBuffer(
copyCmd,
stagingBuffer.buffer,
indirectCommandsBuffer.buffer,
1,
&copyRegion);
VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
stagingBuffer.destroy(); stagingBuffer.destroy();
} }
@ -529,14 +549,12 @@ public:
for (auto i = 0; i < objectCount; i++) for (auto i = 0; i < objectCount; i++)
{ {
instanceData[i].rot = glm::vec3(M_PI * uniformDist(rndGenerator), M_PI * uniformDist(rndGenerator), M_PI * uniformDist(rndGenerator)); instanceData[i].rot = glm::vec3(0.0f, M_PI * uniformDist(rndGenerator), 0.0f);
float theta = 2 * M_PI * uniformDist(rndGenerator); float theta = 2 * M_PI * uniformDist(rndGenerator);
float phi = acos(1 - 2 * uniformDist(rndGenerator)); float phi = acos(1 - 2 * uniformDist(rndGenerator));
glm::vec3 pos; instanceData[i].pos = glm::vec3(sin(phi) * cos(theta), 0.0f, cos(phi)) * PLANT_RADIUS;
instanceData[i].pos = glm::vec3(sin(phi) * cos(theta), sin(theta) * uniformDist(rndGenerator) / 1500.0f, cos(phi)) * 7.5f;
instanceData[i].color = glm::vec3(rnd(1.0f), rnd(1.0f), rnd(1.0f));
instanceData[i].scale = 1.0f + uniformDist(rndGenerator) * 2.0f; instanceData[i].scale = 1.0f + uniformDist(rndGenerator) * 2.0f;
instanceData[i].texIndex = rnd(textures.colorMap.layerCount); instanceData[i].texIndex = i / OBJECT_INSTANCE_COUNT;
} }
vk::Buffer stagingBuffer; vk::Buffer stagingBuffer;
@ -553,19 +571,7 @@ public:
&instanceBuffer, &instanceBuffer,
stagingBuffer.size)); stagingBuffer.size));
// Copy to staging buffer vulkanDevice->copyBuffer(&stagingBuffer, &instanceBuffer, queue);
VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
VkBufferCopy copyRegion = { };
copyRegion.size = instanceBuffer.size;
vkCmdCopyBuffer(
copyCmd,
stagingBuffer.buffer,
instanceBuffer.buffer,
1,
&copyRegion);
VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
stagingBuffer.destroy(); stagingBuffer.destroy();
} }
@ -587,16 +593,8 @@ public:
{ {
if (viewChanged) if (viewChanged)
{ {
uboVS.projection = glm::perspective(glm::radians(60.0f), (float)width / (float)height, 0.001f, 256.0f); uboVS.projection = camera.matrices.perspective;
uboVS.view = glm::translate(glm::mat4(), cameraPos + glm::vec3(0.0f, 0.0f, zoom)); uboVS.view = camera.matrices.view;
uboVS.view = glm::rotate(uboVS.view, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
uboVS.view = glm::rotate(uboVS.view, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
uboVS.view = glm::rotate(uboVS.view, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
}
if (!paused)
{
uboVS.time += frameTimer * 0.05f;
} }
memcpy(uniformData.scene.mapped, &uboVS, sizeof(uboVS)); memcpy(uniformData.scene.mapped, &uboVS, sizeof(uboVS));
@ -619,8 +617,7 @@ public:
void prepare() void prepare()
{ {
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
loadTextures(); loadAssets();
loadMeshes();
prepareIndirectData(); prepareIndirectData();
prepareInstanceData(); prepareInstanceData();
setupVertexDescriptions(); setupVertexDescriptions();
@ -640,10 +637,6 @@ public:
return; return;
} }
draw(); draw();
if (!paused)
{
updateUniformBuffer(false);
}
} }
virtual void viewChanged() virtual void viewChanged()
@ -653,67 +646,8 @@ public:
virtual void getOverlayText(VulkanTextOverlay *textOverlay) virtual void getOverlayText(VulkanTextOverlay *textOverlay)
{ {
textOverlay->addText("Rendering " + std::to_string(objectCount) + " objects", 5.0f, 85.0f, VulkanTextOverlay::alignLeft); textOverlay->addText(std::to_string(objectCount) + " objects", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
} }
}; };
VulkanExample *vulkanExample; VULKAN_EXAMPLE_MAIN()
#if defined(_WIN32)
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (vulkanExample != NULL)
{
vulkanExample->handleMessages(hWnd, uMsg, wParam, lParam);
}
return (DefWindowProc(hWnd, uMsg, wParam, lParam));
}
#elif defined(__linux__) && !defined(__ANDROID__)
static void handleEvent(const xcb_generic_event_t *event)
{
if (vulkanExample != NULL)
{
vulkanExample->handleEvent(event);
}
}
#endif
// Main entry point
#if defined(_WIN32)
// Windows entry point
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)
#elif defined(__ANDROID__)
// Android entry point
void android_main(android_app* state)
#elif defined(__linux__)
// Linux entry point
int main(const int argc, const char *argv[])
#endif
{
#if defined(__ANDROID__)
// Removing this may cause the compiler to omit the main entry point
// which would make the application crash at start
app_dummy();
#endif
vulkanExample = new VulkanExample();
#if defined(_WIN32)
vulkanExample->setupWindow(hInstance, WndProc);
#elif defined(__ANDROID__)
// Attach vulkan example to global android application state
state->userData = vulkanExample;
state->onAppCmd = VulkanExample::handleAppCommand;
state->onInputEvent = VulkanExample::handleAppInput;
vulkanExample->androidApp = state;
#elif defined(__linux__)
vulkanExample->setupWindow();
#endif
#if !defined(__ANDROID__)
vulkanExample->initSwapchain();
vulkanExample->prepare();
#endif
vulkanExample->renderLoop();
delete(vulkanExample);
#if !defined(__ANDROID__)
return 0;
#endif
}

View file

@ -22,8 +22,12 @@
<ClInclude Include="..\base\vulkantools.h" /> <ClInclude Include="..\base\vulkantools.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\data\shaders\indirectdraw\ground.frag" />
<None Include="..\data\shaders\indirectdraw\ground.vert" />
<None Include="..\data\shaders\indirectdraw\indirectdraw.frag" /> <None Include="..\data\shaders\indirectdraw\indirectdraw.frag" />
<None Include="..\data\shaders\indirectdraw\indirectdraw.vert" /> <None Include="..\data\shaders\indirectdraw\indirectdraw.vert" />
<None Include="..\data\shaders\indirectdraw\skysphere.frag" />
<None Include="..\data\shaders\indirectdraw\skysphere.vert" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{2BBDD10F-2C9D-4BEA-8C7B-1C510A2CE08B}</ProjectGuid> <ProjectGuid>{2BBDD10F-2C9D-4BEA-8C7B-1C510A2CE08B}</ProjectGuid>

View file

@ -49,5 +49,17 @@
<None Include="..\data\shaders\indirectdraw\indirectdraw.vert"> <None Include="..\data\shaders\indirectdraw\indirectdraw.vert">
<Filter>Shaders</Filter> <Filter>Shaders</Filter>
</None> </None>
<None Include="..\data\shaders\indirectdraw\ground.frag">
<Filter>Shaders</Filter>
</None>
<None Include="..\data\shaders\indirectdraw\ground.vert">
<Filter>Shaders</Filter>
</None>
<None Include="..\data\shaders\indirectdraw\skysphere.frag">
<Filter>Shaders</Filter>
</None>
<None Include="..\data\shaders\indirectdraw\skysphere.vert">
<Filter>Shaders</Filter>
</None>
</ItemGroup> </ItemGroup>
</Project> </Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 KiB