diff --git a/.gitignore b/.gitignore
index 9491a2f..bac85c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -360,4 +360,5 @@ MigrationBackup/
.ionide/
# Fody - auto-generated XML schema
-FodyWeavers.xsd
\ No newline at end of file
+FodyWeavers.xsd
+/cw 9/textures/test
diff --git a/cw 9/grk-cw9.rc b/cw 9/grk-cw9.rc
new file mode 100644
index 0000000..58dec08
Binary files /dev/null and b/cw 9/grk-cw9.rc differ
diff --git a/cw 9/grk-cw9.vcxproj b/cw 9/grk-cw9.vcxproj
index 2794e1d..f9c4f7c 100644
--- a/cw 9/grk-cw9.vcxproj
+++ b/cw 9/grk-cw9.vcxproj
@@ -44,6 +44,8 @@
+
+
diff --git a/cw 9/resource.h b/cw 9/resource.h
new file mode 100644
index 0000000..415e221
--- /dev/null
+++ b/cw 9/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by grk-cw9.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/cw 9/shaders/shader_bubble.frag b/cw 9/shaders/shader_bubble.frag
new file mode 100644
index 0000000..e20b1bc
--- /dev/null
+++ b/cw 9/shaders/shader_bubble.frag
@@ -0,0 +1,303 @@
+#version 430 core
+uniform vec3 iResolution;
+//uniform vec3 cameraPos;
+//uniform vec3 cameraDir;
+uniform mat3 camMat;
+uniform sampler2D iChannel1;
+uniform samplerCube iChannel0;
+uniform float time;
+
+
+//in float iDate;
+in vec4 bubblePosition;
+
+out vec4 fragColor;
+
+/*
+ Fast Thin-Film Interference
+
+ This is a performance-optimized version of my previous
+ thin-film interference shader here: https://www.shadertoy.com/view/XddXRj
+ This version also fixes a platform-specific bug and has
+ a few other tweaks as well.
+
+ Thin-film interference and chromatic dispersion are simulated at
+ six different wavelengths and then downsampled to RGB.
+*/
+
+// To see just the reflection (no refraction/transmission) uncomment this next line:
+//#define REFLECTANCE_ONLY
+
+// performance and raymarching options
+#define INTERSECTION_PRECISION 0.01 // raymarcher intersection precision
+#define ITERATIONS 20 // max number of iterations
+#define AA_SAMPLES 1 // anti aliasing samples
+#define BOUND 6.0 // cube bounds check
+#define DIST_SCALE 0.9 // scaling factor for raymarching position update
+
+// optical properties
+#define DISPERSION 0.05 // dispersion amount
+#define IOR 0.9 // base IOR value specified as a ratio
+#define THICKNESS_SCALE 32.0 // film thickness scaling factor
+#define THICKNESS_CUBEMAP_SCALE 0.1 // film thickness cubemap scaling factor
+#define REFLECTANCE_SCALE 3.0 // reflectance scaling factor
+#define REFLECTANCE_GAMMA_SCALE 2.0 // reflectance gamma scaling factor
+#define FRESNEL_RATIO 0.7 // fresnel weight for reflectance
+#define SIGMOID_CONTRAST 8.0 // contrast enhancement
+
+#define TWO_PI 6.28318530718
+#define WAVELENGTHS 6 // number of wavelengths, not a free parameter
+
+// iq's cubemap function
+vec3 fancyCube( sampler2D sam, in vec3 d, in float s, in float b )
+{
+ vec3 colx = textureLod( sam, 0.5 + s*d.yz/d.x, b ).xyz;
+ vec3 coly = textureLod( sam, 0.5 + s*d.zx/d.y, b ).xyz;
+ vec3 colz = textureLod( sam, 0.5 + s*d.xy/d.z, b ).xyz;
+
+ vec3 n = d*d;
+
+ return (colx*n.x + coly*n.y + colz*n.z)/(n.x+n.y+n.z);
+}
+
+// iq's 3D noise function
+float hash( float n ){
+ return fract(sin(n)*43758.5453);
+}
+
+float noise( in vec3 x ) {
+ vec3 p = floor(x);
+ vec3 f = fract(x);
+
+ f = f*f*(3.0-2.0*f);
+ float n = p.x + p.y*57.0 + 113.0*p.z;
+ return mix(mix(mix( hash(n+ 0.0), hash(n+ 1.0),f.x),
+ mix( hash(n+ 57.0), hash(n+ 58.0),f.x),f.y),
+ mix(mix( hash(n+113.0), hash(n+114.0),f.x),
+ mix( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z);
+}
+
+vec3 noise3(vec3 x) {
+ return vec3( noise(x+vec3(123.456,.567,.37)),
+ noise(x+vec3(.11,47.43,19.17)),
+ noise(x) );
+}
+
+// a sphere with a little bit of warp
+float sdf( vec3 p ) {
+ vec3 n = vec3(sin(time * 0.5), sin(time * 0.3), cos(time * 0.2));
+ vec3 q = 0.1 * (noise3(p + n) - 0.5);
+
+ return length(q + p) - 3.5;
+}
+
+vec3 fresnel( vec3 rd, vec3 norm, vec3 n2 ) {
+ vec3 r0 = pow((1.0-n2)/(1.0+n2), vec3(2));
+ return r0 + (1. - r0)*pow(clamp(1. + dot(rd, norm), 0.0, 1.0), 5.);
+}
+
+vec3 calcNormal( in vec3 pos ) {
+ const float eps = INTERSECTION_PRECISION;
+
+ const vec3 v1 = vec3( 1.0,-1.0,-1.0);
+ const vec3 v2 = vec3(-1.0,-1.0, 1.0);
+ const vec3 v3 = vec3(-1.0, 1.0,-1.0);
+ const vec3 v4 = vec3( 1.0, 1.0, 1.0);
+
+ return normalize( v1*sdf( pos + v1*eps ) +
+ v2*sdf( pos + v2*eps ) +
+ v3*sdf( pos + v3*eps ) +
+ v4*sdf( pos + v4*eps ) );
+}
+
+#define GAMMA_CURVE 50.0
+#define GAMMA_SCALE 4.5
+vec3 filmic_gamma(vec3 x) {
+ return log(GAMMA_CURVE * x + 1.0) / GAMMA_SCALE;
+}
+
+vec3 filmic_gamma_inverse(vec3 y) {
+ return (1.0 / GAMMA_CURVE) * (exp(GAMMA_SCALE * y) - 1.0);
+}
+
+// sample weights for the cubemap given a wavelength i
+// room for improvement in this function
+#define GREEN_WEIGHT 2.8
+vec3 texCubeSampleWeights(float i) {
+ vec3 w = vec3((1.0 - i) * (1.0 - i), GREEN_WEIGHT * i * (1.0 - i), i * i);
+ return w / dot(w, vec3(1.0));
+}
+
+vec3 sampleCubeMap(vec3 i, vec3 rd) {
+ vec3 col = textureLod(iChannel0, rd * vec3(1.0,-1.0,1.0), 0.0).xyz;
+ return vec3(
+ dot(texCubeSampleWeights(i.x), col),
+ dot(texCubeSampleWeights(i.y), col),
+ dot(texCubeSampleWeights(i.z), col)
+ );
+}
+
+vec3 sampleCubeMap(vec3 i, vec3 rd0, vec3 rd1, vec3 rd2) {
+ vec3 col0 = textureLod(iChannel0, rd0 * vec3(1.0,-1.0,1.0), 0.0).xyz;
+ vec3 col1 = textureLod(iChannel0, rd1 * vec3(1.0,-1.0,1.0), 0.0).xyz;
+ vec3 col2 = textureLod(iChannel0, rd2 * vec3(1.0,-1.0,1.0), 0.0).xyz;
+ return vec3(
+ dot(texCubeSampleWeights(i.x), col0),
+ dot(texCubeSampleWeights(i.y), col1),
+ dot(texCubeSampleWeights(i.z), col2)
+ );
+}
+
+
+
+vec3 sampleWeights(float i) {
+ return vec3((1.0 - i) * (1.0 - i), GREEN_WEIGHT * i * (1.0 - i), i * i);
+}
+
+vec3 resample(vec3 wl0, vec3 wl1, vec3 i0, vec3 i1) {
+ vec3 w0 = sampleWeights(wl0.x);
+ vec3 w1 = sampleWeights(wl0.y);
+ vec3 w2 = sampleWeights(wl0.z);
+ vec3 w3 = sampleWeights(wl1.x);
+ vec3 w4 = sampleWeights(wl1.y);
+ vec3 w5 = sampleWeights(wl1.z);
+
+ return i0.x * w0 + i0.y * w1 + i0.z * w2
+ + i1.x * w3 + i1.y * w4 + i1.z * w5;
+}
+
+// downsample to RGB
+vec3 resampleColor(vec3[WAVELENGTHS] rds, vec3 refl0, vec3 refl1, vec3 wl0, vec3 wl1) {
+
+
+ #ifdef REFLECTANCE_ONLY
+ vec3 intensity0 = refl0;
+ vec3 intensity1 = refl1;
+ #else
+ vec3 cube0 = sampleCubeMap(wl0, rds[0], rds[1], rds[2]);
+ vec3 cube1 = sampleCubeMap(wl1, rds[3], rds[4], rds[5]);
+
+ vec3 intensity0 = filmic_gamma_inverse(cube0) + refl0;
+ vec3 intensity1 = filmic_gamma_inverse(cube1) + refl1;
+ #endif
+ vec3 col = resample(wl0, wl1, intensity0, intensity1);
+
+ return 1.4 * filmic_gamma(col / float(WAVELENGTHS));
+}
+
+vec3 resampleColorSimple(vec3 rd, vec3 wl0, vec3 wl1) {
+ vec3 cube0 = sampleCubeMap(wl0, rd);
+ vec3 cube1 = sampleCubeMap(wl1, rd);
+
+ vec3 intensity0 = filmic_gamma_inverse(cube0);
+ vec3 intensity1 = filmic_gamma_inverse(cube1);
+ vec3 col = resample(wl0, wl1, intensity0, intensity1);
+
+ return 1.4 * filmic_gamma(col / float(WAVELENGTHS));
+}
+
+// compute the wavelength/IOR curve values.
+vec3 iorCurve(vec3 x) {
+ return x;
+}
+
+vec3 attenuation(float filmThickness, vec3 wavelengths, vec3 normal, vec3 rd) {
+ return 0.5 + 0.5 * cos(((THICKNESS_SCALE * filmThickness)/(wavelengths + 1.0)) * dot(normal, rd));
+}
+
+vec3 contrast(vec3 x) {
+ return 1.0 / (1.0 + exp(-SIGMOID_CONTRAST * (x - 0.5)));
+}
+
+void doCamera( out vec3 camPos, out vec3 camTar, in float time, in vec4 m ) {
+ camTar = vec3(0.0,0.0,0.0);
+ if (max(m.z, m.w) <= 0.0) {
+ float an = 1.5 + sin(time * 0.05) * 4.0;
+ camPos = vec3(6.5*sin(an), 0.0 ,6.5*cos(an));
+ } else {
+ float an = 10.0 * m.x - 5.0;
+ camPos = vec3(6.5*sin(an),10.0 * m.y - 5.0,6.5*cos(an));
+ }
+}
+
+mat3 calcLookAtMatrix( in vec3 ro, in vec3 ta, in float roll )
+{
+ vec3 ww = normalize( ta - ro );
+ vec3 uu = normalize( cross(ww,vec3(sin(roll),cos(roll),0.0) ) );
+ vec3 vv = normalize( cross(uu,ww));
+ return mat3( uu, vv, ww );
+}
+
+void main()
+{
+ vec2 p = (-iResolution.xy + 2.0*gl_FragCoord.xy)/iResolution.y;
+ //vec4 m = vec4(iMouse.xy/iResolution.xy, iMouse.zw);
+
+ // camera movement
+ //vec3 ro, ta;
+ //doCamera( ro, ta, iTime, m );
+ //mat3 camMat = calcLookAtMatrix( cameraPos, cameraDir, 0.0 );
+
+ float dh = (0.666 / iResolution.y);
+ const float rads = TWO_PI / float(AA_SAMPLES);
+
+ vec3 col = vec3(0.0);
+
+ vec3 wavelengths0 = vec3(1.0, 0.8, 0.6);
+ vec3 wavelengths1 = vec3(0.4, 0.2, 0.0);
+ vec3 iors0 = IOR + iorCurve(wavelengths0) * DISPERSION;
+ vec3 iors1 = IOR + iorCurve(wavelengths1) * DISPERSION;
+
+ vec3 rds[WAVELENGTHS];
+
+ for (int samp = 0; samp < AA_SAMPLES; samp++) {
+ vec2 dxy = dh * vec2(cos(float(samp) * rads), sin(float(samp) * rads));
+ vec3 rd = normalize(camMat * vec3(p.xy + dxy, 1.5)); // 1.5 is the lens length
+ vec3 pos = bubblePosition.xyz;
+ bool hit = false;
+ for (int j = 0; j < ITERATIONS; j++) {
+ float t = DIST_SCALE * sdf(pos);
+ pos += t * rd;
+ hit = t < INTERSECTION_PRECISION;
+ if ( clamp(pos, -BOUND, BOUND) != pos || hit ) {
+ break;
+ }
+ }
+
+ if (hit) {
+ vec3 normal = calcNormal(pos);
+
+ float filmThickness = fancyCube( iChannel1, normal, THICKNESS_CUBEMAP_SCALE, 0.0 ).x + 0.1;
+
+ vec3 att0 = attenuation(filmThickness, wavelengths0, normal, rd);
+ vec3 att1 = attenuation(filmThickness, wavelengths1, normal, rd);
+
+ vec3 f0 = (1.0 - FRESNEL_RATIO) + FRESNEL_RATIO * fresnel(rd, normal, 1.0 / iors0);
+ vec3 f1 = (1.0 - FRESNEL_RATIO) + FRESNEL_RATIO * fresnel(rd, normal, 1.0 / iors1);
+
+ vec3 rrd = reflect(rd, normal);
+
+ vec3 cube0 = REFLECTANCE_GAMMA_SCALE * att0 * sampleCubeMap(wavelengths0, rrd);
+ vec3 cube1 = REFLECTANCE_GAMMA_SCALE * att1 * sampleCubeMap(wavelengths1, rrd);
+
+ vec3 refl0 = REFLECTANCE_SCALE * filmic_gamma_inverse(mix(vec3(0), cube0, f0));
+ vec3 refl1 = REFLECTANCE_SCALE * filmic_gamma_inverse(mix(vec3(0), cube1, f1));
+
+ rds[0] = refract(rd, normal, iors0.x);
+ rds[1] = refract(rd, normal, iors0.y);
+ rds[2] = refract(rd, normal, iors0.z);
+ rds[3] = refract(rd, normal, iors1.x);
+ rds[4] = refract(rd, normal, iors1.y);
+ rds[5] = refract(rd, normal, iors1.z);
+
+ col += resampleColor(rds, refl0, refl1, wavelengths0, wavelengths1);
+ } else {
+ col += resampleColorSimple(rd, wavelengths0, wavelengths1);
+ }
+
+ }
+
+ col /= float(AA_SAMPLES);
+
+ fragColor = vec4( contrast(col), 1.0 );
+}
\ No newline at end of file
diff --git a/cw 9/shaders/shader_bubble.vert b/cw 9/shaders/shader_bubble.vert
new file mode 100644
index 0000000..48decc2
--- /dev/null
+++ b/cw 9/shaders/shader_bubble.vert
@@ -0,0 +1,19 @@
+#version 430 core
+
+layout(location = 0) in vec3 vertexPosition;
+layout(location = 1) in vec3 vertexNormal;
+layout(location = 2) in vec2 vertexTexCoord;
+
+uniform mat4 transformation;
+//uniform float time;
+
+out vec4 bubblePosition;
+//out float iDate;
+
+void main()
+{
+ bubblePosition = transformation * vec4(vertexPosition, 1.0);
+ //vec3 bubbling = sdf(bubblePosition2.xyz);
+ gl_Position = bubblePosition;
+ //gl_Position = vec4(vertexPosition, 1.0);
+}
diff --git a/cw 9/src/ex_9_1.hpp b/cw 9/src/ex_9_1.hpp
index 0272ade..3e234fb 100644
--- a/cw 9/src/ex_9_1.hpp
+++ b/cw 9/src/ex_9_1.hpp
@@ -89,6 +89,15 @@ std::vector faces = {
"textures/skybox_2/back.jpg",
};
+std::vector facesBubble = {
+ "textures/bubbleSkybox/right.jpg",
+ "textures/bubbleSkybox/left.jpg",
+ "textures/bubbleSkybox/top.jpg",
+ "textures/bubbleSkybox/bottom.jpg",
+ "textures/bubbleSkybox/front.jpg",
+ "textures/bubbleSkybox/back.jpg",
+};
+
namespace texture {
GLuint water;
GLuint rust;
@@ -232,6 +241,8 @@ GLuint programDepth;
GLuint programSkybox;
GLuint programWater;
GLuint skyboxTexture;
+GLuint bubbleTexture0, bubbleTexture1;
+GLuint programBubble;
Core::Shader_Loader shaderLoader;
@@ -274,7 +285,7 @@ glm::vec3 lightPos = glm::vec3(-8, 4, 2);
float lastTime = -1.f;
float deltaTime = 0.f;
-unsigned int loadSkybox(std::vector faces)
+unsigned int loadSkybox(std::vector faces1)
{
unsigned int textureID;
glGenTextures(1, &textureID);
@@ -284,7 +295,7 @@ unsigned int loadSkybox(std::vector faces)
unsigned char* data;
for (unsigned int i = 0; i < 6; i++)
{
- unsigned char* data = SOIL_load_image(faces[i].c_str(), &w, &h, 0, SOIL_LOAD_RGBA);
+ unsigned char* data = SOIL_load_image(faces1[i].c_str(), &w, &h, 0, SOIL_LOAD_RGBA);
glTexImage2D(
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data
@@ -327,8 +338,8 @@ glm::mat4 createCameraMatrix()
void drawSkybox(Core::RenderContext& context, glm::mat4 transformation, GLuint textureID) {
glUseProgram(programSkybox);
glUniformMatrix4fv(glGetUniformLocation(programSkybox, "transformation"), 1, GL_FALSE, (float*)&transformation);
- glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
Core::SetActiveTexture(textureID, "colorTexture", programSkybox, 0);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
Core::DrawContext(context);
}
glm::mat4 createPerspectiveMatrix()
@@ -522,6 +533,28 @@ void drawObjectDepth(Core::RenderContext context, glm::mat4 viewProjectionMatrix
Core::DrawContext(context);
}
+void drawBubble(glm::mat4 transformSphere) {
+ float time = glfwGetTime();
+ glUseProgram(programBubble);
+ glm::mat4 cameraMatrix = createCameraMatrix();
+ glm::mat4 perspectiveMatrix = createPerspectiveMatrix();
+ glm::mat4 viewProjectionMatrix = perspectiveMatrix * cameraMatrix;
+ //glm::mat4 transformation = viewProjectionMatrix * glm::translate(pointlightPos) * glm::scale(glm::vec3(0.1));
+ glm::mat4 bubbleSkyboxViewMatrix = perspectiveMatrix * glm::mat4(glm::mat3(cameraMatrix));
+ glUniformMatrix4fv(glGetUniformLocation(programBubble, "transformation"), 1, GL_FALSE, (float*)&transformSphere);
+ glUniform3f(glGetUniformLocation(programBubble, "iResolution"), WIDTH, HEIGHT, 1.0);
+ glUniform1f(glGetUniformLocation(programBubble, "time"), time);
+ //glUniform3f(glGetUniformLocation(programBubble, "cameraPos"), cameraPos.x, cameraPos.y, cameraPos.z);
+ //glUniform3f(glGetUniformLocation(programBubble, "cameraDir"), cameraDir.x, cameraDir.y, cameraDir.z);
+ glUniformMatrix3fv(glGetUniformLocation(programBubble, "camMat"), 1, GL_FALSE, (float*)&glm::mat3(bubbleSkyboxViewMatrix));
+
+ Core::SetActiveTexture(bubbleTexture0, "iChannel0", programBubble, 1);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, bubbleTexture0);
+ Core::SetActiveTexture(bubbleTexture1, "iChannel1", programBubble, 0);
+ glBindTexture(GL_TEXTURE_2D, bubbleTexture1);
+ Core::DrawContext(sphereContext);
+}
+
void renderShadowapSun() {
float time = glfwGetTime();
@@ -701,9 +734,6 @@ void renderScene(GLFWwindow* window)
drawObjectPBR(sphereContext, glm::translate(pointlightPos) * glm::scale(glm::vec3(0.1)) * glm::eulerAngleY(time / 3) * glm::translate(glm::vec3(4.f, 0, 0)) * glm::scale(glm::vec3(0.3f)), glm::vec3(0.2, 0.7, 0.3), 0.3, 0.0);
- drawObjectPBR(sphereContext,
- glm::translate(pointlightPos) * glm::scale(glm::vec3(0.1)) * glm::eulerAngleY(time / 3) * glm::translate(glm::vec3(4.f, 0, 0)) * glm::eulerAngleY(time) * glm::translate(glm::vec3(1.f, 0, 0)) * glm::scale(glm::vec3(0.1f)),
- glm::vec3(0.5, 0.5, 0.5), 0.7, 0.0);
glm::vec3 spaceshipSide = glm::normalize(glm::cross(spaceshipDir, glm::vec3(0.f, 1.f, 0.f)));
glm::vec3 spaceshipUp = glm::normalize(glm::cross(spaceshipSide, spaceshipDir));
@@ -779,14 +809,13 @@ void renderScene(GLFWwindow* window)
drawObjectColorWater(waterContext, glm::translate(glm::mat4(1.0), glm::vec3(0.0f, -1.7f, 0.0f)), glm::vec4(0.1, 0.1, 0.95, 0.5), time, texture::water);
-
//test depth buffer
/*glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programTest);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthMap);
Core::DrawContext(models::testContext);*/
-
+
glUseProgram(0);
glfwSwapBuffers(window);
}
@@ -837,6 +866,7 @@ void init(GLFWwindow* window)
programTex = shaderLoader.CreateProgram("shaders/shader_tex.vert", "shaders/shader_tex.frag");
programTexPBR = shaderLoader.CreateProgram("shaders/shader_tex_pbr.vert", "shaders/shader_tex_pbr.frag");
programTexPBR_ARM = shaderLoader.CreateProgram("shaders/shader_tex_pbr_arm.vert", "shaders/shader_tex_pbr_arm.frag");
+ programBubble = shaderLoader.CreateProgram("shaders/shader_bubble.vert", "shaders/shader_bubble.frag");
water.readOBJ("./models/plane2.obj");
texture::water = Core::LoadTexture("textures/test.png");
texture::rust = Core::LoadTexture("textures/rust.jpg");
diff --git a/cw 9/textures/bubbleNoise.jpg b/cw 9/textures/bubbleNoise.jpg
new file mode 100644
index 0000000..d876668
Binary files /dev/null and b/cw 9/textures/bubbleNoise.jpg differ
diff --git a/cw 9/textures/bubbleSkybox/back.jpg b/cw 9/textures/bubbleSkybox/back.jpg
new file mode 100644
index 0000000..260d08e
Binary files /dev/null and b/cw 9/textures/bubbleSkybox/back.jpg differ
diff --git a/cw 9/textures/bubbleSkybox/bottom.jpg b/cw 9/textures/bubbleSkybox/bottom.jpg
new file mode 100644
index 0000000..4a0ad43
Binary files /dev/null and b/cw 9/textures/bubbleSkybox/bottom.jpg differ
diff --git a/cw 9/textures/bubbleSkybox/front.jpg b/cw 9/textures/bubbleSkybox/front.jpg
new file mode 100644
index 0000000..4de401d
Binary files /dev/null and b/cw 9/textures/bubbleSkybox/front.jpg differ
diff --git a/cw 9/textures/bubbleSkybox/left.jpg b/cw 9/textures/bubbleSkybox/left.jpg
new file mode 100644
index 0000000..8cc72ac
Binary files /dev/null and b/cw 9/textures/bubbleSkybox/left.jpg differ
diff --git a/cw 9/textures/bubbleSkybox/right.jpg b/cw 9/textures/bubbleSkybox/right.jpg
new file mode 100644
index 0000000..8246fc0
Binary files /dev/null and b/cw 9/textures/bubbleSkybox/right.jpg differ
diff --git a/cw 9/textures/bubbleSkybox/top.jpg b/cw 9/textures/bubbleSkybox/top.jpg
new file mode 100644
index 0000000..4fc846e
Binary files /dev/null and b/cw 9/textures/bubbleSkybox/top.jpg differ