1 module armos.graphics.fbo; 2 3 import derelict.opengl3.gl; 4 import armos.graphics; 5 import armos.types; 6 import armos.math.vector; 7 import armos.utils.scoped; 8 9 /++ 10 Frame Buffer Objectを表すclassです. 11 +/ 12 class Fbo{ 13 public{ 14 /++ 15 +/ 16 this(){ 17 import armos.app; 18 this(currentWindow.size); 19 } 20 21 /++ 22 +/ 23 this(V2)(in V2 size){ 24 this(size[0], size[1]); 25 } 26 27 /++ 28 +/ 29 this(T)(in T width, in T height){ 30 _size = Vector2i(width, height); 31 Vector2i textureSize = _size * _samples; 32 int x = textureSize.x; 33 int y = textureSize.y; 34 35 glGenFramebuffers(1, cast(uint*)&_id); 36 37 _colorTexture = (new Texture).allocate(x, y, armos.graphics.ColorFormat.RGBA) 38 .minMagFilter(TextureMinFilter.Nearest, TextureMagFilter.Nearest); 39 40 _depthTexture = (new Texture).allocate(x, y, armos.graphics.ColorFormat.Depth) 41 .minMagFilter(TextureMinFilter.Nearest, TextureMagFilter.Nearest); 42 43 _colorTextureTmp = (new Texture).allocate(x, y, armos.graphics.ColorFormat.RGBA) 44 .minMagFilter(TextureMinFilter.Nearest, TextureMagFilter.Nearest); 45 46 _depthTextureTmp = (new Texture).allocate(x, y, armos.graphics.ColorFormat.Depth) 47 .minMagFilter(TextureMinFilter.Nearest, TextureMagFilter.Nearest); 48 49 _rect = new Mesh; 50 51 _rect.texCoords0 = [ 52 Vector4f(0f, 0f, 0.0, 1.0f), 53 Vector4f(1f, 0, 0.0, 1.0f), 54 Vector4f(1f, 1f, 0.0, 1.0f), 55 Vector4f(0, 1f, 0.0, 1.0f), 56 ]; 57 // isFlip(true); 58 59 _rect.vertices = [ 60 Vector4f(0.0, 0.0, 0.0, 1.0f), 61 Vector4f(_size.x, 0.0, 0.0, 1.0f), 62 Vector4f(_size.x, _size.y, 0.0, 1.0f), 63 Vector4f(0.0, _size.y, 0.0, 1.0f), 64 ]; 65 66 _rect.indices = [ 67 0, 1, 2, 68 2, 3, 0, 69 ]; 70 71 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_savedId); 72 glBindFramebuffer(GL_FRAMEBUFFER, _id); 73 74 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _colorTexture.id, 0); 75 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthTexture.id, 0); 76 glBindFramebuffer(GL_FRAMEBUFFER, _savedId); 77 78 _material = (new FboMaterial).texture("colorTexture", _colorTexture) 79 .texture("depthTexture", _depthTexture); 80 } 81 82 /++ 83 FBOへの描画処理を開始します. 84 +/ 85 Fbo begin(in bool setScreenPerspective = true){ 86 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_savedId); 87 glBindFramebuffer(GL_FRAMEBUFFER, _id); 88 Vector2i textureSize = _size*_samples; 89 viewport(Vector2i.zero, textureSize); 90 91 pushProjectionMatrix; 92 import armos.app:windowSize; 93 if(setScreenPerspective) loadProjectionMatrix(screenPerspectiveMatrix(_size)); 94 return this; 95 } 96 97 /++ 98 FBOへの描画処理を終了します. 99 +/ 100 Fbo end(){ 101 popProjectionMatrix; 102 glBindFramebuffer(GL_FRAMEBUFFER, _savedId); 103 return this; 104 } 105 106 /++ 107 FBOのIDを返します. 108 +/ 109 int id()const{ 110 return _id; 111 } 112 113 /++ 114 FBOを描画します. 115 +/ 116 Fbo draw(){ 117 _material.begin; 118 _rect.drawFill; 119 _material.end; 120 return this; 121 } 122 123 /++ 124 FBOをリサイズします. 125 Params: 126 size = リサイズ後のサイズ 127 +/ 128 Fbo resize(in armos.math.Vector2i size){ 129 _size = size; 130 _rect.vertices[1][0] = _size[0]; 131 _rect.vertices[2][0] = _size[0]; 132 _rect.vertices[2][1] = _size[1]; 133 _rect.vertices[3][1] = _size[1]; 134 resizeTextures; 135 return this; 136 } 137 138 /// 139 bool isFlip()const{return _isFlip;} 140 141 /// 142 Fbo isFlip(in bool f){ 143 _isFlip = f; 144 if(_isFlip){ 145 _rect.texCoords0 = [ 146 Vector4f(0f, 1f, 0.0, 1.0f), 147 Vector4f(1f, 1, 0.0, 1.0f), 148 Vector4f(1f, 0f, 0.0, 1.0f), 149 Vector4f(0, 0f, 0.0, 1.0f), 150 ]; 151 }else{ 152 _rect.texCoords0 = [ 153 Vector4f(0f, 0f, 0.0, 1.0f), 154 Vector4f(1f, 0, 0.0, 1.0f), 155 Vector4f(1f, 1f, 0.0, 1.0f), 156 Vector4f(0, 1f, 0.0, 1.0f), 157 ]; 158 } 159 return this; 160 } 161 162 /// 163 Fbo samples(in int s){ 164 _samples = s; 165 resizeTextures; 166 return this; 167 } 168 169 /// 170 int samples()const{ 171 return _samples; 172 } 173 174 /// 175 Fbo minFilter(in TextureMinFilter filter){ 176 _colorTexture.minFilter(filter); 177 _colorTextureTmp.minFilter(filter); 178 _depthTexture.minFilter(filter); 179 _depthTextureTmp.minFilter(filter); 180 return this; 181 } 182 183 /// 184 Fbo magFilter(in TextureMagFilter filter){ 185 _colorTexture.magFilter(filter); 186 _colorTextureTmp.magFilter(filter); 187 _depthTexture.magFilter(filter); 188 _depthTextureTmp.magFilter(filter); 189 return this; 190 } 191 192 /// 193 Fbo filteredBy(Material material){ 194 { 195 auto scopedFbo = scoped(this); 196 { 197 auto scopedColor = scoped(_colorTextureTmp); 198 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, _size.x, _size.y); 199 } 200 { 201 auto scopedDepth= scoped(_depthTextureTmp); 202 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, _size.x, _size.y); 203 } 204 } 205 206 material.texture("colorTexture", _colorTextureTmp) 207 .texture("depthTexture", _depthTextureTmp); 208 209 auto scopedFbo = scoped(this); 210 auto scopedMaterial = scoped(material); 211 _rect.drawFill; 212 213 return this; 214 } 215 216 }//public 217 218 private{ 219 int _savedId = 0; 220 int _id = 0; 221 222 Texture _colorTexture; 223 Texture _colorTextureTmp; 224 Texture _depthTexture; 225 Texture _depthTextureTmp; 226 227 Mesh _rect = new Mesh; 228 Material _material; 229 int _samples = 1; 230 bool _isFlip = false; 231 Vector2i _size; 232 233 void resizeTextures(){ 234 begin; 235 _colorTexture.resize(_size*_samples); 236 _depthTexture.resize(_size*_samples); 237 _colorTextureTmp.resize(_size*_samples); 238 _depthTextureTmp.resize(_size*_samples); 239 end; 240 } 241 }//private 242 } 243 244 /++ 245 +/ 246 class FboMaterial : Material{ 247 mixin MaterialImpl; 248 249 /// 250 this(){ 251 _shader = new Shader; 252 _shader.loadSources(fboVertexShaderSource, "", fboFragmentShaderSource); 253 } 254 255 private{ 256 } 257 }//class FboMaterial 258 259 private immutable string fboVertexShaderSource = q{ 260 #version 330 261 262 uniform mat4 modelViewMatrix; 263 uniform mat4 projectionMatrix; 264 uniform mat4 modelViewProjectionMatrix; 265 uniform mat4 textureMatrix; 266 267 in vec4 vertex; 268 in vec3 normal; 269 in vec3 tangent; 270 in vec4 texCoord0; 271 in vec4 texCoord1; 272 in vec4 color; 273 274 out vec4 f_color; 275 out vec2 outtexCoord0; 276 out vec2 outtexCoord1; 277 278 void main(void) { 279 gl_Position = modelViewProjectionMatrix * vertex; 280 f_color = color; 281 outtexCoord0 = texCoord0.xy; 282 outtexCoord1 = texCoord1.xy; 283 } 284 }; 285 286 private immutable string fboFragmentShaderSource = q{ 287 #version 330 288 289 in vec4 f_color; 290 in vec2 outtexCoord0; 291 in vec2 outtexCoord1; 292 293 out vec4 fragColor; 294 295 uniform sampler2D colorTexture; 296 uniform sampler2D depthTexture; 297 298 void main(void) { 299 fragColor = texture(colorTexture, outtexCoord0); 300 } 301 };