Updated (multi) indirect draw example
This commit is contained in:
parent
be68bc0a5a
commit
444c4b9c24
23 changed files with 1565 additions and 214 deletions
|
|
@ -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.
|
||||
<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/)
|
||||
<img src="./screenshots/multisampling.png" height="96px" align="right">
|
||||
|
||||
|
|
|
|||
170
data/models/plane_circle.dae
Normal file
170
data/models/plane_circle.dae
Normal 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
1015
data/models/plants.dae
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,2 +0,0 @@
|
|||
glslangvalidator -V indirectdraw.vert -o indirectdraw.vert.spv
|
||||
glslangvalidator -V indirectdraw.frag -o indirectdraw.frag.spv
|
||||
28
data/shaders/indirectdraw/ground.frag
Normal file
28
data/shaders/indirectdraw/ground.frag
Normal 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);
|
||||
}
|
||||
BIN
data/shaders/indirectdraw/ground.frag.spv
Normal file
BIN
data/shaders/indirectdraw/ground.frag.spv
Normal file
Binary file not shown.
42
data/shaders/indirectdraw/ground.vert
Normal file
42
data/shaders/indirectdraw/ground.vert
Normal 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;
|
||||
}
|
||||
BIN
data/shaders/indirectdraw/ground.vert.spv
Normal file
BIN
data/shaders/indirectdraw/ground.vert.spv
Normal file
Binary file not shown.
|
|
@ -7,28 +7,24 @@ layout (binding = 1) uniform sampler2DArray samplerArray;
|
|||
|
||||
layout (location = 0) in vec3 inNormal;
|
||||
layout (location = 1) in vec3 inColor;
|
||||
layout (location = 2) in vec3 inEyePos;
|
||||
layout (location = 3) in vec3 inLightVec;
|
||||
layout (location = 4) in vec3 inUV;
|
||||
layout (location = 2) in vec3 inUV;
|
||||
layout (location = 3) in vec3 inViewVec;
|
||||
layout (location = 4) in vec3 inLightVec;
|
||||
|
||||
layout (location = 0) out vec4 outFragColor;
|
||||
|
||||
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 L = normalize(vec3(1.0));
|
||||
|
||||
vec3 Eye = normalize(-inEyePos);
|
||||
vec3 Reflected = normalize(reflect(-inLightVec, inNormal));
|
||||
|
||||
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);
|
||||
|
||||
vec3 L = normalize(inLightVec);
|
||||
vec3 ambient = vec3(0.65);
|
||||
vec3 diffuse = max(dot(N, L), 0.0) * inColor;
|
||||
outFragColor = vec4((ambient + diffuse) * color.rgb, 1.0);
|
||||
}
|
||||
Binary file not shown.
|
|
@ -12,22 +12,20 @@ layout (location = 3) in vec3 inColor;
|
|||
// Instanced attributes
|
||||
layout (location = 4) in vec3 instancePos;
|
||||
layout (location = 5) in vec3 instanceRot;
|
||||
layout (location = 6) in vec3 instanceColor;
|
||||
layout (location = 7) in float instanceScale;
|
||||
layout (location = 8) in int instanceTexIndex;
|
||||
layout (location = 6) in float instanceScale;
|
||||
layout (location = 7) in int instanceTexIndex;
|
||||
|
||||
layout (binding = 0) uniform UBO
|
||||
{
|
||||
mat4 projection;
|
||||
mat4 view;
|
||||
float time;
|
||||
mat4 modelview;
|
||||
} ubo;
|
||||
|
||||
layout (location = 0) out vec3 outNormal;
|
||||
layout (location = 1) out vec3 outColor;
|
||||
layout (location = 2) out vec3 outEyePos;
|
||||
layout (location = 3) out vec3 outLightVec;
|
||||
layout (location = 4) out vec3 outUV;
|
||||
layout (location = 2) out vec3 outUV;
|
||||
layout (location = 3) out vec3 outViewVec;
|
||||
layout (location = 4) out vec3 outLightVec;
|
||||
|
||||
out gl_PerVertex
|
||||
{
|
||||
|
|
@ -36,8 +34,9 @@ out gl_PerVertex
|
|||
|
||||
void main()
|
||||
{
|
||||
outColor = instanceColor;
|
||||
outColor = inColor;
|
||||
outUV = vec3(inUV, instanceTexIndex);
|
||||
outUV.t = 1.0 - outUV.t;
|
||||
|
||||
mat4 mx, my, mz;
|
||||
|
||||
|
|
@ -51,8 +50,8 @@ void main()
|
|||
mx[3] = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
// rotate around y
|
||||
s = sin(instanceRot.y + ubo.time);
|
||||
c = cos(instanceRot.y + ubo.time);
|
||||
s = sin(instanceRot.y);
|
||||
c = cos(instanceRot.y);
|
||||
|
||||
my[0] = vec4(c, 0.0, s, 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;
|
||||
|
||||
outEyePos = vec3(ubo.view * pos);
|
||||
gl_Position = ubo.projection * ubo.modelview * pos;
|
||||
|
||||
gl_Position = ubo.projection * ubo.view * pos;
|
||||
|
||||
vec4 lightPos = vec4(0.0, 0.0, 0.0, 1.0) * ubo.view;
|
||||
outLightVec = normalize(lightPos.xyz - outEyePos);
|
||||
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.
17
data/shaders/indirectdraw/skysphere.frag
Normal file
17
data/shaders/indirectdraw/skysphere.frag
Normal 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);
|
||||
}
|
||||
BIN
data/shaders/indirectdraw/skysphere.frag.spv
Normal file
BIN
data/shaders/indirectdraw/skysphere.frag.spv
Normal file
Binary file not shown.
28
data/shaders/indirectdraw/skysphere.vert
Normal file
28
data/shaders/indirectdraw/skysphere.vert
Normal 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);
|
||||
}
|
||||
BIN
data/shaders/indirectdraw/skysphere.vert.spv
Normal file
BIN
data/shaders/indirectdraw/skysphere.vert.spv
Normal file
Binary file not shown.
BIN
data/textures/ground_dry_bc3.ktx
Normal file
BIN
data/textures/ground_dry_bc3.ktx
Normal file
Binary file not shown.
BIN
data/textures/texturearray_plants_bc3.ktx
Normal file
BIN
data/textures/texturearray_plants_bc3.ktx
Normal file
Binary file not shown.
101
indirectdraw/README.md
Normal file
101
indirectdraw/README.md
Normal 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/)
|
||||
|
|
@ -6,13 +6,16 @@
|
|||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
#define OBJECT_INSTANCE_COUNT 2048
|
||||
// Circular range of plant distribution
|
||||
#define PLANT_RADIUS 25.0f
|
||||
|
||||
// Vertex layout for this example
|
||||
std::vector<vkMeshLoader::VertexLayout> vertexLayout =
|
||||
|
|
@ -59,18 +64,20 @@ public:
|
|||
} vertices;
|
||||
|
||||
struct {
|
||||
vkMeshLoader::MeshBuffer example;
|
||||
vkMeshLoader::MeshBuffer plants;
|
||||
vkMeshLoader::MeshBuffer ground;
|
||||
vkMeshLoader::MeshBuffer skysphere;
|
||||
} meshes;
|
||||
|
||||
struct {
|
||||
vkTools::VulkanTexture colorMap;
|
||||
vkTools::VulkanTexture ground;
|
||||
} textures;
|
||||
|
||||
// Per-instance data block
|
||||
struct InstanceData {
|
||||
glm::vec3 pos;
|
||||
glm::vec3 rot;
|
||||
glm::vec3 color;
|
||||
float scale;
|
||||
uint32_t texIndex;
|
||||
};
|
||||
|
|
@ -84,7 +91,6 @@ public:
|
|||
struct {
|
||||
glm::mat4 projection;
|
||||
glm::mat4 view;
|
||||
float time = 0.0f;
|
||||
} uboVS;
|
||||
|
||||
struct {
|
||||
|
|
@ -92,13 +98,17 @@ public:
|
|||
} uniformData;
|
||||
|
||||
struct {
|
||||
VkPipeline solid;
|
||||
VkPipeline plants;
|
||||
VkPipeline ground;
|
||||
VkPipeline skysphere;
|
||||
} pipelines;
|
||||
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkDescriptorSet descriptorSet;
|
||||
VkDescriptorSetLayout descriptorSetLayout;
|
||||
|
||||
VkSampler samplerRepeat;
|
||||
|
||||
uint32_t objectCount = 0;
|
||||
|
||||
// Store the indirect draw commands containing index offsets and instance count per object
|
||||
|
|
@ -106,19 +116,23 @@ public:
|
|||
|
||||
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
||||
{
|
||||
zoom = -12.0f;
|
||||
rotationSpeed = 0.25f;
|
||||
enableTextOverlay = true;
|
||||
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));
|
||||
}
|
||||
|
||||
~VulkanExample()
|
||||
{
|
||||
vkDestroyPipeline(device, pipelines.solid, nullptr);
|
||||
vkDestroyPipeline(device, pipelines.plants, nullptr);
|
||||
vkDestroyPipeline(device, pipelines.ground, nullptr);
|
||||
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
||||
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
||||
vkMeshLoader::freeMeshBufferResources(device, &meshes.example);
|
||||
vkMeshLoader::freeMeshBufferResources(device, &meshes.plants);
|
||||
textureLoader->destroyTexture(textures.colorMap);
|
||||
instanceBuffer.destroy();
|
||||
indirectCommandsBuffer.destroy();
|
||||
|
|
@ -140,7 +154,7 @@ public:
|
|||
VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo();
|
||||
|
||||
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 };
|
||||
|
||||
VkRenderPassBeginInfo renderPassBeginInfo = vkTools::initializers::renderPassBeginInfo();
|
||||
|
|
@ -165,38 +179,47 @@ public:
|
|||
VkRect2D scissor = vkTools::initializers::rect2D(width, height, 0, 0);
|
||||
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 };
|
||||
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
|
||||
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
|
||||
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
|
||||
// Index offsets and instance count are taken from the indirect buffer
|
||||
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]);
|
||||
|
||||
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_rocks_bc3.ktx",
|
||||
VK_FORMAT_BC3_UNORM_BLOCK,
|
||||
&textures.colorMap);
|
||||
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);
|
||||
}
|
||||
|
||||
void setupVertexDescriptions()
|
||||
|
|
@ -270,20 +293,15 @@ public:
|
|||
vkTools::initializers::vertexInputAttributeDescription(
|
||||
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
|
||||
vertices.attributeDescriptions.push_back(
|
||||
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
|
||||
vertices.attributeDescriptions.push_back(
|
||||
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();
|
||||
|
|
@ -299,7 +317,7 @@ public:
|
|||
std::vector<VkDescriptorPoolSize> poolSizes =
|
||||
{
|
||||
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 =
|
||||
|
|
@ -320,11 +338,16 @@ public:
|
|||
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
VK_SHADER_STAGE_VERTEX_BIT,
|
||||
0),
|
||||
// Binding 1 : Fragment shader combined sampler
|
||||
// Binding 1: Fragment shader combined sampler (plants texture array)
|
||||
vkTools::initializers::descriptorSetLayoutBinding(
|
||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
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 =
|
||||
|
|
@ -352,12 +375,6 @@ public:
|
|||
|
||||
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 =
|
||||
{
|
||||
// Binding 0: Vertex shader uniform buffer
|
||||
|
|
@ -366,12 +383,18 @@ public:
|
|||
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
0,
|
||||
&uniformData.scene.descriptor),
|
||||
// Binding 1 : Color map
|
||||
// Binding 1: Plants texture array combined
|
||||
vkTools::initializers::writeDescriptorSet(
|
||||
descriptorSet,
|
||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
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);
|
||||
|
|
@ -388,7 +411,7 @@ public:
|
|||
VkPipelineRasterizationStateCreateInfo rasterizationState =
|
||||
vkTools::initializers::pipelineRasterizationStateCreateInfo(
|
||||
VK_POLYGON_MODE_FILL,
|
||||
VK_CULL_MODE_BACK_BIT,
|
||||
VK_CULL_MODE_NONE,
|
||||
VK_FRONT_FACE_CLOCKWISE,
|
||||
0);
|
||||
|
||||
|
|
@ -426,19 +449,14 @@ public:
|
|||
dynamicStateEnables.size(),
|
||||
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 =
|
||||
vkTools::initializers::pipelineCreateInfo(
|
||||
pipelineLayout,
|
||||
renderPass,
|
||||
0);
|
||||
|
||||
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
|
||||
|
||||
pipelineCreateInfo.pVertexInputState = &vertices.inputState;
|
||||
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
|
||||
pipelineCreateInfo.pRasterizationState = &rasterizationState;
|
||||
|
|
@ -450,29 +468,43 @@ public:
|
|||
pipelineCreateInfo.stageCount = shaderStages.size();
|
||||
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
|
||||
void prepareIndirectData()
|
||||
{
|
||||
VkDrawIndexedIndirectCommand dic{};
|
||||
dic.firstInstance = 0;
|
||||
dic.instanceCount = OBJECT_INSTANCE_COUNT;
|
||||
indirectCommands.clear();
|
||||
|
||||
dic.firstIndex = 0;
|
||||
dic.indexCount = 36;
|
||||
indirectCommands.push_back(dic);
|
||||
// Create on indirect command for each mesh in the scene
|
||||
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;
|
||||
|
||||
dic.firstInstance += OBJECT_INSTANCE_COUNT;
|
||||
dic.firstIndex = 36;
|
||||
dic.indexCount = 2880;
|
||||
indirectCommands.push_back(dic);
|
||||
indirectCommands.push_back(indirectCmd);
|
||||
|
||||
dic.firstInstance += OBJECT_INSTANCE_COUNT;
|
||||
dic.firstIndex = 2916;
|
||||
dic.indexCount = 186;
|
||||
indirectCommands.push_back(dic);
|
||||
m++;
|
||||
}
|
||||
|
||||
indirectDrawCount = static_cast<uint32_t>(indirectCommands.size());
|
||||
|
||||
|
|
@ -496,19 +528,7 @@ public:
|
|||
&indirectCommandsBuffer,
|
||||
stagingBuffer.size));
|
||||
|
||||
// Copy to staging buffer
|
||||
VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||
|
||||
VkBufferCopy copyRegion = {};
|
||||
copyRegion.size = indirectCommandsBuffer.size;
|
||||
vkCmdCopyBuffer(
|
||||
copyCmd,
|
||||
stagingBuffer.buffer,
|
||||
indirectCommandsBuffer.buffer,
|
||||
1,
|
||||
©Region);
|
||||
|
||||
VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
|
||||
vulkanDevice->copyBuffer(&stagingBuffer, &indirectCommandsBuffer, queue);
|
||||
|
||||
stagingBuffer.destroy();
|
||||
}
|
||||
|
|
@ -529,14 +549,12 @@ public:
|
|||
|
||||
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 phi = acos(1 - 2 * uniformDist(rndGenerator));
|
||||
glm::vec3 pos;
|
||||
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].pos = glm::vec3(sin(phi) * cos(theta), 0.0f, cos(phi)) * PLANT_RADIUS;
|
||||
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;
|
||||
|
|
@ -553,19 +571,7 @@ public:
|
|||
&instanceBuffer,
|
||||
stagingBuffer.size));
|
||||
|
||||
// Copy to staging buffer
|
||||
VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||
|
||||
VkBufferCopy copyRegion = { };
|
||||
copyRegion.size = instanceBuffer.size;
|
||||
vkCmdCopyBuffer(
|
||||
copyCmd,
|
||||
stagingBuffer.buffer,
|
||||
instanceBuffer.buffer,
|
||||
1,
|
||||
©Region);
|
||||
|
||||
VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
|
||||
vulkanDevice->copyBuffer(&stagingBuffer, &instanceBuffer, queue);
|
||||
|
||||
stagingBuffer.destroy();
|
||||
}
|
||||
|
|
@ -587,16 +593,8 @@ public:
|
|||
{
|
||||
if (viewChanged)
|
||||
{
|
||||
uboVS.projection = glm::perspective(glm::radians(60.0f), (float)width / (float)height, 0.001f, 256.0f);
|
||||
uboVS.view = glm::translate(glm::mat4(), cameraPos + glm::vec3(0.0f, 0.0f, zoom));
|
||||
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;
|
||||
uboVS.projection = camera.matrices.perspective;
|
||||
uboVS.view = camera.matrices.view;
|
||||
}
|
||||
|
||||
memcpy(uniformData.scene.mapped, &uboVS, sizeof(uboVS));
|
||||
|
|
@ -619,8 +617,7 @@ public:
|
|||
void prepare()
|
||||
{
|
||||
VulkanExampleBase::prepare();
|
||||
loadTextures();
|
||||
loadMeshes();
|
||||
loadAssets();
|
||||
prepareIndirectData();
|
||||
prepareInstanceData();
|
||||
setupVertexDescriptions();
|
||||
|
|
@ -640,10 +637,6 @@ public:
|
|||
return;
|
||||
}
|
||||
draw();
|
||||
if (!paused)
|
||||
{
|
||||
updateUniformBuffer(false);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void viewChanged()
|
||||
|
|
@ -653,67 +646,8 @@ public:
|
|||
|
||||
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;
|
||||
|
||||
#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
|
||||
}
|
||||
VULKAN_EXAMPLE_MAIN()
|
||||
|
|
@ -22,8 +22,12 @@
|
|||
<ClInclude Include="..\base\vulkantools.h" />
|
||||
</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.vert" />
|
||||
<None Include="..\data\shaders\indirectdraw\skysphere.frag" />
|
||||
<None Include="..\data\shaders\indirectdraw\skysphere.vert" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{2BBDD10F-2C9D-4BEA-8C7B-1C510A2CE08B}</ProjectGuid>
|
||||
|
|
|
|||
|
|
@ -49,5 +49,17 @@
|
|||
<None Include="..\data\shaders\indirectdraw\indirectdraw.vert">
|
||||
<Filter>Shaders</Filter>
|
||||
</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>
|
||||
</Project>
|
||||
BIN
screenshots/indirectdraw.jpg
Normal file
BIN
screenshots/indirectdraw.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 464 KiB |
Loading…
Add table
Add a link
Reference in a new issue