From 2cd339138b79c0915c02ccc1355fd8c89580c457 Mon Sep 17 00:00:00 2001 From: XProger Date: Thu, 22 Dec 2016 03:37:49 +0300 Subject: [PATCH] #23 environment reflections for crystals (cubemaps) --- src/core.h | 24 ++++++++------ src/level.h | 86 ++++++++++++++++++++++++++++++------------------- src/shader.glsl | 41 ++++++++++++++--------- src/shader.h | 6 ++-- src/texture.h | 41 ++++++++++++----------- src/trigger.h | 23 +++++++++++++ 6 files changed, 142 insertions(+), 79 deletions(-) diff --git a/src/core.h b/src/core.h index fcc99ac..d5a5f93 100644 --- a/src/core.h +++ b/src/core.h @@ -246,7 +246,7 @@ namespace Core { glGenFramebuffers(1, &RT); glGenRenderbuffers(1, &RB); glBindRenderbuffer(GL_RENDERBUFFER, RB); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 64, 64); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 128, 128); glBindRenderbuffer(GL_RENDERBUFFER, 0); Sound::init(); @@ -262,11 +262,6 @@ namespace Core { Sound::free(); } - void resetStates() { - memset(&active, 0, sizeof(active)); - glEnable(GL_DEPTH_TEST); - } - void clear(const vec4 &color) { glClearColor(color.x, color.y, color.z, color.w); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); @@ -315,16 +310,20 @@ namespace Core { glEnable(GL_BLEND); } - void setTarget(Texture *target) { + void setTarget(Texture *target, int face = 0) { if (!target) { glBindFramebuffer(GL_FRAMEBUFFER, 0); glColorMask(true, true, true, true); return; } + GLenum texTarget = GL_TEXTURE_2D; + if (target->cube) + texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + glBindFramebuffer(GL_FRAMEBUFFER, RT); - glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target->ID, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, target->dummy ? target->dummy->ID : 0, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, texTarget, target->ID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, texTarget, target->dummy ? target->dummy->ID : 0, 0); if (!target->depth) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, RB); @@ -333,6 +332,13 @@ namespace Core { // GLenum buffers[] = { GL_COLOR_ATTACHMENT0 }; // glDrawBuffers(target->depth ? 0 : 1, buffers); } + + void resetStates() { + memset(&active, 0, sizeof(active)); + glEnable(GL_DEPTH_TEST); + setCulling(cfFront); + setBlending(bmAlpha); + } } #endif diff --git a/src/level.h b/src/level.h index 5fdf0cc..ba804a8 100644 --- a/src/level.h +++ b/src/level.h @@ -48,10 +48,10 @@ struct Level { #endif mesh = new MeshBuilder(level); - shadow = new Texture(1024, 1024, true); + shadow = new Texture(1024, 1024, true, false); for (int j = 0; j < 6; j++) for (int i = 0; i < 4; i++) - ambient[j * 4 + i] = new Texture(64 >> (i << 1), 64 >> (i << 1), false); + ambient[j * 4 + i] = new Texture(64 >> (i << 1), 64 >> (i << 1), false, false); initAtlas(); initShaders(); @@ -119,6 +119,9 @@ struct Level { case TR::Entity::TRAP_FLOOR : entity.controller = new TrapFloor(&level, i); break; + case TR::Entity::CRYSTAL : + entity.controller = new Crystal(&level, i); + break; case TR::Entity::TRAP_BLADE : case TR::Entity::TRAP_SPIKES : entity.controller = new Trigger(&level, i, true); @@ -151,6 +154,8 @@ struct Level { camera = new Camera(&level, lara); level.cameraController = camera; + + initReflections(); } ~Level() { @@ -204,7 +209,7 @@ struct Level { fclose(f); */ - atlas = new Texture(1024, 1024, false, data); + atlas = new Texture(1024, 1024, false, false, data); PROFILE_LABEL(TEXTURE, atlas->ID, "atlas"); delete[] data; @@ -274,6 +279,17 @@ struct Level { */ } + void initReflections() { + Core::resetStates(); + for (int i = 0; i < level.entitiesBaseCount; i++) { + TR::Entity &e = level.entities[i]; + if (e.type == TR::Entity::CRYSTAL) { + Crystal *c = (Crystal*)e.controller; + renderEnvironment(c->getRoomIndex(), c->pos - vec3(0, 512, 0), &c->environment); + } + } + } + #ifdef LEVEL_EDITOR struct Light { vec3 pos; @@ -601,20 +617,20 @@ struct Level { } void setupCubeCamera(const vec3 &pos, int face) { - vec3 up = vec3(0, 1, 0); + vec3 up = vec3(0, -1, 0); vec3 dir; switch (face) { case 0 : dir = vec3( 1, 0, 0); break; case 1 : dir = vec3(-1, 0, 0); break; - case 2 : dir = vec3( 0, 1, 0); up = vec3(1, 0, 0); break; - case 3 : dir = vec3( 0, -1, 0); up = vec3(1, 0, 0); break; + case 2 : dir = vec3( 0, 1, 0); up = vec3(0, 0, 1); break; + case 3 : dir = vec3( 0, -1, 0); up = vec3(0, 0, -1); break; case 4 : dir = vec3( 0, 0, 1); break; case 5 : dir = vec3( 0, 0, -1); break; } Core::mViewInv = mat4(pos, pos + dir, up); - Core::mView = Core::mViewInv.inverse(); - Core::mProj = mat4(90, 1.0f, camera->znear, camera->zfar); + Core::mView = Core::mViewInv.inverse(); + Core::mProj = mat4(90, 1.0f, camera->znear, camera->zfar); } bool setupLightCamera() { @@ -628,13 +644,13 @@ struct Level { TR::Room::Light &light = level.rooms[room].lights[idx]; vec3 shadowLightPos = vec3(float(light.x), float(light.y), float(light.z)); Core::mViewInv = mat4(shadowLightPos, pos - vec3(0, 256, 0), vec3(0, -1, 0)); - Core::mView = Core::mViewInv.inverse(); - Core::mProj = mat4(120, 1.0f, camera->znear, camera->zfar); + Core::mView = Core::mViewInv.inverse(); + Core::mProj = mat4(120, 1.0f, camera->znear, camera->zfar); - mat4 bias; - bias.identity(); - bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f; - Core::mLightProj = bias * Core::mProj * Core::mView; + mat4 bias; + bias.identity(); + bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f; + Core::mLightProj = bias * Core::mProj * Core::mView; return true; } @@ -652,20 +668,25 @@ struct Level { sh->bind(); } - void renderAmbient(int roomIndex, const vec3 &pos, vec3 *cube) { - PROFILE_MARKER("PASS_AMBIENT"); - + void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) { + PROFILE_MARKER("ENVIRONMENT"); // first pass render level into cube faces - for (int j = 0; j < 6; j++) { - setupCubeCamera(pos, j); + for (int i = 0; i < 6; i++) { + setupCubeCamera(pos, i); setPassShader(Core::passAmbient); Core::setBlending(bmAlpha); - Texture *target = ambient[j * 4 + 0]; - Core::setTarget(target); - Core::setViewport(0, 0, target->width, target->height); + Texture *target = targets[0]->cube ? targets[0] : targets[i * stride]; + Core::setTarget(target, i); + Core::setViewport(0, 0, target->width, target->height); Core::clear(vec4(0, 0, 0, 1)); renderScene(roomIndex); } + } + + void renderAmbient(int roomIndex, const vec3 &pos, vec3 *cube) { + PROFILE_MARKER("PASS_AMBIENT"); + + renderEnvironment(roomIndex, pos, ambient, 4); // second pass - downsample glDisable(GL_DEPTH_TEST); @@ -705,7 +726,7 @@ struct Level { void renderShadows(int roomIndex) { PROFILE_MARKER("PASS_SHADOW"); if (!setupLightCamera()) return; - Texture::unbind(sShadow); + shadow->unbind(sShadow); setPassShader(Core::passShadow); Core::setBlending(bmNone); Core::setTarget(shadow); @@ -734,7 +755,6 @@ struct Level { renderAmbient(lara->getRoomIndex(), lara->pos - vec3(0, 512, 0), cube); renderShadows(lara->getRoomIndex()); renderCompose(camera->getRoomIndex()); - #ifdef _DEBUG static int modelIndex = 0; @@ -765,7 +785,7 @@ struct Level { // Debug::Level::rooms(level, lara->pos, lara->getEntity().room); // Debug::Level::lights(level, lara->getRoomIndex()); // Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y); - Debug::Level::portals(level); + // Debug::Level::portals(level); // Debug::Level::meshes(level); // Debug::Level::entities(level); static int dbg_ambient = 0; @@ -781,19 +801,19 @@ struct Level { switch (j) { case 0 : glRotatef( 90, 0, 1, 0); break; case 1 : glRotatef(-90, 0, 1, 0); break; - case 2 : glRotatef(-90, 1, 0, 0); glRotatef(-90, 0, 0, 1); break; - case 3 : glRotatef( 90, 1, 0, 0); glRotatef(-90, 0, 0, 1); break; + case 2 : glRotatef(-90, 1, 0, 0); break; + case 3 : glRotatef( 90, 1, 0, 0); break; case 4 : glRotatef( 0, 0, 1, 0); break; case 5 : glRotatef(180, 0, 1, 0); break; } glTranslatef(0, 0, 256); - Texture::unbind(sShadow); + shadow->unbind(sShadow); ambient[j * 4 + dbg_ambient]->bind(sDiffuse); glBegin(GL_QUADS); - glTexCoord2f(1, 1); glVertex3f(-256, 256, 0); - glTexCoord2f(0, 1); glVertex3f( 256, 256, 0); - glTexCoord2f(0, 0); glVertex3f( 256, -256, 0); - glTexCoord2f(1, 0); glVertex3f(-256, -256, 0); + glTexCoord2f(0, 0); glVertex3f(-256, 256, 0); + glTexCoord2f(1, 0); glVertex3f( 256, 256, 0); + glTexCoord2f(1, 1); glVertex3f( 256, -256, 0); + glTexCoord2f(0, 1); glVertex3f(-256, -256, 0); glEnd(); glPopMatrix(); } @@ -813,7 +833,7 @@ struct Level { glEnable(GL_DEPTH_TEST); */ - Debug::Level::info(level, lara->getEntity(), lara->animation); +// Debug::Level::info(level, lara->getEntity(), lara->animation); Debug::end(); #endif } diff --git a/src/shader.glsl b/src/shader.glsl index f7d0f52..ab75c8d 100644 --- a/src/shader.glsl +++ b/src/shader.glsl @@ -13,9 +13,10 @@ varying vec2 vTexCoord; #endif #define TYPE_SPRITE 0 -#define TYPE_ROOM 1 -#define TYPE_ENTITY 2 -#define TYPE_FLASH 3 +#define TYPE_FLASH 1 +#define TYPE_ROOM 2 +#define TYPE_ENTITY 3 +#define TYPE_MIRROR 4 uniform int uType; @@ -103,8 +104,10 @@ uniform int uType; uniform sampler2D sDiffuse; uniform vec4 uColor; #ifdef PASS_COMPOSE - uniform vec3 uLightPos[MAX_LIGHTS]; - uniform vec4 uLightColor[MAX_LIGHTS]; + uniform samplerCube sEnvironment; + uniform vec3 uLightPos[MAX_LIGHTS]; + uniform vec4 uLightColor[MAX_LIGHTS]; + uniform vec3 uAmbient[6]; #endif #ifdef PASS_SHADOW @@ -120,15 +123,6 @@ uniform int uType; #endif #ifdef PASS_COMPOSE - uniform vec3 uAmbient[6]; - - vec3 getAmbientLight(vec3 n) { - vec3 sqr = n * n; - vec3 pos = step(0.0, n); - return sqr.x * mix(uAmbient[1], uAmbient[0], pos.x) + - sqr.y * mix(uAmbient[3], uAmbient[2], pos.y) + - sqr.z * mix(uAmbient[5], uAmbient[4], pos.z); - } #ifdef SHADOW_SAMPLER uniform sampler2DShadow sShadow; @@ -201,6 +195,14 @@ uniform int uType; float att = max(0.0, 1.0 - dot(lv, lv) / color.w); return color.xyz * (lum * att); } + + vec3 calcAmbient(vec3 n) { + vec3 sqr = n * n; + vec3 pos = step(0.0, n); + return sqr.x * mix(uAmbient[1], uAmbient[0], pos.x) + + sqr.y * mix(uAmbient[3], uAmbient[2], pos.y) + + sqr.z * mix(uAmbient[5], uAmbient[4], pos.z); + } #endif void main() { @@ -242,10 +244,17 @@ uniform int uType; } if (uType == TYPE_ENTITY) { - vec3 rAmbient = pow(abs(getAmbientLight(normal)), vec3(2.2)); + vec3 rAmbient = pow(abs(calcAmbient(normal)), vec3(2.2)); float rShadow = getShadow(vLightProj); - light += calcLight(normal, uLightPos[0], uLightColor[0]) * rShadow + rAmbient; + light += calcLight(normal, uLightPos[0], uLightColor[0]) * rShadow + rAmbient; } + + if (uType == TYPE_MIRROR) { + vec3 rv = reflect(-viewVec, normal); + color.xyz = uColor.xyz * pow(abs(textureCube(sEnvironment, normalize(rv)).xyz), vec3(2.2)); + light.xyz = vec3(1.0); + } + color.xyz *= light; } else { color.w = uColor.w; diff --git a/src/shader.h b/src/shader.h index 69df9b4..0d8cb81 100644 --- a/src/shader.h +++ b/src/shader.h @@ -4,18 +4,18 @@ #include "core.h" enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX }; -enum SamplerType { sDiffuse, sShadow, sMAX }; +enum SamplerType { sDiffuse, sShadow, sEnvironment, sMAX }; enum UniformType { uType, uCaustics, uTime, uViewProj, uViewInv, uModel, uLightProj, uColor, uAmbient, uViewPos, uLightPos, uLightColor, uLightTarget, uAnimTexRanges, uAnimTexOffsets, uMAX }; const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" }; -const char *SamplerName[sMAX] = { "sDiffuse", "sShadow" }; +const char *SamplerName[sMAX] = { "sDiffuse", "sShadow", "sEnvironment" }; const char *UniformName[uMAX] = { "uType", "uCaustics", "uTime", "uViewProj", "uViewInv", "uModel", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightPos", "uLightColor", "uLightTarget", "uAnimTexRanges", "uAnimTexOffsets" }; struct Shader { GLuint ID; GLint uID[uMAX]; - enum : GLint { SPRITE = 0, ROOM = 1, ENTITY = 2, FLASH = 3, DOWNSAMPLE = 10 }; + enum : GLint { SPRITE = 0, FLASH = 1, ROOM = 2, ENTITY = 3, MIRROR = 4, DOWNSAMPLE = 10 }; Shader(const char *text, const char *defines = "") { #ifdef MOBILE diff --git a/src/texture.h b/src/texture.h index 74ae9f5..77892c2 100644 --- a/src/texture.h +++ b/src/texture.h @@ -7,36 +7,41 @@ struct Texture { GLuint ID; int width, height; bool depth; + bool cube; Texture *dummy; - Texture(int width, int height, bool depth, void *data = NULL) : width(width), height(height), dummy(NULL) { + Texture(int width, int height, bool depth, bool cube, void *data = NULL) : width(width), height(height), cube(cube), dummy(NULL) { glGenTextures(1, &ID); bind(0); - int filter = 1; + bool filter = true; if (depth && !Core::support.depthTexture) depth = false; this->depth = depth; + GLenum target = cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; + GLint format = depth ? GL_DEPTH_COMPONENT : GL_RGBA; + if (depth) { if (Core::support.shadowSampler) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); } else - filter = 0; + filter = false; + } + + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter ? GL_LINEAR : GL_NEAREST); + + for (int i = 0; i < 6; i++) { + glTexImage2D(cube ? (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i) : GL_TEXTURE_2D, 0, format, width, height, 0, format, depth ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE, data); + if (!cube) break; } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter ? GL_LINEAR : GL_NEAREST); - - GLint format = depth ? GL_DEPTH_COMPONENT : GL_RGBA; - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, depth ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE, data); - if (depth) - dummy = new Texture(width, height, false, NULL); // some drivers can't render to texture without color target, create dummy color target for fix it + dummy = new Texture(width, height, false, false, NULL); // some drivers can't render to texture without color target, create dummy color target for fix it } virtual ~Texture() { @@ -46,12 +51,12 @@ struct Texture { void bind(int sampler) { glActiveTexture(GL_TEXTURE0 + sampler); - glBindTexture(GL_TEXTURE_2D, ID); + glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID); } - static void unbind(int sampler) { + void unbind(int sampler) { glActiveTexture(GL_TEXTURE0 + sampler); - glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, 0); } }; diff --git a/src/trigger.h b/src/trigger.h index 6294ccd..ed16560 100644 --- a/src/trigger.h +++ b/src/trigger.h @@ -1,6 +1,7 @@ #ifndef H_TRIGGER #define H_TRIGGER +#include "core.h" #include "controller.h" #include "sprite.h" @@ -287,4 +288,26 @@ struct Bridge : Trigger { } }; +struct Crystal : Controller { + Texture *environment; + + Crystal(TR::Level *level, int entity) : Controller(level, entity) { + environment = new Texture(128, 128, false, true); + } + + virtual ~Crystal() { + delete environment; + } + + virtual void render(Frustum *frustum, MeshBuilder *mesh) { + Shader *sh = Core::active.shader; + sh->setParam(uType, Shader::MIRROR); + sh->setParam(uColor, vec4(0.4f, 0.4f, 16.0f, 1.0f)); // blue color dodge + environment->bind(sEnvironment); + Controller::render(frustum, mesh); + environment->unbind(sEnvironment); + sh->setParam(uType, Shader::ENTITY); + } +}; + #endif \ No newline at end of file