├── img ├── normalView.jpg ├── raytracing.jpg └── raytracingFinal.jpg ├── README.md ├── LICENSE ├── Main.cpp └── OutputShader.frag /img/normalView.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArtemOnigiri/RealTimeRayTracing/HEAD/img/normalView.jpg -------------------------------------------------------------------------------- /img/raytracing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArtemOnigiri/RealTimeRayTracing/HEAD/img/raytracing.jpg -------------------------------------------------------------------------------- /img/raytracingFinal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArtemOnigiri/RealTimeRayTracing/HEAD/img/raytracingFinal.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RealTimeRayTracing 2 | 3 | Улучшенная версия с полигонами, текстурами и многим другим: 4 | https://github.com/Artalmaz31/RealTimeRayTracing 5 | 6 | ![Ray tracing final image](img/raytracingFinal.jpg) 7 | ![Ray tracing](img/raytracing.jpg) 8 | ![Normal view](img/normalView.jpg) 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Artem Yashin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | int w = 1920; 7 | int h = 1080; 8 | int mouseX = w / 2; 9 | int mouseY = h / 2; 10 | float mouseSensitivity = 3.0f; 11 | float speed = 0.1f; 12 | bool mouseHidden = true; 13 | bool wasdUD[6] = { false, false, false, false, false, false }; 14 | sf::Vector3f pos = sf::Vector3f(-5.0f, 0.0f, 0.0f); 15 | sf::Clock clock; 16 | int framesStill = 1; 17 | 18 | sf::RenderWindow window(sf::VideoMode(w, h), "Ray tracing", sf::Style::Titlebar | sf::Style::Close); 19 | window.setFramerateLimit(60); 20 | window.setMouseCursorVisible(false); 21 | 22 | sf::RenderTexture firstTexture; 23 | firstTexture.create(w, h); 24 | sf::Sprite firstTextureSprite = sf::Sprite(firstTexture.getTexture()); 25 | sf::Sprite firstTextureSpriteFlipped = sf::Sprite(firstTexture.getTexture()); 26 | firstTextureSpriteFlipped.setScale(1, -1); 27 | firstTextureSpriteFlipped.setPosition(0, h); 28 | 29 | sf::RenderTexture outputTexture; 30 | outputTexture.create(w, h); 31 | sf::Sprite outputTextureSprite = sf::Sprite(outputTexture.getTexture()); 32 | sf::Sprite outputTextureSpriteFlipped = sf::Sprite(firstTexture.getTexture()); 33 | outputTextureSpriteFlipped.setScale(1, -1); 34 | outputTextureSpriteFlipped.setPosition(0, h); 35 | 36 | sf::Shader shader; 37 | shader.loadFromFile("OutputShader.frag", sf::Shader::Fragment); 38 | shader.setUniform("u_resolution", sf::Vector2f(w, h)); 39 | 40 | std::random_device rd; 41 | std::mt19937 e2(rd()); 42 | std::uniform_real_distribution<> dist(0.0f, 1.0f); 43 | 44 | while (window.isOpen()) 45 | { 46 | sf::Event event; 47 | while (window.pollEvent(event)) 48 | { 49 | if (event.type == sf::Event::Closed) 50 | { 51 | window.close(); 52 | } 53 | else if (event.type == sf::Event::MouseMoved) 54 | { 55 | if (mouseHidden) 56 | { 57 | int mx = event.mouseMove.x - w / 2; 58 | int my = event.mouseMove.y - h / 2; 59 | mouseX += mx; 60 | mouseY += my; 61 | sf::Mouse::setPosition(sf::Vector2i(w / 2, h / 2), window); 62 | if (mx != 0 || my != 0) framesStill = 1; 63 | } 64 | } 65 | else if (event.type == sf::Event::MouseButtonPressed) 66 | { 67 | if (!mouseHidden) framesStill = 1; 68 | window.setMouseCursorVisible(false); 69 | mouseHidden = true; 70 | } 71 | else if (event.type == sf::Event::KeyPressed) 72 | { 73 | if (event.key.code == sf::Keyboard::Escape) 74 | { 75 | window.setMouseCursorVisible(true); 76 | mouseHidden = false; 77 | } 78 | else if (event.key.code == sf::Keyboard::W) wasdUD[0] = true; 79 | else if (event.key.code == sf::Keyboard::A) wasdUD[1] = true; 80 | else if (event.key.code == sf::Keyboard::S) wasdUD[2] = true; 81 | else if (event.key.code == sf::Keyboard::D) wasdUD[3] = true; 82 | else if (event.key.code == sf::Keyboard::Space) wasdUD[4] = true; 83 | else if (event.key.code == sf::Keyboard::LShift) wasdUD[5] = true; 84 | } 85 | else if (event.type == sf::Event::KeyReleased) 86 | { 87 | if (event.key.code == sf::Keyboard::W) wasdUD[0] = false; 88 | else if (event.key.code == sf::Keyboard::A) wasdUD[1] = false; 89 | else if (event.key.code == sf::Keyboard::S) wasdUD[2] = false; 90 | else if (event.key.code == sf::Keyboard::D) wasdUD[3] = false; 91 | else if (event.key.code == sf::Keyboard::Space) wasdUD[4] = false; 92 | else if (event.key.code == sf::Keyboard::LShift) wasdUD[5] = false; 93 | } 94 | } 95 | if (mouseHidden) 96 | { 97 | float mx = ((float)mouseX / w - 0.5f) * mouseSensitivity; 98 | float my = ((float)mouseY / h - 0.5f) * mouseSensitivity; 99 | sf::Vector3f dir = sf::Vector3f(0.0f, 0.0f, 0.0f); 100 | sf::Vector3f dirTemp; 101 | if (wasdUD[0]) dir = sf::Vector3f(1.0f, 0.0f, 0.0f); 102 | else if (wasdUD[2]) dir = sf::Vector3f(-1.0f, 0.0f, 0.0f); 103 | if (wasdUD[1]) dir += sf::Vector3f(0.0f, -1.0f, 0.0f); 104 | else if (wasdUD[3]) dir += sf::Vector3f(0.0f, 1.0f, 0.0f); 105 | dirTemp.z = dir.z * cos(-my) - dir.x * sin(-my); 106 | dirTemp.x = dir.z * sin(-my) + dir.x * cos(-my); 107 | dirTemp.y = dir.y; 108 | dir.x = dirTemp.x * cos(mx) - dirTemp.y * sin(mx); 109 | dir.y = dirTemp.x * sin(mx) + dirTemp.y * cos(mx); 110 | dir.z = dirTemp.z; 111 | pos += dir * speed; 112 | if (wasdUD[4]) pos.z -= speed; 113 | else if (wasdUD[5]) pos.z += speed; 114 | for (int i = 0; i < 6; i++) 115 | { 116 | if (wasdUD[i]) 117 | { 118 | framesStill = 1; 119 | break; 120 | } 121 | } 122 | shader.setUniform("u_pos", pos); 123 | shader.setUniform("u_mouse", sf::Vector2f(mx, my)); 124 | shader.setUniform("u_time", clock.getElapsedTime().asSeconds()); 125 | shader.setUniform("u_sample_part", 1.0f / framesStill); 126 | shader.setUniform("u_seed1", sf::Vector2f((float)dist(e2), (float)dist(e2)) * 999.0f); 127 | shader.setUniform("u_seed2", sf::Vector2f((float)dist(e2), (float)dist(e2)) * 999.0f); 128 | } 129 | if (framesStill % 2 == 1) 130 | { 131 | shader.setUniform("u_sample", firstTexture.getTexture()); 132 | outputTexture.draw(firstTextureSpriteFlipped, &shader); 133 | window.draw(outputTextureSprite); 134 | } 135 | else 136 | { 137 | shader.setUniform("u_sample", outputTexture.getTexture()); 138 | firstTexture.draw(outputTextureSpriteFlipped, &shader); 139 | window.draw(firstTextureSprite); 140 | } 141 | window.display(); 142 | framesStill++; 143 | } 144 | return 0; 145 | } -------------------------------------------------------------------------------- /OutputShader.frag: -------------------------------------------------------------------------------- 1 | #version 130 2 | 3 | uniform vec2 u_resolution; 4 | uniform vec2 u_mouse; 5 | uniform vec3 u_pos; 6 | uniform float u_time; 7 | uniform sampler2D u_sample; 8 | uniform float u_sample_part; 9 | uniform vec2 u_seed1; 10 | uniform vec2 u_seed2; 11 | 12 | const float MAX_DIST = 99999.0; 13 | const int MAX_REF = 8; 14 | vec3 light = normalize(vec3(-0.5, 0.75, -1.0)); 15 | 16 | uvec4 R_STATE; 17 | 18 | uint TausStep(uint z, int S1, int S2, int S3, uint M) 19 | { 20 | uint b = (((z << S1) ^ z) >> S2); 21 | return (((z & M) << S3) ^ b); 22 | } 23 | 24 | uint LCGStep(uint z, uint A, uint C) 25 | { 26 | return (A * z + C); 27 | } 28 | 29 | vec2 hash22(vec2 p) 30 | { 31 | p += u_seed1.x; 32 | vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); 33 | p3 += dot(p3, p3.yzx+33.33); 34 | return fract((p3.xx+p3.yz)*p3.zy); 35 | } 36 | 37 | float random() 38 | { 39 | R_STATE.x = TausStep(R_STATE.x, 13, 19, 12, uint(4294967294)); 40 | R_STATE.y = TausStep(R_STATE.y, 2, 25, 4, uint(4294967288)); 41 | R_STATE.z = TausStep(R_STATE.z, 3, 11, 17, uint(4294967280)); 42 | R_STATE.w = LCGStep(R_STATE.w, uint(1664525), uint(1013904223)); 43 | return 2.3283064365387e-10 * float((R_STATE.x ^ R_STATE.y ^ R_STATE.z ^ R_STATE.w)); 44 | } 45 | 46 | vec3 randomOnSphere() { 47 | vec3 rand = vec3(random(), random(), random()); 48 | float theta = rand.x * 2.0 * 3.14159265; 49 | float v = rand.y; 50 | float phi = acos(2.0 * v - 1.0); 51 | float r = pow(rand.z, 1.0 / 3.0); 52 | float x = r * sin(phi) * cos(theta); 53 | float y = r * sin(phi) * sin(theta); 54 | float z = r * cos(phi); 55 | return vec3(x, y, z); 56 | } 57 | 58 | mat2 rot(float a) { 59 | float s = sin(a); 60 | float c = cos(a); 61 | return mat2(c, -s, s, c); 62 | } 63 | 64 | vec2 sphIntersect(in vec3 ro, in vec3 rd, float ra) { 65 | float b = dot(ro, rd); 66 | float c = dot(ro, ro) - ra * ra; 67 | float h = b * b - c; 68 | if(h < 0.0) return vec2(-1.0); 69 | h = sqrt(h); 70 | return vec2(-b - h, -b + h); 71 | } 72 | 73 | vec2 boxIntersection(in vec3 ro, in vec3 rd, in vec3 rad, out vec3 oN) { 74 | vec3 m = 1.0 / rd; 75 | vec3 n = m * ro; 76 | vec3 k = abs(m) * rad; 77 | vec3 t1 = -n - k; 78 | vec3 t2 = -n + k; 79 | float tN = max(max(t1.x, t1.y), t1.z); 80 | float tF = min(min(t2.x, t2.y), t2.z); 81 | if(tN > tF || tF < 0.0) return vec2(-1.0); 82 | oN = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz); 83 | return vec2(tN, tF); 84 | } 85 | 86 | float plaIntersect(in vec3 ro, in vec3 rd, in vec4 p) { 87 | return -(dot(ro, p.xyz) + p.w) / dot(rd, p.xyz); 88 | } 89 | 90 | vec3 getSky(vec3 rd) { 91 | vec3 col = vec3(0.3, 0.6, 1.0); 92 | vec3 sun = vec3(0.95, 0.9, 1.0); 93 | sun *= max(0.0, pow(dot(rd, light), 256.0)); 94 | col *= max(0.0, dot(light, vec3(0.0, 0.0, -1.0))); 95 | return clamp(sun + col * 0.01, 0.0, 1.0); 96 | } 97 | 98 | vec4 castRay(inout vec3 ro, inout vec3 rd) { 99 | vec4 col; 100 | vec2 minIt = vec2(MAX_DIST); 101 | vec2 it; 102 | vec3 n; 103 | mat2x4 spheres[6]; 104 | spheres[0][0] = vec4(-1.0, 0.0, -0.01, 1.0); 105 | spheres[1][0] = vec4(0.0, 3.0, -0.01, 1.0); 106 | spheres[2][0] = vec4(1.0, -2.0, -0.01, 1.0); 107 | spheres[3][0] = vec4(3.5, -1.0, 0.5, 0.5); 108 | spheres[4][0] = vec4(-3.5, -1.0, 0.0, 0.5); 109 | spheres[5][0] = vec4(-5.5, -0.5, -0.01, 1.0); 110 | spheres[0][1] = vec4(1.0, 1.0, 1.0, -0.5); 111 | spheres[1][1] = vec4(1.0, 1.0, 1.0, 0.5); 112 | spheres[2][1] = vec4(1.0, 0.0, 0.5, 1.0); 113 | spheres[3][1] = vec4(1.0, 1.0, 1.0, -2.0); 114 | spheres[4][1] = vec4(0.5, 1.0, 0.5, -2.0); 115 | spheres[5][1] = vec4(0.5, 0.5, 0.5, 0.0); 116 | for(int i = 0; i < spheres.length(); i++) { 117 | it = sphIntersect(ro - spheres[i][0].xyz, rd, spheres[i][0].w); 118 | if(it.x > 0.0 && it.x < minIt.x) { 119 | minIt = it; 120 | vec3 itPos = ro + rd * it.x; 121 | n = normalize(itPos - spheres[i][0].xyz); 122 | col = spheres[i][1]; 123 | } 124 | } 125 | vec3 boxN; 126 | vec3 boxPos = vec3(3.0, 1.0, -0.001); 127 | it = boxIntersection(ro - boxPos, rd, vec3(1.0), boxN); 128 | if(it.x > 0.0 && it.x < minIt.x) { 129 | minIt = it; 130 | n = boxN; 131 | col = vec4(0.9, 0.2, 0.2, -0.5); 132 | } 133 | vec3 planeNormal = vec3(0.0, 0.0, -1.0); 134 | it = vec2(plaIntersect(ro, rd, vec4(planeNormal, 1.0))); 135 | if(it.x > 0.0 && it.x < minIt.x) { 136 | minIt = it; 137 | n = planeNormal; 138 | col = vec4(0.5, 0.25, 0.1, 0.01); 139 | } 140 | if(minIt.x == MAX_DIST) return vec4(getSky(rd), -2.0); 141 | if(col.a == -2.0) return col; 142 | vec3 reflected = reflect(rd, n); 143 | if(col.a < 0.0) { 144 | float fresnel = 1.0 - abs(dot(-rd, n)); 145 | if(random() - 0.1 < fresnel * fresnel) { 146 | rd = reflected; 147 | return col; 148 | } 149 | ro += rd * (minIt.y + 0.001); 150 | rd = refract(rd, n, 1.0 / (1.0 - col.a)); 151 | return col; 152 | } 153 | vec3 itPos = ro + rd * it.x; 154 | vec3 r = randomOnSphere(); 155 | vec3 diffuse = normalize(r * dot(r, n)); 156 | ro += rd * (minIt.x - 0.001); 157 | rd = mix(diffuse, reflected, col.a); 158 | return col; 159 | } 160 | 161 | vec3 traceRay(vec3 ro, vec3 rd) { 162 | vec3 col = vec3(1.0); 163 | for(int i = 0; i < MAX_REF; i++) 164 | { 165 | vec4 refCol = castRay(ro, rd); 166 | col *= refCol.rgb; 167 | if(refCol.a == -2.0) return col; 168 | } 169 | return vec3(0.0); 170 | } 171 | 172 | void main() { 173 | vec2 uv = (gl_TexCoord[0].xy - 0.5) * u_resolution / u_resolution.y; 174 | vec2 uvRes = hash22(uv + 1.0) * u_resolution + u_resolution; 175 | R_STATE.x = uint(u_seed1.x + uvRes.x); 176 | R_STATE.y = uint(u_seed1.y + uvRes.x); 177 | R_STATE.z = uint(u_seed2.x + uvRes.y); 178 | R_STATE.w = uint(u_seed2.y + uvRes.y); 179 | vec3 rayOrigin = u_pos; 180 | vec3 rayDirection = normalize(vec3(1.0, uv)); 181 | rayDirection.zx *= rot(-u_mouse.y); 182 | rayDirection.xy *= rot(u_mouse.x); 183 | vec3 col = vec3(0.0); 184 | int samples = 4; 185 | for(int i = 0; i < samples; i++) { 186 | col += traceRay(rayOrigin, rayDirection); 187 | } 188 | col /= samples; 189 | float white = 20.0; 190 | col *= white * 16.0; 191 | col = (col * (1.0 + col / white / white)) / (1.0 + col); 192 | vec3 sampleCol = texture(u_sample, gl_TexCoord[0].xy).rgb; 193 | col = mix(sampleCol, col, u_sample_part); 194 | gl_FragColor = vec4(col, 1.0); 195 | } 196 | --------------------------------------------------------------------------------