From 5fd45795c12fbcee939ee7b6d07c487420e2a2c2 Mon Sep 17 00:00:00 2001 From: XProger Date: Sun, 20 May 2018 06:36:50 +0300 Subject: [PATCH] D3D reflections and water; hide dummy meshes for fire traps --- src/animation.h | 2 +- src/cache.h | 28 +++-- src/core.h | 3 +- src/format.h | 5 +- src/gapi_d3d9.h | 42 ++++--- src/lara.h | 2 +- src/level.h | 26 +++-- src/platform/win/main.cpp | 2 +- src/shaders/base.hlsl | 20 ++-- src/shaders/common.hlsl | 23 ++-- src/shaders/compile_dx9.bat | 24 ++-- src/shaders/filter.hlsl | 4 +- src/shaders/gui.hlsl | 14 +-- src/shaders/water.glsl | 28 +++-- src/shaders/water.hlsl | 221 +++++++++++++++++++++++++++++++----- 15 files changed, 312 insertions(+), 132 deletions(-) diff --git a/src/animation.h b/src/animation.h index 6c8c82b..85366c3 100644 --- a/src/animation.h +++ b/src/animation.h @@ -120,7 +120,7 @@ struct Animation { // real frame index & lerp delta int fIndex = int(time * 30.0f) / anim->frameRate; int k = fIndex * anim->frameRate; - delta = (time * 30.0f - k) / min((int)anim->frameRate, max(1, framesCount - k)); // min is because in some cases framesCount > realFramesCount / frameRate * frameRate + delta = (time * 30.0f - k) / max(1, min((int)anim->frameRate, framesCount - k)); // min is because in some cases framesCount > realFramesCount / frameRate * frameRate int fIndexA = fIndex % fCount, fIndexB = (fIndex + 1) % fCount; diff --git a/src/cache.h b/src/cache.h index 513e5e5..947816a 100644 --- a/src/cache.h +++ b/src/cache.h @@ -446,8 +446,8 @@ struct WaterCache { int *mf = new int[4 * w * 64 * h * 64]; memset(mf, 0, sizeof(int) * 4 * w * 64 * h * 64); - data[0] = new Texture(w * 64, h * 64, FMT_RGBA_HALF, OPT_TARGET, mf); - data[1] = new Texture(w * 64, h * 64, FMT_RGBA_HALF, OPT_TARGET); + data[0] = new Texture(w * 64, h * 64, FMT_RGBA_HALF, OPT_TARGET | OPT_VERTEX, mf); + data[1] = new Texture(w * 64, h * 64, FMT_RGBA_HALF, OPT_TARGET | OPT_VERTEX); delete[] mf; caustics = Core::settings.detail.water > Core::Settings::MEDIUM ? new Texture(512, 512, FMT_RGBA, OPT_TARGET) : NULL; @@ -594,11 +594,13 @@ struct WaterCache { void drop(Item &item) { if (!dropCount) return; + vec2 s(item.size.x * DETAIL * 2.0f, item.size.z * DETAIL * 2.0f); + game->setShader(Core::passWater, Shader::WATER_DROP); - Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f)); vec4 rPosScale[2] = { vec4(0.0f), vec4(1.0f) }; Core::active.shader->setParam(uPosScale, rPosScale[0], 2); + Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, s.x / item.data[0]->width, s.y / item.data[0]->height)); for (int i = 0; i < dropCount; i++) { Drop &drop = drops[i]; @@ -606,11 +608,12 @@ struct WaterCache { vec3 p; p.x = (drop.pos.x - (item.pos.x - item.size.x)) * DETAIL; p.z = (drop.pos.z - (item.pos.z - item.size.z)) * DETAIL; + Core::active.shader->setParam(uParam, vec4(p.x, p.z, drop.radius * DETAIL, -drop.strength)); item.data[0]->bind(sDiffuse); Core::setTarget(item.data[1], RT_STORE_COLOR); - Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f)); + Core::setViewport(0, 0, int(s.x + 0.5f), int(s.y + 0.5f)); game->getMesh()->renderQuad(); swap(item.data[0], item.data[1]); } @@ -619,20 +622,25 @@ struct WaterCache { void step(Item &item) { if (item.timer < SIMULATE_TIMESTEP) return; + vec2 s(item.size.x * DETAIL * 2.0f, item.size.z * DETAIL * 2.0f); + game->setShader(Core::passWater, Shader::WATER_STEP); - Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f)); Core::active.shader->setParam(uParam, vec4(0.995f, 1.0f, 0, Core::params.x)); + Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, s.x / item.data[0]->width, s.y / item.data[0]->height)); while (item.timer >= SIMULATE_TIMESTEP) { // water step item.data[0]->bind(sDiffuse); Core::setTarget(item.data[1], RT_STORE_COLOR); - Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f)); + Core::setViewport(0, 0, int(s.x + 0.5f), int(s.y + 0.5f)); game->getMesh()->renderQuad(); swap(item.data[0], item.data[1]); item.timer -= SIMULATE_TIMESTEP; } + if (Core::settings.detail.water < Core::Settings::HIGH) + return; + // calc caustics game->setShader(Core::passWater, Shader::WATER_CAUSTICS); vec4 rPosScale[2] = { vec4(0.0f), vec4(32767.0f / PLANE_DETAIL) }; @@ -641,7 +649,7 @@ struct WaterCache { float sx = item.size.x * DETAIL / (item.data[0]->width / 2); float sz = item.size.z * DETAIL / (item.data[0]->height / 2); - Core::active.shader->setParam(uTexParam, vec4(1.0f, 1.0f, sx, sz)); + Core::active.shader->setParam(uTexParam, vec4(0.0f, 0.0f, sx, sz)); Core::whiteTex->bind(sReflect); item.data[0]->bind(sNormal); @@ -711,13 +719,11 @@ struct WaterCache { // get refraction texture if (!refract || w != refract->origWidth || h != refract->origHeight) { delete refract; - refract = new Texture(w, h, FMT_RGBA); - /* + refract = new Texture(w, h, FMT_RGBA, OPT_TARGET); Core::setTarget(refract, RT_CLEAR_COLOR | RT_STORE_COLOR); Core::validateRenderState(); Core::setTarget(NULL, RT_STORE_COLOR); Core::validateRenderState(); - */ } Core::copyTarget(refract, 0, 0, int(Core::viewportDef.x), int(Core::viewportDef.y), w, h); // copy framebuffer into refraction texture } @@ -832,7 +838,7 @@ struct WaterCache { float sx = item.size.x * DETAIL / (item.data[0]->width / 2); float sz = item.size.z * DETAIL / (item.data[0]->height / 2); - Core::active.shader->setParam(uTexParam, vec4(1.0f, 1.0f, sx, sz)); + Core::active.shader->setParam(uTexParam, vec4(0.0f, 0.0f, sx, sz)); refract->bind(sDiffuse); reflect->bind(sReflect); diff --git a/src/core.h b/src/core.h index 91cc811..90888d4 100644 --- a/src/core.h +++ b/src/core.h @@ -350,7 +350,8 @@ enum TexOption { OPT_MIPMAPS = 2, OPT_NEAREST = 4, OPT_TARGET = 8, - OPT_PROXY = 16, + OPT_VERTEX = 16, + OPT_PROXY = 32, }; // Pipeline State Object diff --git a/src/format.h b/src/format.h index f9af4d9..33ad8ba 100644 --- a/src/format.h +++ b/src/format.h @@ -4153,7 +4153,10 @@ namespace TR { int16 getModelIndex(Entity::Type type) const { //#ifndef _DEBUG - if ((type >= Entity::AI_GUARD && type <= Entity::AI_CHECK) || (type >= Entity::GLOW_2 && type <= Entity::ENEMY_BAT_SWARM) || type == Entity::WATERFALL || type == Entity::KILL_ALL_TRIGGERS || type == Entity::VIEW_TARGET || type == Entity::SOUND_DOOR_BELL || type == Entity::SOUND_ALARM_BELL || type == Entity::TRIPWIRE) + if ((type >= Entity::AI_GUARD && type <= Entity::AI_CHECK) || + (type >= Entity::GLOW_2 && type <= Entity::ENEMY_BAT_SWARM) || + (type == Entity::TRAP_FLAME_EMITTER || type == Entity::MIDAS_HAND) || + type == Entity::WATERFALL || type == Entity::KILL_ALL_TRIGGERS || type == Entity::VIEW_TARGET || type == Entity::SOUND_DOOR_BELL || type == Entity::SOUND_ALARM_BELL || type == Entity::TRIPWIRE) return 0; //#endif diff --git a/src/gapi_d3d9.h b/src/gapi_d3d9.h index 2ad28c1..f228fd5 100644 --- a/src/gapi_d3d9.h +++ b/src/gapi_d3d9.h @@ -229,8 +229,8 @@ namespace GAPI { { 32, D3DFMT_A8R8G8B8 }, { 16, D3DFMT_R5G6B5 }, { 16, D3DFMT_A1R5G5B5 }, - { 64, D3DFMT_A16B16G16R16F }, {128, D3DFMT_A32B32G32R32F }, + { 64, D3DFMT_A16B16G16R16F }, { 16, D3DFMT_D16 }, { 16, D3DFMT_D24X8 }, }; @@ -277,9 +277,12 @@ namespace GAPI { if (Core::active.textures[sampler] != this) { Core::active.textures[sampler] = this; - if (tex2D) + if (tex2D) { device->SetTexture(sampler, tex2D); - else if (texCube) + if (opt & OPT_VERTEX) { + device->SetTexture(D3DVERTEXTEXTURESAMPLER0 + sampler, tex2D); + } + } else if (texCube) device->SetTexture(sampler, texCube); bool filter = (Core::settings.detail.filter > Core::Settings::LOW) && !(opt & OPT_NEAREST); @@ -291,7 +294,7 @@ namespace GAPI { if (aniso) { device->SetSamplerState(sampler, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC); - device->SetSamplerState(sampler, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); + device->SetSamplerState(sampler, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); device->SetSamplerState(sampler, D3DSAMP_MIPFILTER, D3DTEXF_NONE); device->SetSamplerState(sampler, D3DSAMP_MAXANISOTROPY, support.maxAniso); } else { @@ -403,15 +406,15 @@ namespace GAPI { support.depthTexture = false; // SHADOW_DEPTH support.shadowSampler = false; support.discardFrame = false; - support.texNPOT = false; + support.texNPOT = true; support.texRG = false; support.texBorder = false; - support.colorFloat = false; - support.colorHalf = false; - support.texFloatLinear = false; - support.texFloat = false; - support.texHalfLinear = false; - support.texHalf = false; + support.colorFloat = true; + support.colorHalf = true; + support.texFloatLinear = true; + support.texFloat = true; + support.texHalfLinear = true; + support.texHalf = true; #ifdef PROFILE support.profMarker = false; @@ -428,10 +431,14 @@ namespace GAPI { }; device->CreateVertexDeclaration(VERTEX_DECL, &vertexDecl); + + defRT = defDS = NULL; } void deinit() { vertexDecl->Release(); + if (defRT) defRT->Release(); + if (defDS) defDS->Release(); } void resetDevice() { @@ -456,6 +463,9 @@ namespace GAPI { res.texture->deinit(); } + if (defRT) { defRT->Release(); defRT = NULL; } + if (defDS) { defDS->Release(); defDS = NULL; } + D3DCHECK(device->Reset(&d3dpp)); // reinit texture RTs @@ -466,7 +476,6 @@ namespace GAPI { else res.texture->init(NULL); } - } mat4 ortho(float l, float r, float b, float t, float znear, float zfar) { @@ -493,16 +502,15 @@ namespace GAPI { return false; } - device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &defRT); - device->GetDepthStencilSurface(&defDS); + if (defRT == NULL) device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &defRT); + if (defDS == NULL) device->GetDepthStencilSurface(&defDS); + device->BeginScene(); return true; } void endFrame() { device->EndScene(); - defRT->Release(); - defDS->Release(); } void resetState() { @@ -561,6 +569,8 @@ namespace GAPI { surface->Release(); } + + Core::active.viewport = Viewport(0, 0, 0, 0); // forcing viewport reset } void discardTarget(bool color, bool depth) {} diff --git a/src/lara.h b/src/lara.h index 2114a46..d99886a 100644 --- a/src/lara.h +++ b/src/lara.h @@ -1444,7 +1444,7 @@ struct Lara : Character { flags.invisible = true; if (!environment) environment = new Texture(256, 256, FMT_RGBA, OPT_CUBEMAP | OPT_MIPMAPS | OPT_TARGET); - game->renderEnvironment(getRoomIndex(), pos - vec3(0.0f, 384.0f, 0.0f), &environment, 0, Core::passCompose); + game->renderEnvironment(getRoomIndex(), pos - vec3(0.0f, 384.0f, 0.0f), &environment); environment->generateMipMap(); flags.invisible = false; } diff --git a/src/level.h b/src/level.h index ac1f547..d69c01e 100644 --- a/src/level.h +++ b/src/level.h @@ -50,6 +50,7 @@ struct Level : IGame { bool lastTitle; bool isEnded; + bool isFirstFrame; TR::Effect::Type effect; float effectTimer; @@ -686,7 +687,13 @@ struct Level : IGame { Sound::listenersCount = 1; - if (!level.isTitle()) { + shadow = NULL; + camera = NULL; + ambientCache = NULL; + waterCache = NULL; + zoneCache = NULL; + + if (!(lastTitle = level.isTitle())) { ASSERT(players[0] != NULL); player = players[0]; camera = player->camera; @@ -695,11 +702,8 @@ struct Level : IGame { ambientCache = Core::settings.detail.lighting > Core::Settings::MEDIUM ? new AmbientCache(this) : NULL; waterCache = Core::settings.detail.water > Core::Settings::LOW ? new WaterCache(this) : NULL; - shadow = NULL; initShadow(); - initReflections(); - for (int i = 0; i < level.soundSourcesCount; i++) { TR::SoundSource &src = level.soundSources[i]; int flags = Sound::PAN; @@ -708,14 +712,7 @@ struct Level : IGame { playSound(src.id, vec3(float(src.x), float(src.y), float(src.z)), flags); } - lastTitle = false; } else { - camera = NULL; - ambientCache = NULL; - waterCache = NULL; - zoneCache = NULL; - shadow = NULL; - lastTitle = true; inventory.toggle(0, Inventory::PAGE_OPTION); } @@ -726,6 +723,8 @@ struct Level : IGame { sndWater = sndTrack = NULL; + isFirstFrame = true; + playTrack(0); /* if (level.id == TR::LVL_TR2_RIG) { @@ -2375,6 +2374,11 @@ struct Level : IGame { } void renderPrepare() { + if (isFirstFrame) { + initReflections(); + isFirstFrame = false; + } + if (ambientCache) ambientCache->processQueue(); diff --git a/src/platform/win/main.cpp b/src/platform/win/main.cpp index d21dadd..a01bd41 100644 --- a/src/platform/win/main.cpp +++ b/src/platform/win/main.cpp @@ -429,7 +429,7 @@ HWND hWnd; memset(&d3dpp, 0, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.BackBufferCount = 1; - d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; + d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = hWnd; d3dpp.EnableAutoDepthStencil = TRUE; diff --git a/src/shaders/base.hlsl b/src/shaders/base.hlsl index cebcc62..60245e3 100644 --- a/src/shaders/base.hlsl +++ b/src/shaders/base.hlsl @@ -1,15 +1,15 @@ #include "common.hlsl" struct VS_OUTPUT { - float4 pos : POSITION; - float3 coord : TEXCOORD0; - float4 texCoord : TEXCOORD1; - float4 viewVec : TEXCOORD2; - float4 normal : NORMAL; - float4 diffuse : COLOR0; - float3 ambient : COLOR1; - float4 lightMap : COLOR2; - float4 light : COLOR3; + float4 pos : POSITION; + float3 coord : TEXCOORD0; + float4 texCoord : TEXCOORD1; + float4 viewVec : TEXCOORD2; + float4 normal : NORMAL; + float4 diffuse : COLOR0; + float3 ambient : COLOR1; + float4 lightMap : COLOR2; + float4 light : COLOR3; float4 hpos : TEXCOORD4; }; @@ -216,7 +216,7 @@ float getContactAO(float3 p, float3 n) { float calcCaustics(float3 coord, float3 n) { float2 cc = saturate((coord.xz - uRoomSize.xy) / uRoomSize.zw); - return tex2D(sReflect, cc).x * max(0.0, -n.y); + return tex2D(sReflect, float2(cc.x, 1.0 - cc.y)).x * max(0.0, -n.y); } float calcSpecular(float3 normal, float3 viewVec, float3 lightVec, float4 color, float intensity) { diff --git a/src/shaders/common.hlsl b/src/shaders/common.hlsl index 7132a91..21a8eca 100644 --- a/src/shaders/common.hlsl +++ b/src/shaders/common.hlsl @@ -2,15 +2,12 @@ #define MAX_CONTACTS 15 #define WATER_FOG_DIST (1.0 / (6.0 * 1024.0)) #define UNDERWATER_COLOR float3(0.6, 0.9, 0.9) +#define SHADOW_NORMAL_BIAS 16.0 +#define SHADOW_CONST_BIAS 0.18 +#define PI 3.141592653589793 static const float3 SHADOW_TEXEL = float3(1.0 / 1024.0, 1.0 / 1024.0, 0.0); -#define SHADOW_NORMAL_BIAS 16.0 -#define SHADOW_CONST_BIAS 0.12 - -#define MAX_LIGHTS 4 -#define MAX_CONTACTS 15 - struct VS_INPUT { float4 aCoord : POSITION; float4 aNormal : NORMAL; @@ -19,14 +16,12 @@ struct VS_INPUT { float4 aLight : COLOR1; }; -#ifdef PIXEL - sampler sDiffuse : register(s0); - sampler sNormal : register(s1); - sampler sReflect : register(s2); - sampler sShadow : register(s3); - sampler sEnvironment : register(s4); - sampler sMask : register(s5); -#endif +sampler sDiffuse : register(s0); +sampler sNormal : register(s1); +sampler sReflect : register(s2); +sampler sShadow : register(s3); +sampler sEnvironment : register(s4); +sampler sMask : register(s5); bool uFlags[16] : register( b0 ); float4 uParam : register( c0 ); diff --git a/src/shaders/compile_dx9.bat b/src/shaders/compile_dx9.bat index a604f90..59fd086 100644 --- a/src/shaders/compile_dx9.bat +++ b/src/shaders/compile_dx9.bat @@ -1,13 +1,13 @@ @echo off -fxc /nologo /T vs_3_0 /O3 /Vn COMPOSE_VS /Fh compose_vs.h base.hlsl /DPASS_COMPOSE /DVERTEX -fxc /nologo /T ps_3_0 /O3 /Vn COMPOSE_PS /Fh compose_ps.h base.hlsl /DPASS_COMPOSE /DPIXEL -fxc /nologo /T vs_3_0 /O3 /Vn SHADOW_VS /Fh shadow_vs.h base.hlsl /DPASS_SHADOW /DVERTEX -fxc /nologo /T ps_3_0 /O3 /Vn SHADOW_PS /Fh shadow_ps.h base.hlsl /DPASS_SHADOW /DPIXEL -fxc /nologo /T vs_3_0 /O3 /Vn AMBIENT_VS /Fh ambient_vs.h base.hlsl /DPASS_AMBIENT /DVERTEX -fxc /nologo /T ps_3_0 /O3 /Vn AMBIENT_PS /Fh ambient_ps.h base.hlsl /DPASS_AMBIENT /DPIXEL -fxc /nologo /T vs_3_0 /O3 /Vn WATER_VS /Fh water_vs.h water.hlsl /DVERTEX -fxc /nologo /T ps_3_0 /O3 /Vn WATER_PS /Fh water_ps.h water.hlsl /DPIXEL -fxc /nologo /T vs_3_0 /O3 /Vn FILTER_VS /Fh filter_vs.h filter.hlsl /DVERTEX -fxc /nologo /T ps_3_0 /O3 /Vn FILTER_PS /Fh filter_ps.h filter.hlsl /DPIXEL -fxc /nologo /T vs_3_0 /O3 /Vn GUI_VS /Fh gui_vs.h gui.hlsl /DVERTEX -fxc /nologo /T ps_3_0 /O3 /Vn GUI_PS /Fh gui_ps.h gui.hlsl /DPIXEL \ No newline at end of file +fxc /nologo /T vs_3_0 /O3 /Gec /Vn COMPOSE_VS /Fh compose_vs.h base.hlsl /DPASS_COMPOSE /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Gec /Vn COMPOSE_PS /Fh compose_ps.h base.hlsl /DPASS_COMPOSE /DPIXEL +fxc /nologo /T vs_3_0 /O3 /Gec /Vn SHADOW_VS /Fh shadow_vs.h base.hlsl /DPASS_SHADOW /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Gec /Vn SHADOW_PS /Fh shadow_ps.h base.hlsl /DPASS_SHADOW /DPIXEL +fxc /nologo /T vs_3_0 /O3 /Gec /Vn AMBIENT_VS /Fh ambient_vs.h base.hlsl /DPASS_AMBIENT /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Gec /Vn AMBIENT_PS /Fh ambient_ps.h base.hlsl /DPASS_AMBIENT /DPIXEL +fxc /nologo /T vs_3_0 /O3 /Gec /Vn WATER_VS /Fh water_vs.h water.hlsl /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Gec /Vn WATER_PS /Fh water_ps.h water.hlsl /DPIXEL +fxc /nologo /T vs_3_0 /O3 /Gec /Vn FILTER_VS /Fh filter_vs.h filter.hlsl /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Gec /Vn FILTER_PS /Fh filter_ps.h filter.hlsl /DPIXEL +fxc /nologo /T vs_3_0 /O3 /Gec /Vn GUI_VS /Fh gui_vs.h gui.hlsl /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Gec /Vn GUI_PS /Fh gui_ps.h gui.hlsl /DPIXEL \ No newline at end of file diff --git a/src/shaders/filter.hlsl b/src/shaders/filter.hlsl index de20637..fe38570 100644 --- a/src/shaders/filter.hlsl +++ b/src/shaders/filter.hlsl @@ -1,7 +1,7 @@ #include "common.hlsl" struct VS_OUTPUT { - float4 wpos : POSITION; + float4 pos : POSITION; float2 texCoord : TEXCOORD0; float4 diffuse : COLOR0; }; @@ -9,7 +9,7 @@ struct VS_OUTPUT { #ifdef VERTEX VS_OUTPUT main(VS_INPUT In) { VS_OUTPUT Out; - Out.wpos = float4(In.aCoord.xy * (1.0 / 32767.0), 0.0, 1.0); + Out.pos = float4(In.aCoord.xy * (1.0 / 32767.0), 0.0, 1.0); Out.texCoord = In.aTexCoord.xy * (1.0 / 32767.0); Out.diffuse = In.aLight; diff --git a/src/shaders/gui.hlsl b/src/shaders/gui.hlsl index e58f284..8a7921b 100644 --- a/src/shaders/gui.hlsl +++ b/src/shaders/gui.hlsl @@ -1,23 +1,23 @@ #include "common.hlsl" struct VS_OUTPUT { - float4 wPos : POSITION; - float2 vTexCoord : TEXCOORD0; - float4 vDiffuse : COLOR0; + float4 pos : POSITION; + float2 texCoord : TEXCOORD0; + float4 diffuse : COLOR0; }; #ifdef VERTEX VS_OUTPUT main(VS_INPUT In) { VS_OUTPUT Out; - Out.wPos = mul(uViewProj, float4(In.aCoord.xy, 0.0, 1.0)); - Out.vTexCoord = In.aTexCoord.xy * (1.0 / 32767.0); - Out.vDiffuse = In.aLight * uMaterial; + Out.pos = mul(uViewProj, float4(In.aCoord.xy, 0.0, 1.0)); + Out.texCoord = In.aTexCoord.xy * (1.0 / 32767.0); + Out.diffuse = In.aLight * uMaterial; return Out; } #else // PIXEL float4 main(VS_OUTPUT In) : COLOR0 { - return (In.vDiffuse * tex2D(sDiffuse, In.vTexCoord.xy)).bgra; + return (In.diffuse * tex2D(sDiffuse, In.texCoord.xy)).bgra; } #endif \ No newline at end of file diff --git a/src/shaders/water.glsl b/src/shaders/water.glsl index 08761db..469318b 100644 --- a/src/shaders/water.glsl +++ b/src/shaders/water.glsl @@ -10,11 +10,14 @@ R"====( varying vec3 vCoord; varying vec2 vTexCoord; varying vec4 vProjCoord; -varying vec4 vOldPos; -varying vec4 vNewPos; varying vec3 vViewVec; varying vec3 vLightVec; +#ifdef WATER_CAUSTICS + varying vec3 vOldPos; + varying vec3 vNewPos; +#endif + uniform vec4 uViewPos; uniform mat4 uViewProj; uniform vec4 uLightPos; @@ -26,9 +29,6 @@ uniform vec4 uParam; uniform sampler2D sNormal; #ifdef VERTEX - #define ETA_AIR 1.000 - #define ETA_WATER 1.333 - attribute vec4 aCoord; void main() { @@ -59,12 +59,11 @@ uniform sampler2D sNormal; vec3 refOld = refract(-light, vec3(0.0, 0.0, 1.0), 0.75); vec3 refNew = refract(-light, normal, 0.75); - vOldPos = vec4(rCoord + refOld * (-1.0 / refOld.z) + refOld * ((-refOld.z - 1.0) / refOld.z), 1.0); - vNewPos = vec4(rCoord + refNew * ((info.r - 1.0) / refNew.z) + refOld * ((-refNew.z - 1.0) / refOld.z), 1.0); + vOldPos = rCoord + refOld * (-1.0 / refOld.z) + refOld * ((-refOld.z - 1.0) / refOld.z); + vNewPos = rCoord + refNew * ((info.r - 1.0) / refNew.z) + refOld * ((-refNew.z - 1.0) / refOld.z); gl_Position = vec4(vNewPos.xy + refOld.xy / refOld.z, 0.0, 1.0); #else - vOldPos = vNewPos = vec4(0.0); gl_Position = vec4(coord.xyz, 1.0); #endif #endif @@ -91,10 +90,9 @@ uniform sampler2D sNormal; } vec4 drop() { - vec2 tc = gl_FragCoord.xy * uTexParam.xy; - vec4 v = texture2D(sDiffuse, tc); + vec4 v = texture2D(sDiffuse, vTexCoord); - float drop = max(0.0, 1.0 - length(uParam.xy - gl_FragCoord.xy) / uParam.z); + float drop = max(0.0, 1.0 - length(uParam.xy - vTexCoord / uTexParam.xy) / uParam.z); drop = 0.5 - cos(drop * PI) * 0.5; v.x += drop * uParam.w; @@ -133,7 +131,7 @@ uniform sampler2D sNormal; } vec4 calc() { - vec2 tc = gl_FragCoord.xy * uTexParam.xy; + vec2 tc = vTexCoord; if (texture2D(sMask, tc).x < 0.5) return vec4(0.0); @@ -160,10 +158,10 @@ uniform sampler2D sNormal; } #ifdef WATER_CAUSTICS vec4 caustics() { - float rOldArea = length(dFdx(vOldPos.xyz)) * length(dFdy(vOldPos.xyz)); - float rNewArea = length(dFdx(vNewPos.xyz)) * length(dFdy(vNewPos.xyz)); + float rOldArea = length(dFdx(vOldPos)) * length(dFdy(vOldPos)); + float rNewArea = length(dFdx(vNewPos)) * length(dFdy(vNewPos)); rNewArea = max(rNewArea, 0.00002); // WebGL NVIDIA workaround >_< - float value = clamp(rOldArea / rNewArea * 0.2, 0.0, 1.0) * vOldPos.w; + float value = clamp(rOldArea / rNewArea * 0.2, 0.0, 1.0); return vec4(value, 0.0, 0.0, 0.0); } #endif diff --git a/src/shaders/water.hlsl b/src/shaders/water.hlsl index 2d50ed5..9a2c7f7 100644 --- a/src/shaders/water.hlsl +++ b/src/shaders/water.hlsl @@ -1,50 +1,213 @@ #include "common.hlsl" struct VS_OUTPUT { - float4 wPos : POSITION; - float3 vCoord : TEXCOORD2; - float4 vTexCoord : TEXCOORD0; - float4 vDiffuse : COLOR0; - float4 vNormal : NORMAL; - float4 vViewVec : TEXCOORD1; - float3 vAmbient : COLOR1; - float4 vLightMap : COLOR2; - float4 vLight : COLOR3; + float4 pos : POSITION; + float3 coord : TEXCOORD0; + float2 texCoord : TEXCOORD1; + float3 viewVec : TEXCOORD2; + float3 lightVec : TEXCOORD3; + float3 oldPos : TEXCOORD4; + float3 newPos : TEXCOORD5; + float4 hpos : TEXCOORD6; }; -#ifdef VERTEX -float3 mulQuat(float4 q, float3 v) { - return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + v * q.w); +float2 invUV(float2 uv) { + return float2(uv.x, 1.0 - uv.y); } -float3 mulBasis(float4 rot, float3 pos, float3 v) { - return mulQuat(rot, v) + pos; +float3 getInvUV(float2 uv, float4 param) { + return float3((float2(uv.x, -uv.y) * 0.5 + 0.5) * param.zw + 0.5 * param.xy, 0.0); } - + +#ifdef VERTEX VS_OUTPUT main(VS_INPUT In) { VS_OUTPUT Out; + + float3 coord = In.aCoord.xyz * (1.0 / 32767.0); - int index = int(In.aCoord.w * 2.0); - float4 rBasisRot = uBasis[index]; - float4 rBasisPos = uBasis[index + 1]; - Out.vCoord = mulBasis(rBasisRot, rBasisPos.xyz, In.aCoord.xyz); - Out.wPos = mul(uViewProj, float4(Out.vCoord, rBasisPos.w)); + if (WATER_COMPOSE) { + Out.coord = float3(coord.x, 0.0, coord.y) * uPosScale[1].xyz + uPosScale[0].xyz; + Out.pos = mul(uViewProj, float4(Out.coord, 1.0)); + Out.viewVec = uViewPos.xyz - Out.coord.xyz; + Out.lightVec = uLightPos[0].xyz - Out.coord.xyz; + Out.oldPos = getInvUV(coord.xy, uTexParam); + } else if (WATER_DROP) { + Out.pos = float4(coord.xyz, 1.0); + Out.oldPos = getInvUV(coord.xy, uTexParam); + } else if (WATER_STEP) { + Out.pos = float4(coord.xyz, 1.0); + Out.oldPos = getInvUV(coord.xy, uTexParam); + } else if (WATER_CAUSTICS) { + float3 rCoord = float3(coord.x, coord.y, 0.0) * uPosScale[1].xzy; + float2 uv = getInvUV(rCoord.xy, uTexParam).xy; + float4 info = tex2Dlod(sNormal, float4(uv, 0, 0)); + float3 normal = float3(info.z, info.w, sqrt(1.0 - dot(info.zw, info.zw))); - Out.vTexCoord = In.aTexCoord * (1.0 / 32767.0); - Out.vTexCoord.xy *= Out.vTexCoord.zw; + float3 light = float3(0.0, 0.0, 1.0); + float3 refOld = refract(-light, float3(0.0, 0.0, 1.0), 0.75); + float3 refNew = refract(-light, normal, 0.75); - Out.vDiffuse = float4(In.aColor.xyz * In.aLight.xyz, 1.0); - Out.vNormal = In.aNormal; - Out.vViewVec = float4(uViewPos.xyz - Out.vCoord, 0.0); - Out.vAmbient = float3(0.2, 0.2, 0.2); - Out.vLightMap = float4(1.0, 1.0, 1.0, 0.0); - Out.vLight = float4(0.5, 0.5, 0.5, 0.5); + Out.oldPos = rCoord + refOld * (-1.0 / refOld.z) + refOld * ((-refOld.z - 1.0) / refOld.z); + Out.newPos = rCoord + refNew * ((info.r - 1.0) / refNew.z) + refOld * ((-refNew.z - 1.0) / refOld.z); + + Out.pos = float4(Out.newPos.xy + refOld.xy / refOld.z, 0.0, 1.0); + } else if (WATER_MASK) { + Out.coord = float3(coord.x, 0.0, coord.y) * uPosScale[1].xyz + uPosScale[0].xyz; + Out.pos = mul(uViewProj, float4(Out.coord, 1.0)); + } + + Out.texCoord = (coord.xy * 0.5 + 0.5) * uTexParam.zw + 0.5 * uTexParam.xy; // + half texel offset + Out.hpos = Out.pos; + return Out; } #else // PIXEL +float calcFresnel(float NdotL, float fbias) { + float f = 1.0 - NdotL; + return saturate(fbias + (1.0 - fbias) * (f * f)); +} + +float3 applyFog(float3 color, float3 fogColor, float factor) { + float fog = saturate(1.0 / exp(factor)); + return lerp(fogColor, color, fog); +} + +float4 drop(VS_OUTPUT In) { + float2 iuv = In.oldPos.xy; + + float4 v = tex2D(sDiffuse, iuv); + + float drop = max(0.0, 1.0 - length(uParam.xy - In.texCoord / uTexParam.xy) / uParam.z); + drop = 0.5 - cos(drop * PI) * 0.5; + + v.x += drop * uParam.w; + + return v; +} + +float3 hash33(float3 p3) { + p3 = frac(p3 * float3(.1031,.11369,.13787)); + p3 += dot(p3, p3.yxz+19.19); + return -1.0 + 2.0 * frac(float3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x)); +} + +float simplex_noise(float3 p) { // https://www.shadertoy.com/view/4sc3z2 + const float K1 = 0.333333333; + const float K2 = 0.166666667; + + float3 i = floor(p + (p.x + p.y + p.z) * K1); + float3 d0 = p - (i - (i.x + i.y + i.z) * K2); + + float3 e = step((float3)0.0, d0 - d0.yzx); + float3 i1 = e * (1.0 - e.zxy); + float3 i2 = 1.0 - e.zxy * (1.0 - e); + + float3 d1 = d0 - (i1 - 1.0 * K2); + float3 d2 = d0 - (i2 - 2.0 * K2); + float3 d3 = d0 - (1.0 - 3.0 * K2); + + float4 h = max(0.6 - float4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0); + float4 n = h * h * h * h * float4(dot(d0, hash33(i)), dot(d1, hash33(i + i1)), dot(d2, hash33(i + i2)), dot(d3, hash33(i + 1.0))); + + return dot((float4)31.316, n); +} + +float h(float2 tc) { + return simplex_noise(float3(tc * 16.0, uParam.w)) * 0.0005; +} + +float4 calc(VS_OUTPUT In) { + float2 iuv = In.oldPos.xy; + float2 uv = In.texCoord; + + if (tex2D(sMask, uv).x < 0.5) + return 0.0; + + float4 v = tex2D(sDiffuse, iuv); // height, speed, normal.xz + + float3 d = float3(float2(uTexParam.x, -uTexParam.y), 0.0); + float4 f = float4( + tex2D(sDiffuse, iuv + d.xz).x, tex2D(sDiffuse, iuv + d.zy).x, + tex2D(sDiffuse, iuv - d.xz).x, tex2D(sDiffuse, iuv - d.zy).x + ); + + float average = dot(f, (float4)0.25); + +// normal + v.zw = normalize( float3(f.x - f.z, 64.0 / (1024.0 * 4.0), f.y - f.w) ).xz; + +// integrate + const float vel = 1.4; + const float vis = 0.995; + + v.y += (average - v.x) * vel; + v.y *= vis; + v.x += v.y + h(uv); + + return v; +} + +float4 caustics(VS_OUTPUT In) { + float rOldArea = length(ddx(In.oldPos)) * length(ddy(In.oldPos)); + float rNewArea = length(ddx(In.newPos)) * length(ddy(In.newPos)); + rNewArea = max(rNewArea, 0.00002); // WebGL NVIDIA workaround >_< + float value = saturate(rOldArea / rNewArea * 0.2); + return float4(value, 0.0, 0.0, 0.0); +} + +float4 mask(VS_OUTPUT In) { + return 0.0; +} + +float4 compose(VS_OUTPUT In) { + float3 viewVec = normalize(In.viewVec); + float2 iuv = In.oldPos.xy; + + float4 value = tex2D(sNormal, iuv); + float3 normal = float3(value.z, sqrt(1.0 - dot(value.zw, value.zw)) * sign(viewVec.y), value.w); + float2 dudv = mul(uViewProj, float4(normal.x, 0.0, normal.z, 0.0)).xy; + + float3 rv = reflect(-viewVec, normal); + float3 lv = normalize(In.lightVec); + + float spec = pow(max(0.0, dot(rv, lv)), 64.0) * 0.5; + + float2 tc = In.hpos.xy / In.hpos.w * 0.5 + 0.5; + + float4 refrA = tex2D(sDiffuse, uParam.xy * invUV(clamp(tc + dudv * uParam.z, 0.0, 0.999)) ); + float4 refrB = tex2D(sDiffuse, uParam.xy * invUV(tc) ); + float4 refr = float4(lerp(refrA.xyz, refrB.xyz, refrA.w), 1.0); + float4 refl = tex2D(sReflect, tc.xy + dudv * uParam.w); + + float fresnel = calcFresnel(dot(normal, viewVec), 0.04); + + float4 color = lerp(refr, refl, fresnel) + spec * 1.5; + + float d = abs((In.coord.y - uViewPos.y) / normalize(In.viewVec).y); + d *= step(0.0, uViewPos.y - In.coord.y); // apply fog only when camera is underwater + color.xyz = applyFog(color.xyz, UNDERWATER_COLOR * 0.2, d * WATER_FOG_DIST); + color.w *= tex2D(sMask, In.texCoord).x; + return color; +} + float4 main(VS_OUTPUT In) : COLOR0 { - return (In.vDiffuse * tex2D(sDiffuse, In.vTexCoord.xy / In.vTexCoord.zw)).bgra; + if (WATER_DROP) + return drop(In); + + if (WATER_STEP) + return calc(In); + + if (WATER_CAUSTICS) + return caustics(In); + + if (WATER_MASK) + return mask(In); + + if (WATER_COMPOSE) + return compose(In); + + return float4(1.0, 0.0, 1.0, 1.0); } #endif \ No newline at end of file