1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-20 03:41:33 +02:00

D3D reflections and water; hide dummy meshes for fire traps

This commit is contained in:
XProger
2018-05-20 06:36:50 +03:00
parent d6e1d42927
commit 5fd45795c1
15 changed files with 312 additions and 132 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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) {}

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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 );

View File

@@ -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
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

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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