From e729c53e3c81fad7ff1c9be63a7aa6d919231e26 Mon Sep 17 00:00:00 2001 From: austin Date: Fri, 25 Mar 2022 16:09:18 -0400 Subject: [PATCH] Good first pass at anime outline shader --- assets/Data/creatures/human.json | 3 +- assets/Data/items.json | 6 +- assets/Shaders/anime/compositeAnimeOutline.fs | 30 ++++ assets/Shaders/anime/compositeAnimeOutline.vs | 8 ++ assets/Shaders/anime/outlineNormals.fs | 134 ++++++++++++++++++ assets/Shaders/anime/outlineNormals.vs | 10 ++ .../Shaders/anime/outlineNormalsColorful.fs | 45 ++++++ .../Shaders/anime/outlineNormalsColorful.vs | 10 ++ assets/Shaders/anime/renderNormals.fs | 8 +- assets/Shaders/anime/renderNormals.vs | 25 ++-- assets/Shaders/oit/composite.fs | 9 +- assets/Shaders/oit/composite.vs | 3 +- .../electrosphere/engine/LoadingThread.java | 1 + .../entity/EntityDataStrings.java | 1 + .../entity/types/creature/CreatureUtils.java | 3 + .../entity/types/item/ItemUtils.java | 3 + .../server/terrain/generation/TerrainGen.java | 116 +++++++-------- .../java/electrosphere/renderer/Mesh.java | 4 +- .../renderer/RenderingEngine.java | 112 +++++++++++++-- .../framebuffer/FramebufferUtils.java | 15 ++ 20 files changed, 451 insertions(+), 95 deletions(-) create mode 100644 assets/Shaders/anime/compositeAnimeOutline.fs create mode 100644 assets/Shaders/anime/compositeAnimeOutline.vs create mode 100644 assets/Shaders/anime/outlineNormals.fs create mode 100644 assets/Shaders/anime/outlineNormals.vs create mode 100644 assets/Shaders/anime/outlineNormalsColorful.fs create mode 100644 assets/Shaders/anime/outlineNormalsColorful.vs diff --git a/assets/Data/creatures/human.json b/assets/Data/creatures/human.json index 06a64465..034cadc7 100644 --- a/assets/Data/creatures/human.json +++ b/assets/Data/creatures/human.json @@ -56,7 +56,8 @@ "GRAVITY", "TARGETABLE", "CAN_EQUIP", - "INVENTORY" + "INVENTORY", + "OUTLINE" ], "visualAttributes" : [], "movementSystems" : [ diff --git a/assets/Data/items.json b/assets/Data/items.json index e1768a3d..4e451f1f 100644 --- a/assets/Data/items.json +++ b/assets/Data/items.json @@ -30,7 +30,8 @@ "GRAVITY", "BLENDER_TRANSFORM", "MELEE", - "TARGETABLE" + "TARGETABLE", + "OUTLINE" ], "equipClass" : "weapon", "idleAnim" : "Sword|Idle", @@ -55,7 +56,8 @@ "tokens" : [ "GRAVITY", "RANGED", - "TARGETABLE" + "TARGETABLE", + "OUTLINE" ], "equipClass" : "weapon", "collidable": { diff --git a/assets/Shaders/anime/compositeAnimeOutline.fs b/assets/Shaders/anime/compositeAnimeOutline.fs new file mode 100644 index 00000000..67f60c44 --- /dev/null +++ b/assets/Shaders/anime/compositeAnimeOutline.fs @@ -0,0 +1,30 @@ +#version 420 core + +// shader outputs +layout (location = 0) out vec4 frag; + +// color accumulation buffer +layout (binding = 0) uniform sampler2D texture; + +void main(){ + // fragment coordination + ivec2 coords = ivec2(gl_FragCoord.xy); + + // fragment color + vec4 color = texelFetch(texture, coords, 0); + + float val = color.r; + + // if(color.r < 0.5){z + // discard; + // } + + vec4 outColor = vec4(0); + + if(val == 1){ + outColor = vec4(0,0,0,1); + // outColor.a = 1; + } + + frag = outColor; +} \ No newline at end of file diff --git a/assets/Shaders/anime/compositeAnimeOutline.vs b/assets/Shaders/anime/compositeAnimeOutline.vs new file mode 100644 index 00000000..166cef5f --- /dev/null +++ b/assets/Shaders/anime/compositeAnimeOutline.vs @@ -0,0 +1,8 @@ +#version 420 core + +// shader inputs +layout (location = 0) in vec3 position; + +void main(){ + gl_Position = vec4(position, 1.0f); +} \ No newline at end of file diff --git a/assets/Shaders/anime/outlineNormals.fs b/assets/Shaders/anime/outlineNormals.fs new file mode 100644 index 00000000..82b026d0 --- /dev/null +++ b/assets/Shaders/anime/outlineNormals.fs @@ -0,0 +1,134 @@ +#version 330 core +out vec4 FragColor; + +in vec2 TexCoords; + +uniform sampler2D screenTexture; + +const float offset = 1.0 / 2000.0; + +int posToIndex(int x, int y); +float calculateAveragedEdge(int x, int y, vec3 sT[25]); + +void main(){ + vec2 offsets[25] = vec2[25]( + vec2(-2 * offset, 2 * offset), + vec2(-2 * offset, 1 * offset), + vec2(-2 * offset, 0 * offset), + vec2(-2 * offset, -1 * offset), + vec2(-2 * offset, -2 * offset), + vec2(-1 * offset, 2 * offset), + vec2(-1 * offset, 1 * offset), + vec2(-1 * offset, 0 * offset), + vec2(-1 * offset, -1 * offset), + vec2(-1 * offset, -2 * offset), + vec2( 0 * offset, 2 * offset), + vec2( 0 * offset, 1 * offset), + vec2( 0 * offset, 0 * offset), + vec2( 0 * offset, -1 * offset), + vec2( 0 * offset, -2 * offset), + vec2( 1 * offset, 2 * offset), + vec2( 1 * offset, 1 * offset), + vec2( 1 * offset, 0 * offset), + vec2( 1 * offset, -1 * offset), + vec2( 1 * offset, -2 * offset), + vec2( 2 * offset, 2 * offset), + vec2( 2 * offset, 1 * offset), + vec2( 2 * offset, 0 * offset), + vec2( 2 * offset, -1 * offset), + vec2( 2 * offset, -2 * offset) + ); + // vec2 offsets[9] = vec2[]( + // vec2(-offset, offset), // top-left + // vec2( 0.0f, offset), // top-center + // vec2( offset, offset), // top-right + // vec2(-offset, 0.0f), // center-left + // vec2( 0.0f, 0.0f), // center-center + // vec2( offset, 0.0f), // center-right + // vec2(-offset, -offset), // bottom-left + // vec2( 0.0f, -offset), // bottom-center + // vec2( offset, -offset) // bottom-right + // ); + + // float kernel[9] = float[]( + // -1, -1, -1, + // -1, 9, -1, + // -1, -1, -1 + // ); + + vec3 sT[25]; + for(int x = 0; x < 5; x++){ + for(int y = 0; y < 5; y++){ + sT[x * 5 + y] = texture(screenTexture, TexCoords.st + offsets[x * 5 + y]).xyz; + } + } + // vec3 Gx = (-sT[0] + sT[2]) + 2 * (-sT[3] + sT[5]) + (-sT[6] + sT[8]); + // vec3 Gy = (sT[0] + 2 * sT[1] + sT[2]) - (sT[6] + 2 * sT[7] + sT[8]); + // vec3 G = sqrt(Gx * Gx + Gy * Gy); + // float averaged = (G.x + G.y + G.z)/3.0; + float vals[9]; + for(int x = 0; x < 3; x++){ + for(int y = 0; y < 3; y++){ + vals[x * 3 + y] = calculateAveragedEdge(x,y,sT); + } + } + + float rVal = 0; + float cutoff1 = 0.6; + float cutoff2 = 0.1; + float cutoff3 = 0.5; + + float surroundAvg = (vals[0] + vals[2] + vals[6] + vals[8])/4.0; + + if( + //center + vals[4] > cutoff1 && + surroundAvg > cutoff3 + // //plus + // vals[1] > cutoff2 && + // vals[3] > cutoff2 && + // vals[5] > cutoff2 && + // vals[7] > cutoff2 //&& + // // //diag + // vals[0] < cutoff3 && + // vals[2] < cutoff3 && + // vals[6] < cutoff3 && + // vals[8] < cutoff3 + ){ + rVal = min(vals[4],1.0); + } + + // rVal = calculateAveragedEdge(1,1,sT); + // if(rVal < 0.8){ + // rVal = 0; + // } + // vec3 col = vec3(0.0); + // for(int i = 0; i < 9; i++){ + // col += sampleTex[i] * kernel[i]; + // } + + + FragColor = vec4(rVal,rVal,rVal,1); +} + +float calculateAveragedEdge(int x, int y, vec3 sT[25]){ + //compute sobel kernel + vec3 Gx = + (-sT[posToIndex(x,y) + 0] + sT[posToIndex(x,y) + 2]) + + 2 * (-sT[posToIndex(x,y) + 5] + sT[posToIndex(x,y) + 7]) + + (-sT[posToIndex(x,y) + 10] + sT[posToIndex(x,y)+ 12]); + vec3 Gy = + (sT[posToIndex(x,y) + 0] + 2 * sT[posToIndex(x,y) + 1] + sT[posToIndex(x,y) + 2]) - + (sT[posToIndex(x,y) + 10] + 2 * sT[posToIndex(x,y)+ 11] + sT[posToIndex(x,y) + 12]); + vec3 G = sqrt(Gx * Gx + Gy * Gy); + + //compute laplacian kernel + vec3 L = sT[posToIndex(x,y) + 1] + sT[posToIndex(x,y) + 5] - 4 * sT[posToIndex(x,y) + 6] + sT[posToIndex(x,y) + 7] + sT[posToIndex(x,y) + 11]; + + float averaged = abs(G.x + G.y + G.z)/3.0; + return averaged; +} + +int posToIndex(int x, int y){ + return x * 5 + y; +} diff --git a/assets/Shaders/anime/outlineNormals.vs b/assets/Shaders/anime/outlineNormals.vs new file mode 100644 index 00000000..addab705 --- /dev/null +++ b/assets/Shaders/anime/outlineNormals.vs @@ -0,0 +1,10 @@ +#version 330 core +layout (location = 0) in vec2 aPos; +layout (location = 1) in vec2 aTexCoords; + +out vec2 TexCoords; + +void main(){ + gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); + TexCoords = aTexCoords; +} \ No newline at end of file diff --git a/assets/Shaders/anime/outlineNormalsColorful.fs b/assets/Shaders/anime/outlineNormalsColorful.fs new file mode 100644 index 00000000..fe2a5b2a --- /dev/null +++ b/assets/Shaders/anime/outlineNormalsColorful.fs @@ -0,0 +1,45 @@ +#version 330 core +out vec4 FragColor; + +in vec2 TexCoords; + +uniform sampler2D screenTexture; + +const float offset = 1.0 / 500.0; + +void main(){ + + vec2 offsets[9] = vec2[]( + vec2(-offset, offset), // top-left + vec2( 0.0f, offset), // top-center + vec2( offset, offset), // top-right + vec2(-offset, 0.0f), // center-left + vec2( 0.0f, 0.0f), // center-center + vec2( offset, 0.0f), // center-right + vec2(-offset, -offset), // bottom-left + vec2( 0.0f, -offset), // bottom-center + vec2( offset, -offset) // bottom-right + ); + + // float kernel[9] = float[]( + // -1, -1, -1, + // -1, 9, -1, + // -1, -1, -1 + // ); + + vec3 sT[9]; + for(int i = 0; i < 9; i++) + { + sT[i] = vec3(texture(screenTexture, TexCoords.st + offsets[i])); + } + vec3 Gx = (-sT[0] + sT[2]) + 2 * (-sT[3] + sT[5]) + (-sT[6] + sT[8]); + vec3 Gy = (sT[0] + 2 * sT[1] + sT[2]) - (sT[6] + 2 * sT[7] + sT[8]); + vec3 G = sqrt(Gx * Gx + Gy * Gy); + // vec3 col = vec3(0.0); + // for(int i = 0; i < 9; i++){ + // col += sampleTex[i] * kernel[i]; + // } + + + FragColor = vec4(G,1); +} \ No newline at end of file diff --git a/assets/Shaders/anime/outlineNormalsColorful.vs b/assets/Shaders/anime/outlineNormalsColorful.vs new file mode 100644 index 00000000..addab705 --- /dev/null +++ b/assets/Shaders/anime/outlineNormalsColorful.vs @@ -0,0 +1,10 @@ +#version 330 core +layout (location = 0) in vec2 aPos; +layout (location = 1) in vec2 aTexCoords; + +out vec2 TexCoords; + +void main(){ + gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); + TexCoords = aTexCoords; +} \ No newline at end of file diff --git a/assets/Shaders/anime/renderNormals.fs b/assets/Shaders/anime/renderNormals.fs index 59633e31..5ea323dc 100644 --- a/assets/Shaders/anime/renderNormals.fs +++ b/assets/Shaders/anime/renderNormals.fs @@ -1,6 +1,6 @@ #version 330 core -out vec4 FragColor; +out vec3 FragColor; in vec3 FragPos; @@ -8,8 +8,10 @@ in vec3 Normal; void main(){ - vec3 norm = normalize(Normal); + vec3 norm = normalize(Normal) / 2.0; + norm = vec3(norm.x + 0.5,norm.y + 0.5,norm.z + 0.5); + // float dist = gl_FragDepth; - FragColor = vec4(norm,1.0); + FragColor = norm; } diff --git a/assets/Shaders/anime/renderNormals.vs b/assets/Shaders/anime/renderNormals.vs index 11cd314b..71bddb6e 100644 --- a/assets/Shaders/anime/renderNormals.vs +++ b/assets/Shaders/anime/renderNormals.vs @@ -34,19 +34,22 @@ out vec3 FragPos; void main() { - - - //calculate bone transform - mat4 BoneTransform = (bones[int(aIndex[0])] * aWeights[0]); - BoneTransform = BoneTransform + (bones[int(aIndex[1])] * aWeights[1]); - BoneTransform = BoneTransform + (bones[int(aIndex[2])] * aWeights[2]); - BoneTransform = BoneTransform + (bones[int(aIndex[3])] * aWeights[3]); - - //apply bone transform to position vectors - vec4 FinalVertex = BoneTransform * vec4(aPos, 1.0); - vec4 FinalNormal = BoneTransform * vec4(aNormal, 1.0); + vec4 FinalVertex = vec4(aPos, 1.0); + vec4 FinalNormal = vec4(aNormal, 1.0); + if(hasBones==1){ + //calculate bone transform + mat4 BoneTransform = (bones[int(aIndex[0])] * aWeights[0]); + BoneTransform = BoneTransform + (bones[int(aIndex[1])] * aWeights[1]); + BoneTransform = BoneTransform + (bones[int(aIndex[2])] * aWeights[2]); + BoneTransform = BoneTransform + (bones[int(aIndex[3])] * aWeights[3]); + + + //apply bone transform to position vectors + FinalVertex = BoneTransform * vec4(aPos, 1.0); + FinalNormal = BoneTransform * vec4(aNormal, 1.0); + } //make sure the W component is 1.0 FinalVertex = vec4(FinalVertex.xyz, 1.0); diff --git a/assets/Shaders/oit/composite.fs b/assets/Shaders/oit/composite.fs index 4c367042..3c836f57 100644 --- a/assets/Shaders/oit/composite.fs +++ b/assets/Shaders/oit/composite.fs @@ -13,19 +13,16 @@ layout (binding = 1) uniform sampler2D reveal; const float EPSILON = 0.00001f; // caluclate floating point numbers equality accurately -bool isApproximatelyEqual(float a, float b) -{ +bool isApproximatelyEqual(float a, float b){ return abs(a - b) <= (abs(a) < abs(b) ? abs(b) : abs(a)) * EPSILON; } // get the max value between three values -float max3(vec3 v) -{ +float max3(vec3 v) { return max(max(v.x, v.y), v.z); } -void main() -{ +void main(){ // fragment coordination ivec2 coords = ivec2(gl_FragCoord.xy); diff --git a/assets/Shaders/oit/composite.vs b/assets/Shaders/oit/composite.vs index fa50aa04..166cef5f 100644 --- a/assets/Shaders/oit/composite.vs +++ b/assets/Shaders/oit/composite.vs @@ -3,7 +3,6 @@ // shader inputs layout (location = 0) in vec3 position; -void main() -{ +void main(){ gl_Position = vec4(position, 1.0f); } \ No newline at end of file diff --git a/src/main/java/electrosphere/engine/LoadingThread.java b/src/main/java/electrosphere/engine/LoadingThread.java index af10e380..4fbdec01 100644 --- a/src/main/java/electrosphere/engine/LoadingThread.java +++ b/src/main/java/electrosphere/engine/LoadingThread.java @@ -750,6 +750,7 @@ public class LoadingThread extends Thread { Entity shrine = EntityUtils.spawnDrawableEntity("Models/shrine2.fbx"); EntityUtils.getPosition(shrine).set(15,0,15); EntityUtils.getRotation(shrine).rotationX((float)-Math.PI/2.0f); + shrine.putData(EntityDataStrings.DRAW_OUTLINE, true); // goblin = CreatureUtils.spawnBasicCreature("Goblin"); diff --git a/src/main/java/electrosphere/entity/EntityDataStrings.java b/src/main/java/electrosphere/entity/EntityDataStrings.java index 0d2eddc0..bce356b9 100644 --- a/src/main/java/electrosphere/entity/EntityDataStrings.java +++ b/src/main/java/electrosphere/entity/EntityDataStrings.java @@ -20,6 +20,7 @@ public class EntityDataStrings { public static final String DRAW_TRANSPARENT_PASS = "drawTransparentPass"; public static final String DRAW_CAST_SHADOW = "castShadow"; public static final String DRAW_VOLUMETRIC = "drawVolumetric"; + public static final String DRAW_OUTLINE = "drawOutline"; /* diff --git a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java index 813c5d3e..0ebad6a4 100644 --- a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java +++ b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java @@ -202,6 +202,9 @@ public class CreatureUtils { case "INVENTORY": rVal.putData(EntityDataStrings.NATURAL_INVENTORY,UnrelationalInventoryState.createUnrelationalInventory(10)); break; + case "OUTLINE": + rVal.putData(EntityDataStrings.DRAW_OUTLINE, true); + break; } } //variants diff --git a/src/main/java/electrosphere/entity/types/item/ItemUtils.java b/src/main/java/electrosphere/entity/types/item/ItemUtils.java index a27d124e..65758f90 100644 --- a/src/main/java/electrosphere/entity/types/item/ItemUtils.java +++ b/src/main/java/electrosphere/entity/types/item/ItemUtils.java @@ -109,6 +109,9 @@ public class ItemUtils { case "TARGETABLE": Globals.entityManager.registerTargetableEntity(rVal); break; + case "OUTLINE": + rVal.putData(EntityDataStrings.DRAW_OUTLINE, true); + break; } } if(item.getEquipWhitelist() != null){ diff --git a/src/main/java/electrosphere/game/server/terrain/generation/TerrainGen.java b/src/main/java/electrosphere/game/server/terrain/generation/TerrainGen.java index fe00f5dc..271bd2e1 100644 --- a/src/main/java/electrosphere/game/server/terrain/generation/TerrainGen.java +++ b/src/main/java/electrosphere/game/server/terrain/generation/TerrainGen.java @@ -73,82 +73,82 @@ public class TerrainGen { public static int current_Region_X = 0; public static int current_Region_Y = 0; - public static void main(String args[]){ + // public static void main(String args[]){ - TerrainGenerator tergen = new TerrainGenerator(); - tergen.set_Dimension(DIMENSION); - tergen.set_Lifespan(15000); - tergen.run(); - elevation = tergen.get_Terrain(); + // TerrainGenerator tergen = new TerrainGenerator(); + // tergen.set_Dimension(DIMENSION); + // tergen.set_Lifespan(15000); + // tergen.run(); + // elevation = tergen.get_Terrain(); - elevation = interpolate_Elevation_Raws(elevation); - DIMENSION = DIMENSION * 2; + // elevation = interpolate_Elevation_Raws(elevation); + // DIMENSION = DIMENSION * 2; - elevation = compression_filter(elevation); - elevation = three_halves_filter(elevation); - elevation = smooth_Terrain_Further(elevation); - elevation = small_Kernel_Sharpen(elevation); - elevation = smooth_Terrain_Further(elevation); - elevation = three_halves_filter(elevation); - elevation = small_Kernel_Smooth(elevation); - elevation = small_Kernel_Sharpen(elevation); - elevation = smooth_Terrain_Further(elevation); - elevation = smooth_Terrain_Further(elevation); - elevation = land_exponential_filter(elevation); - elevation = land_exponential_filter(elevation); - elevation = land_exponential_filter(elevation); - elevation = land_exponential_filter(elevation); + // elevation = compression_filter(elevation); + // elevation = three_halves_filter(elevation); + // elevation = smooth_Terrain_Further(elevation); + // elevation = small_Kernel_Sharpen(elevation); + // elevation = smooth_Terrain_Further(elevation); + // elevation = three_halves_filter(elevation); + // elevation = small_Kernel_Smooth(elevation); + // elevation = small_Kernel_Sharpen(elevation); + // elevation = smooth_Terrain_Further(elevation); + // elevation = smooth_Terrain_Further(elevation); + // elevation = land_exponential_filter(elevation); + // elevation = land_exponential_filter(elevation); + // elevation = land_exponential_filter(elevation); + // elevation = land_exponential_filter(elevation); - mountainParsed = new int[DIMENSION][DIMENSION]; - oceanParsed = new int[DIMENSION][DIMENSION]; - continentIdField = new int[DIMENSION][DIMENSION]; + // mountainParsed = new int[DIMENSION][DIMENSION]; + // oceanParsed = new int[DIMENSION][DIMENSION]; + // continentIdField = new int[DIMENSION][DIMENSION]; - mountainParsed = parse_Mountainscapes(elevation); + // mountainParsed = parse_Mountainscapes(elevation); - oceanParsed = parse_Oceans(elevation); + // oceanParsed = parse_Oceans(elevation); - wind_field = map_Wind_Field(); + // wind_field = map_Wind_Field(); - precipitationChart = calculate_Rain_Shadows(elevation,oceanParsed,wind_field); + // precipitationChart = calculate_Rain_Shadows(elevation,oceanParsed,wind_field); - temperatureChart = generate_Temperature_Chart(); + // temperatureChart = generate_Temperature_Chart(); - climateCategory = infer_Climate_Category(); + // climateCategory = infer_Climate_Category(); - determine_Continents(); + // determine_Continents(); - fill_Continents(); + // fill_Continents(); - //for display tbh - anchor_To_Real_Region(); + // //for display tbh + // anchor_To_Real_Region(); - display_toggle = 0; + // display_toggle = 0; - create_Frame(); + // create_Frame(); - while(true){ - if(brightness_increasing){ - if(brightness < 100){ - brightness++; - } else { - } - } else { - if(brightness > 0){ - brightness--; - } else { - brightness_increasing = true; - display_toggle++; - if(display_toggle > 1){ - display_toggle = 0; - } - } - } - frame.repaint(); - Utilities.sleep(10); - } - } + // while(true){ + // if(brightness_increasing){ + // if(brightness < 100){ + // brightness++; + // } else { + // } + // } else { + // if(brightness > 0){ + // brightness--; + // } else { + // brightness_increasing = true; + // display_toggle++; + // if(display_toggle > 1){ + // display_toggle = 0; + // } + // } + // } + // frame.repaint(); + // Utilities.sleep(10); + // } + // } public TerrainModel generateModel(){ TerrainModel rVal; diff --git a/src/main/java/electrosphere/renderer/Mesh.java b/src/main/java/electrosphere/renderer/Mesh.java index 4d703681..4200b433 100644 --- a/src/main/java/electrosphere/renderer/Mesh.java +++ b/src/main/java/electrosphere/renderer/Mesh.java @@ -852,10 +852,10 @@ public class Mesh { incrementer++; } } else { - glUniform1i(Globals.renderingEngine.getActiveShader().shaderVertexHasBonesLoc, 0); + glUniform1i(glGetUniformLocation(Globals.renderingEngine.getActiveShader().shaderProgram, "hasBones"), 0); } } else { - glUniform1i(Globals.renderingEngine.getActiveShader().shaderVertexHasBonesLoc, 0); + glUniform1i(glGetUniformLocation(Globals.renderingEngine.getActiveShader().shaderProgram, "hasBones"), 0); } diff --git a/src/main/java/electrosphere/renderer/RenderingEngine.java b/src/main/java/electrosphere/renderer/RenderingEngine.java index 2ac5eb2f..cca8b52f 100644 --- a/src/main/java/electrosphere/renderer/RenderingEngine.java +++ b/src/main/java/electrosphere/renderer/RenderingEngine.java @@ -177,6 +177,18 @@ public class RenderingEngine { // static Framebuffer volumeVerticalBackfaceBuffer; // static Texture volumeVerticalFrontfaceTexture; // static Framebuffer volumeVerticalFrontfaceBuffer; + + /* + Post processing effects (ie kernels) textures, framebuffers, shaders + */ + static Texture normalsOutlineTexture; + static Framebuffer normalsOutlineFrambuffer; + static ShaderProgram normalsOutlineShader; + + /* + compositing functions + */ + static ShaderProgram compositeAnimeOutline; // public static boolean renderHitboxes = false; // public static boolean renderPhysics = false; @@ -187,7 +199,7 @@ public class RenderingEngine { ShaderProgram activeProgram; - static int outputFramebuffer = 0; + static int outputFramebuffer = 6; public void createOpenglContext(){ @@ -312,7 +324,8 @@ public class RenderingEngine { static ShaderProgram renderNormalsShader; */ gameImageNormalsTexture = FramebufferUtils.generateScreenTextureColor(Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); - gameImageNormalsFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, gameImageNormalsTexture); + Texture gameImageNormalsDepthTexture = FramebufferUtils.generateScreenTextureDepth(Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); + gameImageNormalsFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, gameImageNormalsTexture, gameImageNormalsDepthTexture); renderNormalsShader = ShaderProgram.loadSpecificShader("Shaders/anime/renderNormals.vs", "Shaders/anime/renderNormals.fs"); // @@ -328,6 +341,24 @@ public class RenderingEngine { //projection matrices nearVolumeProjectionMatrix.setPerspective((float)(Globals.verticalFOV * Math.PI /180.0f), (float)Globals.WINDOW_WIDTH / (float)Globals.WINDOW_HEIGHT, 0.1f, 100); + // + //Postprocessing textures and buffers + // + /* + static Texture normalsOutlineTexture; + static Framebuffer normalsOutlineFrambuffer; + static ShaderProgram normalsOutlineShader; + */ + normalsOutlineTexture = FramebufferUtils.generateScreenTextureColorAlpha(Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); + normalsOutlineFrambuffer = FramebufferUtils.generateScreenTextureFramebuffer(Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, normalsOutlineTexture); + // normalsOutlineShader = ShaderProgram.loadSpecificShader("Shaders/anime/outlineNormals.vs", "Shaders/anime/outlineNormals.fs"); + Globals.assetManager.addShaderToQueue("Shaders/anime/outlineNormals.vs", "Shaders/anime/outlineNormals.fs"); + + // + //Compositing shaders + // + compositeAnimeOutline = ShaderProgram.loadSpecificShader("Shaders/anime/compositeAnimeOutline.vs", "Shaders/anime/compositeAnimeOutline.fs"); + //instantiate light manager lightManager = new LightManager(); @@ -432,7 +463,8 @@ public class RenderingEngine { if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT){ renderGameContent(); renderDebugContent(); - renderNormals(); + renderNormalsForOutline(); + applyKernelsAndPostprocessing(); compositeGameImage(); } @@ -822,7 +854,7 @@ public class RenderingEngine { } } - static void renderNormals(){ + static void renderNormalsForOutline(){ /* gameImageNormalsTexture; @@ -833,8 +865,11 @@ public class RenderingEngine { //bind screen fbo gameImageNormalsFramebuffer.bind(); glEnable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthFunc(GL_LESS); glDepthMask(true); + glViewport(0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); /// @@ -855,6 +890,7 @@ public class RenderingEngine { if( (boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && currentEntity.getData(EntityDataStrings.DRAW_SOLID_PASS) != null && + currentEntity.getData(EntityDataStrings.DRAW_OUTLINE) != null && drawPoint(cameraPos,new Vector3f((float)position.x,(float)position.y,(float)position.z)) ){ //fetch actor @@ -874,9 +910,41 @@ public class RenderingEngine { } } + static void applyKernelsAndPostprocessing(){ + // + // Outline normals + // + glDepthFunc(GL_ALWAYS); + glDepthMask(false); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + normalsOutlineFrambuffer.bind(); + ShaderProgram program = Globals.assetManager.fetchShader("Shaders/anime/outlineNormals.vs", null, "Shaders/anime/outlineNormals.fs"); + if(program != null){ + Globals.renderingEngine.setActiveShader(program); + + glBindVertexArray(screenTextureVAO); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, gameImageNormalsTexture.getTexturePointer()); + + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + } + } + static void compositeGameImage(){ // - // Pass Three: Composite transparency on top of solids + //Setup to render screen textures & bind screen framebuffer // glDepthFunc(GL_ALWAYS); // glDepthMask(false); @@ -884,10 +952,33 @@ public class RenderingEngine { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); screenFramebuffer.bind(); - Globals.renderingEngine.setActiveShader(oitCompositeProgram); - + glBindVertexArray(screenTextureVAO); + + // + //Draw anime outline + // + Globals.renderingEngine.setActiveShader(compositeAnimeOutline); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, normalsOutlineTexture.getTexturePointer()); + + glDrawArrays(GL_TRIANGLES, 0, 6); + + // + //Composite transparency on top of solids + // + Globals.renderingEngine.setActiveShader(oitCompositeProgram); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE1); @@ -903,6 +994,9 @@ public class RenderingEngine { glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); + + + } static void renderScreenFramebuffer(){ @@ -948,9 +1042,7 @@ public class RenderingEngine { } else if(outputFramebuffer == 5){ glBindTexture(GL_TEXTURE_2D, gameImageNormalsTexture.getTexturePointer()); } else if(outputFramebuffer == 6){ - Globals.renderingEngine.setActiveShader(drawChannel); - glUniform1f(glGetUniformLocation(Globals.renderingEngine.getActiveShader().shaderProgram, "channel"),0); - glBindTexture(GL_TEXTURE_2D, transparencyRevealageTexture.getTexturePointer()); + glBindTexture(GL_TEXTURE_2D, normalsOutlineTexture.getTexturePointer()); } else if(outputFramebuffer == 7){ Globals.renderingEngine.setActiveShader(drawChannel); glUniform1f(glGetUniformLocation(Globals.renderingEngine.getActiveShader().shaderProgram, "channel"),4); diff --git a/src/main/java/electrosphere/renderer/framebuffer/FramebufferUtils.java b/src/main/java/electrosphere/renderer/framebuffer/FramebufferUtils.java index 34b32210..f6ade804 100644 --- a/src/main/java/electrosphere/renderer/framebuffer/FramebufferUtils.java +++ b/src/main/java/electrosphere/renderer/framebuffer/FramebufferUtils.java @@ -78,6 +78,21 @@ public class FramebufferUtils { return texture; } + public static Texture generateScreenTextureColorAlpha(int width, int height){ + int texturePtr = glGenTextures(); + glBindTexture(GL_TEXTURE_2D,texturePtr); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + //these make sure the texture actually clamps to the borders of the quad + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + Texture texture = new Texture(texturePtr); + + return texture; + } + public static Texture generateScreenTextureDepth(int width, int height){ int texturePtr = glGenTextures(); glBindTexture(GL_TEXTURE_2D,texturePtr);