diff --git a/example/Vulkan/Atomsphere.cpp b/example/Vulkan/Atomsphere.cpp new file mode 100644 index 00000000..78033300 --- /dev/null +++ b/example/Vulkan/Atomsphere.cpp @@ -0,0 +1,160 @@ +// 8.大气渲染 +// 画一个球,纯粹使用shader计算出颜色 + +#include"VulkanAppFramework.h" +#include +#include +#include +#include +#include + +using namespace hgl; +using namespace hgl::graph; + +constexpr uint32_t SCREEN_WIDTH=128; +constexpr uint32_t SCREEN_HEIGHT=128; + +struct AtomsphereData +{ + alignas(16) Vector3f position; + float intensity; + float scattering_direction; +};// + +class TestApp:public CameraAppFramework +{ +private: + + SceneNode render_root; + RenderList render_list; + + vulkan::Material * material =nullptr; + vulkan::DescriptorSets * descriptor_sets =nullptr; + + vulkan::Renderable *ro_sphere; + + vulkan::Pipeline *pipeline_solid =nullptr; + + vulkan::Buffer * ubo_atomsphere =nullptr; + AtomsphereData atomsphere_data; + +private: + + bool InitMaterial() + { + material=shader_manage->CreateMaterial(OS_TEXT("Atomsphere.vert.spv"), + OS_TEXT("Atomsphere.frag.spv")); + if(!material) + return(false); + + descriptor_sets=material->CreateDescriptorSets(); + + db->Add(material); + db->Add(descriptor_sets); + return(true); + } + + void CreateRenderObject() + { + ro_sphere=CreateRenderableSphere(db,material,16); + } + + bool InitAtomsphereUBO(vulkan::DescriptorSets *desc_set,uint bindpoint) + { + atomsphere_data.position.Set(0,0.1f,-1.0f); + atomsphere_data.intensity=22.0f; + atomsphere_data.scattering_direction=0.758f; + + ubo_atomsphere=db->CreateUBO(sizeof(AtomsphereData),&atomsphere_data); + + if(!ubo_atomsphere) + return(false); + + return desc_set->BindUBO(bindpoint,*ubo_atomsphere); + } + + bool InitUBO() + { + if(!InitCameraUBO(descriptor_sets,material->GetUBO("world"))) + return(false); + + if(!InitAtomsphereUBO(descriptor_sets,material->GetUBO("sun"))) + return(false); + + descriptor_sets->Update(); + return(true); + } + + bool InitPipeline() + { + vulkan::PipelineCreater *pipeline_creater=new vulkan::PipelineCreater(device,material,device->GetRenderPass(),device->GetExtent()); + pipeline_creater->SetDepthTest(true); + pipeline_creater->SetDepthWrite(true); + pipeline_creater->SetCullMode(VK_CULL_MODE_NONE); + pipeline_creater->Set(PRIM_TRIANGLES); + pipeline_solid=pipeline_creater->Create(); + + if(!pipeline_solid) + return(false); + + db->Add(pipeline_solid); + + delete pipeline_creater; + return(true); + } + + bool InitScene() + { + render_root.Add(db->CreateRenderableInstance(pipeline_solid,descriptor_sets,ro_sphere),scale(1000)); + + render_root.RefreshMatrix(); + render_root.ExpendToList(&render_list); + + return(true); + } + +public: + + bool Init() + { + if(!CameraAppFramework::Init(SCREEN_WIDTH,SCREEN_HEIGHT)) + return(false); + + if(!InitMaterial()) + return(false); + + CreateRenderObject(); + + if(!InitUBO()) + return(false); + + if(!InitPipeline()) + return(false); + + if(!InitScene()) + return(false); + + return(true); + } + + void BuildCommandBuffer(uint32_t index) override + { + render_root.RefreshMatrix(); + render_list.Clear(); + render_root.ExpendToList(&render_list); + + VulkanApplicationFramework::BuildCommandBuffer(index,&render_list); + } +};//class TestApp:public CameraAppFramework + +int main(int,char **) +{ + TestApp app; + + if(!app.Init()) + return(-1); + + while(app.Run()); + + return 0; +} diff --git a/example/Vulkan/CMakeLists.txt b/example/Vulkan/CMakeLists.txt index 92c08904..6888cf05 100644 --- a/example/Vulkan/CMakeLists.txt +++ b/example/Vulkan/CMakeLists.txt @@ -15,4 +15,6 @@ target_link_libraries(6.LoadModel assimp) CreateProject(7.InlineGeometryScene InlineGeometryScene.cpp) -CreateProject(8.RenderToColor RenderToColor.cpp TGATexture.cpp) \ No newline at end of file +CreateProject(8.Atomsphere Atomsphere.cpp) + +CreateProject(9.RenderToColor RenderToColor.cpp TGATexture.cpp) \ No newline at end of file diff --git a/res/shader/Atomsphere.frag b/res/shader/Atomsphere.frag new file mode 100644 index 00000000..23cf1d26 --- /dev/null +++ b/res/shader/Atomsphere.frag @@ -0,0 +1,141 @@ +#version 450 core + +#define PI 3.141592 +#define iSteps 16 +#define jSteps 8 + +layout(location = 0) in vec4 FragmentVertex; + +layout(location = 0) out vec4 FragColor; + +layout(binding = 1) uniform AtomSphere +{ + vec3 position; + float intensity; + float scattering_direction; +}sun; + +vec2 rsi(vec3 r0, vec3 rd, float sr) { + // ray-sphere intersection that assumes + // the sphere is centered at the origin. + // No intersection when result.x > result.y + float a = dot(rd, rd); + float b = 2.0 * dot(rd, r0); + float c = dot(r0, r0) - (sr * sr); + float d = (b*b) - 4.0*a*c; + if (d < 0.0) return vec2(1e5,-1e5); + return vec2( + (-b - sqrt(d))/(2.0*a), + (-b + sqrt(d))/(2.0*a) + ); +} + +vec3 atmosphere(vec3 r, vec3 r0, vec3 pSun, float iSun, float rPlanet, float rAtmos, vec3 kRlh, float kMie, float shRlh, float shMie, float g) +{ + // Normalize the sun and view directions. + pSun = normalize(pSun); + r = normalize(r); + + // Calculate the step size of the primary ray. + vec2 p = rsi(r0, r, rAtmos); + if (p.x > p.y) return vec3(0,0,0); + p.y = min(p.y, rsi(r0, r, rPlanet).x); + float iStepSize = (p.y - p.x) / float(iSteps); + + // Initialize the primary ray time. + float iTime = 0.0; + + // Initialize accumulators for Rayleigh and Mie scattering. + vec3 totalRlh = vec3(0,0,0); + vec3 totalMie = vec3(0,0,0); + + // Initialize optical depth accumulators for the primary ray. + float iOdRlh = 0.0; + float iOdMie = 0.0; + + // Calculate the Rayleigh and Mie phases. + float mu = dot(r, pSun); + float mumu = mu * mu; + float gg = g * g; + float pRlh = 3.0 / (16.0 * PI) * (1.0 + mumu); + float pMie = 3.0 / (8.0 * PI) * ((1.0 - gg) * (mumu + 1.0)) / (pow(1.0 + gg - 2.0 * mu * g, 1.5) * (2.0 + gg)); + + // Sample the primary ray. + for (int i = 0; i < iSteps; i++) { + + // Calculate the primary ray sample position. + vec3 iPos = r0 + r * (iTime + iStepSize * 0.5); + + // Calculate the height of the sample. + float iHeight = length(iPos) - rPlanet; + + // Calculate the optical depth of the Rayleigh and Mie scattering for this step. + float odStepRlh = exp(-iHeight / shRlh) * iStepSize; + float odStepMie = exp(-iHeight / shMie) * iStepSize; + + // Accumulate optical depth. + iOdRlh += odStepRlh; + iOdMie += odStepMie; + + // Calculate the step size of the secondary ray. + float jStepSize = rsi(iPos, pSun, rAtmos).y / float(jSteps); + + // Initialize the secondary ray time. + float jTime = 0.0; + + // Initialize optical depth accumulators for the secondary ray. + float jOdRlh = 0.0; + float jOdMie = 0.0; + + // Sample the secondary ray. + for (int j = 0; j < jSteps; j++) { + + // Calculate the secondary ray sample position. + vec3 jPos = iPos + pSun * (jTime + jStepSize * 0.5); + + // Calculate the height of the sample. + float jHeight = length(jPos) - rPlanet; + + // Accumulate the optical depth. + jOdRlh += exp(-jHeight / shRlh) * jStepSize; + jOdMie += exp(-jHeight / shMie) * jStepSize; + + // Increment the secondary ray time. + jTime += jStepSize; + } + + // Calculate attenuation. + vec3 attn = exp(-(kMie * (iOdMie + jOdMie) + kRlh * (iOdRlh + jOdRlh))); + + // Accumulate scattering. + totalRlh += odStepRlh * attn; + totalMie += odStepMie * attn; + + // Increment the primary ray time. + iTime += iStepSize; + } + + // Calculate and return the final color. + return iSun * (pRlh * kRlh * totalRlh + pMie * kMie * totalMie); +} + +void main() +{ + vec3 nrd=vec3(.x,-FragmentVertex.y,FragmentVertex.z); //vulkan coord to opengl(shader from opengl sample) + + vec3 color=atmosphere( + nrd, // normalized ray direction + vec3(0,6372e3,0), // ray origin + sun.position, // position of the sun + sun.intensity, // intensity of the sun + 6371e3, // radius of the planet in meters + 6471e3, // radius of the atmosphere in meters + vec3(5.5e-6, 13.0e-6, 22.4e-6), // Rayleigh scattering coefficient + 21e-6, // Mie scattering coefficient + 8e3, // Rayleigh scale height + 1.2e3, // Mie scale height + sun.scattering_direction // Mie preferred scattering direction + ); + + FragColor=vec4(1.0-exp(-color),1); +} diff --git a/res/shader/Atomsphere.vert b/res/shader/Atomsphere.vert new file mode 100644 index 00000000..6a310bf2 --- /dev/null +++ b/res/shader/Atomsphere.vert @@ -0,0 +1,24 @@ +#version 450 core + +layout(location = 0) in vec3 Vertex; + +layout(binding = 0) uniform WorldMatrix +{ + mat4 two_dim; + mat4 projection; + mat4 modelview; + mat4 mvp; + mat3 normal; +} world; + +layout(push_constant) uniform Consts { + mat4 local_to_world; +} pc; + +layout(location = 0) out vec4 FragmentVertex; + +void main() +{ + FragmentVertex=vec4(Vertex,1.0)*pc.local_to_world*world.mvp; + gl_Position=FragmentVertex; +} diff --git a/res/shader/shader_compile.sh b/res/shader/shader_compile.sh index a1fe1cb9..6ae4f732 100755 --- a/res/shader/shader_compile.sh +++ b/res/shader/shader_compile.sh @@ -10,4 +10,7 @@ glslangValidator -V -o PositionColor3D.vert.spv PositionColor3D.vert glslangValidator -V -o OnlyPosition3D.vert.spv OnlyPosition3D.vert glslangValidator -V -o c_gbuffer.vert.spv c_gbuffer.vert -glslangValidator -V -o c_gbuffer.frag.spv c_gbuffer.frag \ No newline at end of file +glslangValidator -V -o c_gbuffer.frag.spv c_gbuffer.frag + +glslangValidator -V -o Atomsphere.vert.spv Atomsphere.vert +glslangValidator -V -o Atomsphere.frag.spv Atomsphere.frag