CSharpGL(29)初步封装Texture和Framebuffer
?
CSharpGL(29)初步封裝Texture和Framebuffer
+BIT祝威+悄悄在此留下版了個(gè)權(quán)的信息說:Texture和Framebuffer
Texture和Framebuffer是OpenGL進(jìn)行3D渲染高級(jí)效果必不可少的利器。有了Texture和Framebuffer就可以實(shí)現(xiàn)體渲染(Volume Rendering)等效果。現(xiàn)在到了對Texture和Framebuffer的創(chuàng)建、修改、使用進(jìn)行封裝的時(shí)候。
+BIT祝威+悄悄在此留下版了個(gè)權(quán)的信息說:下載
CSharpGL已在GitHub開源,歡迎對OpenGL有興趣的同學(xué)加入(https://github.com/bitzhuwei/CSharpGL)
+BIT祝威+悄悄在此留下版了個(gè)權(quán)的信息說:封裝Texture
過程式的Texture
首先觀察一下平時(shí)是如何創(chuàng)建和使用Texture對象的。
+BIT祝威+悄悄在此留下版了個(gè)權(quán)的信息說:創(chuàng)建Texture
以創(chuàng)建2D Texture為例。
1 uint CreateTexture(Bitmap bitmap) 2 { 3 glActiveTexture(OpenGL.GL_TEXTURE0); 4 var id = new uint[1]; 5 OpenGL.GenTextures(1, id); 6 OpenGL.BindTexture(target, id[0]); 7 OpenGL.TexParameteri(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_WRAP_R, (int)OpenGL.GL_CLAMP_TO_EDGE); 8 OpenGL.TexParameteri(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_WRAP_S, (int)OpenGL.GL_CLAMP_TO_EDGE); 9 OpenGL.TexParameteri(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_WRAP_T, (int)OpenGL.GL_CLAMP_TO_EDGE); 10 OpenGL.TexParameteri(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MIN_FILTER, (int)OpenGL.GL_REPEAT); 11 OpenGL.TexParameteri(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MAG_FILTER, (int)OpenGL.GL_REPEAT); 12 13 BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), 14 ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 15 OpenGL.TexImage2D(OpenGL.GL_TEXTURE_2D, 0, OpenGL.GL_RGBA, bitmap.Width, bitmap.Height, 0, OpenGL.GL_BGRA, OpenGL.GL_UNSIGNED_BYTE, bitmapData.Scan0); 16 bitmap.UnlockBits(bitmapData); 17 18 return id[0]; 19 } CreateTexture?使用Texture
使用上述Texture的方式:
1 void UseTexture(string textureNameInShader, uint textureId) 2 { 3 uint target = OpenGL.GL_TEXTURE0; 4 glActiveTexture(target); 5 OpenGL.BindTexture(OpenGL.GL_TEXTURE_2D, textureId); 6 SetUniform("textureNameInShader", target - OpenGL.GL_TEXTURE0); 7 } 8 9 int SetUniform(string uniformName, uint v0) 10 { 11 int location = GetUniformLocation(uniformName); 12 if (location >= 0) 13 { 14 glUniform1ui(GetUniformLocation(uniformName), v0); 15 } 16 return location; 17 }封裝的Texture
從上述創(chuàng)建Texture的過程可知,創(chuàng)建Texture主要有2個(gè)步驟:設(shè)置Sampler和填充Texture數(shù)據(jù)。Sampler就是各個(gè)濾波選項(xiàng)。填充數(shù)據(jù)就是用glTexImage2D()一類的命令指定Texture的內(nèi)容。
1 void Initialize() 2 { 3 glActiveTexture(this.ActiveTexture); 4 OpenGL.GenTextures(1, id); 5 BindTextureTarget target = this.Target; 6 OpenGL.BindTexture(target, id[0]); 7 this.Sampler.Bind(this.ActiveTexture - OpenGL.GL_TEXTURE0, target); 8 this.ImageFiller.Fill(target); 9 OpenGL.GenerateMipmap((MipmapTarget)((uint)target));// TODO: does this work? 10 //this.SamplerBuilder.Unbind(OpenGL.GL_TEXTURE0 - OpenGL.GL_TEXTURE0, this.Target); 11 OpenGL.BindTexture(this.Target, 0); 12 } +BIT祝威+悄悄在此留下版了個(gè)權(quán)的信息說:Sampler
Sampler中主要就是那幾個(gè)濾波選項(xiàng)。
1 /// <summary> 2 /// texture's settings. 3 /// </summary> 4 public class SamplerParameters 5 { 6 public TextureWrapping wrapS = TextureWrapping.ClampToEdge; 7 public TextureWrapping wrapT = TextureWrapping.ClampToEdge; 8 public TextureWrapping wrapR = TextureWrapping.ClampToEdge; 9 public TextureFilter minFilter = TextureFilter.Linear; 10 public TextureFilter magFilter = TextureFilter.Linear; 11 12 public SamplerParameters() { } 13 } +BIT祝威+悄悄在此留下版了個(gè)權(quán)的信息說:Sampler的唯一任務(wù)就是在創(chuàng)建Texture時(shí)指定某些濾波。
1 /// <summary> 2 /// texture's settings. 3 /// </summary> 4 public abstract class SamplerBase 5 { 6 protected MipmapFilter mipmapFilter; 7 public SamplerParameters Parameters { get; protected set; } 8 9 /// <summary> 10 /// texture's settings. 11 /// </summary> 12 /// <param name="parameters"></param> 13 /// <param name="mipmapFilter"></param> 14 public SamplerBase(SamplerParameters parameters, MipmapFilter mipmapFilter) 15 { 16 if (parameters == null) 17 { 18 this.Parameters = new SamplerParameters(); 19 } 20 else 21 { 22 this.Parameters = parameters; 23 } 24 25 this.mipmapFilter = mipmapFilter; 26 } 27 28 /// <summary> 29 /// 30 /// </summary> 31 /// <param name="unit">OpenGL.GL_TEXTURE0 etc.</param> 32 /// <param name="target"></param> 33 public abstract void Bind(uint unit, BindTextureTarget target); 34 35 }實(shí)際上為了簡化指定Sampler的操作,OpenGL提供了一個(gè)Sampler對象。這里順便也把它封裝了。
1 /// <summary> 2 /// texture's settings. 3 /// </summary> 4 public partial class Sampler : SamplerBase, IDisposable 5 { 6 /// <summary> 7 /// sampler's Id. 8 /// </summary> 9 public uint Id { get; private set; } 10 11 /// <summary> 12 /// texture's settings. 13 /// </summary> 14 /// <param name="parameters"></param> 15 /// <param name="mipmapFiltering"></param> 16 public Sampler( 17 SamplerParameters parameters = null, 18 MipmapFilter mipmapFiltering = MipmapFilter.LinearMipmapLinear) 19 : base(parameters, mipmapFiltering) 20 { 21 22 } 23 24 private bool initialized = false; 25 /// <summary> 26 /// 27 /// </summary> 28 public void Initialize(uint unit, BindTextureTarget target) 29 { 30 if (!this.initialized) 31 { 32 this.DoInitialize(unit, target); 33 this.initialized = true; 34 } 35 } 36 37 private void DoInitialize(uint unit, BindTextureTarget target) 38 { 39 var ids = new uint[1]; 40 OpenGL.GenSamplers(1, ids); 41 this.Id = ids[0]; 42 //OpenGL.BindSampler(unit, ids[0]); 43 OpenGL.BindSampler(unit, ids[0]); 44 /* Clamping to edges is important to prevent artifacts when scaling */ 45 OpenGL.SamplerParameteri(ids[0], OpenGL.GL_TEXTURE_WRAP_R, (int)this.parameters.wrapR); 46 OpenGL.SamplerParameteri(ids[0], OpenGL.GL_TEXTURE_WRAP_S, (int)this.parameters.wrapS); 47 OpenGL.SamplerParameteri(ids[0], OpenGL.GL_TEXTURE_WRAP_T, (int)this.parameters.wrapT); 48 /* Linear filtering usually looks best for text */ 49 OpenGL.SamplerParameteri(ids[0], OpenGL.GL_TEXTURE_MIN_FILTER, (int)this.parameters.minFilter); 50 OpenGL.SamplerParameteri(ids[0], OpenGL.GL_TEXTURE_MAG_FILTER, (int)this.parameters.magFilter); 51 // TODO: mipmap not used yet. 52 53 OpenGL.BindSampler(unit, 0); 54 } 55 /// <summary> 56 /// texture's settings. 57 /// </summary> 58 /// <param name="unit">OpenGL.GL_TEXTURE0 etc.</param> 59 /// <param name="target"></param> 60 public override void Bind(uint unit, BindTextureTarget target) 61 { 62 if (!this.initialized) { this.Initialize(unit, target); } 63 64 OpenGL.BindSampler(unit, this.Id); 65 } 66 } Sampler +BIT祝威+悄悄在此留下版了個(gè)權(quán)的信息說:當(dāng)然也可以不用這個(gè)OpenGL的Sampler對象,直接用glTexParameteri()等指令。這就像是一個(gè)假的Sampler對象在工作。
1 /// <summary> 2 /// texture's settings. 3 /// </summary> 4 public class FakeSampler : SamplerBase 5 { 6 7 /// <summary> 8 /// texture's settings. 9 /// </summary> 10 /// <param name="parameters"></param> 11 /// <param name="mipmapFiltering"></param> 12 public FakeSampler(SamplerParameters parameters, MipmapFilter mipmapFiltering) 13 : base(parameters, mipmapFiltering) 14 { 15 } 16 17 /// <summary> 18 /// texture's settings. 19 /// </summary> 20 /// <param name="unit">OpenGL.GL_TEXTURE0 etc.</param> 21 /// <param name="target"></param> 22 public override void Bind(uint unit, BindTextureTarget target) 23 { 24 /* Clamping to edges is important to prevent artifacts when scaling */ 25 OpenGL.TexParameteri((uint)target, OpenGL.GL_TEXTURE_WRAP_R, (int)this.parameters.wrapR); 26 OpenGL.TexParameteri((uint)target, OpenGL.GL_TEXTURE_WRAP_S, (int)this.parameters.wrapS); 27 OpenGL.TexParameteri((uint)target, OpenGL.GL_TEXTURE_WRAP_T, (int)this.parameters.wrapT); 28 /* Linear filtering usually looks best for text */ 29 OpenGL.TexParameteri((uint)target, OpenGL.GL_TEXTURE_MIN_FILTER, (int)this.parameters.minFilter); 30 OpenGL.TexParameteri((uint)target, OpenGL.GL_TEXTURE_MAG_FILTER, (int)this.parameters.magFilter); 31 // TODO: mipmap filter not working yet. 32 33 } 34 } FakeSampler當(dāng)然,有的時(shí)候根本不需要指定任何濾波選項(xiàng)。這可以用一個(gè)空的Sampler類型實(shí)現(xiàn)。
1 /// <summary> 2 /// do nothing about sampling in building texture. 3 /// </summary> 4 public class NullSampler : SamplerBase 5 { 6 /// <summary> 7 /// do nothing about sampling in building texture. 8 /// </summary> 9 public NullSampler() : base(null, MipmapFilter.LinearMipmapLinear) { } 10 11 /// <summary> 12 /// do nothing. 13 /// </summary> 14 /// <param name="unit">OpenGL.GL_TEXTURE0 etc.</param> 15 /// <param name="target"></param> 16 public override void Bind(uint unit, BindTextureTarget target) 17 { 18 // nothing to do. 19 } 20 }?
+BIT祝威+悄悄在此留下版了個(gè)權(quán)的信息說:ImageFiller
填充數(shù)據(jù)就是用?glTexImage2D()?、?glTexStorage2D()?等指令設(shè)置Texture的內(nèi)容。ImageFiller就是封裝這一操作的。
1 /// <summary> 2 /// build texture's content. 3 /// </summary> 4 public abstract class ImageFiller 5 { 6 7 /// <summary> 8 /// build texture's content. 9 /// </summary> 10 /// <param name="target"></param> 11 public abstract void Fill(BindTextureTarget target); 12 }對于常見的以?System.Drawing.Bitmap?為數(shù)據(jù)源填充Texture的情形,可以用下面的BitmapFiller。它可以作為1D/2D的Texture對象的填充器。
1 /// <summary> 2 /// build texture's content with Bitmap. 3 /// </summary> 4 public class BitmapFiller : ImageFiller 5 { 6 private System.Drawing.Bitmap bitmap; 7 private int level; 8 private uint internalformat; 9 private int border; 10 private uint format; 11 private uint type; 12 13 /// <summary> 14 /// build texture's content with Bitmap. 15 /// </summary> 16 /// <param name="bitmap"></param> 17 /// <param name="level">0</param> 18 /// <param name="internalformat">OpenGL.GL_RGBA etc.</param> 19 /// <param name="border">0</param> 20 /// <param name="format">OpenGL.GL_BGRA etc.</param> 21 /// <param name="type">OpenGL.GL_UNSIGNED_BYTE etc.</param> 22 public BitmapFiller(System.Drawing.Bitmap bitmap, 23 int level, uint internalformat, int border, uint format, uint type) 24 { 25 this.bitmap = bitmap; 26 this.level = level; 27 this.internalformat = internalformat; 28 this.border = border; 29 this.format = format; 30 this.type = type; 31 } 32 33 /// <summary> 34 /// build texture's content with Bitmap. 35 /// </summary> 36 /// <param name="target"></param> 37 public override void Fill(BindTextureTarget target) 38 { 39 // generate texture. 40 // Lock the image bits (so that we can pass them to OGL). 41 BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), 42 ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 43 if (target == BindTextureTarget.Texture1D) 44 { 45 OpenGL.TexImage1D((uint)target, 0, this.internalformat, bitmap.Width, 0, this.format, this.type, bitmapData.Scan0); 46 } 47 else if (target == BindTextureTarget.Texture2D) 48 { 49 OpenGL.TexImage2D((uint)target, 0, this.internalformat, bitmap.Width, bitmap.Height, 0, this.format, this.type, bitmapData.Scan0); 50 } 51 else 52 { throw new NotImplementedException(); } 53 54 // Unlock the image. 55 bitmap.UnlockBits(bitmapData); 56 } 57 } BitmapFiller還有一個(gè)常見的填充方式?glTexStorage2D()?,可以用下面的TexStorageImageFiller實(shí)現(xiàn)。
1 /// <summary> 2 /// 3 /// </summary> 4 public class TexStorageImageFiller : ImageFiller 5 { 6 private int levels; 7 private uint internalFormat; 8 private int width; 9 private int height; 10 11 /// <summary> 12 /// 13 /// </summary> 14 /// <param name="levels"></param> 15 /// <param name="internalFormat"></param> 16 /// <param name="width"></param> 17 /// <param name="height"></param> 18 public TexStorageImageFiller(int levels, uint internalFormat, int width, int height) 19 { 20 // TODO: Complete member initialization 21 this.levels = levels; 22 this.internalFormat = internalFormat; 23 this.width = width; 24 this.height = height; 25 } 26 27 /// <summary> 28 /// 29 /// </summary> 30 /// <param name="target"></param> 31 public override void Fill(BindTextureTarget target) 32 { 33 switch (target) 34 { 35 case BindTextureTarget.Unknown: 36 break; 37 case BindTextureTarget.Texture1D: 38 break; 39 case BindTextureTarget.Texture2D: 40 OpenGL.TexStorage2D(TexStorage2DTarget.Texture2D, levels, internalFormat, width, height); 41 break; 42 case BindTextureTarget.Texture3D: 43 break; 44 case BindTextureTarget.TextureCubeMap: 45 break; 46 case BindTextureTarget.TextureBuffer: 47 break; 48 default: 49 break; 50 } 51 } 52 } TexStorageImageFiller?
+BIT祝威+悄悄在此留下版了個(gè)權(quán)的信息說:創(chuàng)建Texture
用封裝的類型創(chuàng)建Texture的方式如下:
1 Texture Create(Bitmap bitmap) 2 { 3 var texture = new Texture(BindTextureTarget.Texture2D, 4 new BitmapFiller(bitmap, 0, OpenGL.GL_RGBA32F, 0, OpenGL.GL_BGRA, OpenGL.GL_UNSIGNED_BYTE), 5 new SamplerParameters( 6 TextureWrapping.ClampToEdge, 7 TextureWrapping.ClampToEdge, 8 TextureWrapping.ClampToEdge, 9 TextureFilter.Linear, 10 TextureFilter.Linear)); 11 texture.Initialize(); 12 13 return texture; 14 }使用Texture
Texutre.Id就是用?glGenTextures()?獲得的id。Texture中記錄了此Texture的ActiveTexture、Target等屬性。配合CSharpGL中的?samplerValue?,我們有:
1 /// <summary> 2 /// get <see cref="samplerValue"/> from this texture. 3 /// </summary> 4 /// <param name="texture"></param> 5 /// <returns></returns> 6 public static samplerValue ToSamplerValue(this Texture texture) 7 { 8 return new samplerValue( 9 texture.Target, 10 texture.Id, 11 texture.ActiveTexture); 12 }這就可以用到設(shè)置shader中需要的Texture上:
this.SetUniform("tex", texture.ToSamplerValue());?
封裝Framebuffer
過程式的Framebuffer
首先觀察一下平時(shí)是如何創(chuàng)建和使用Framebuffer對象的。
創(chuàng)建Framebuffer
為關(guān)注重點(diǎn),這里直接傳入Texture的Id。
1 uint Create(int width, int height, uint textureId) 2 { 3 // create framebuffer. 4 var frameBufferId = new uint[1]; 5 glGenFramebuffers(1, frameBufferId); 6 glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, frameBufferId); 7 8 // attach texture as a color buffer. 9 glFramebufferTexture2D(OpenGL.GL_FRAMEBUFFER, OpenGL.GL_COLOR_ATTACHMENT0, OpenGL.GL_TEXTURE_2D, textureId, 0); 10 11 // create a depth buffer. 12 var renderbufferId = new uint[1]; 13 glGenRenderbuffers(1, renderbufferId); 14 glBindRenderbuffer(OpenGL.GL_RENDERBUFFER, renderbufferId[0]); 15 glRenderbufferStorage(OpenGL.GL_RENDERBUFFER, OpenGL.GL_DEPTH_COMPONENT, width, height); 16 17 // attach depth buffer. 18 glFramebufferRenderbuffer(OpenGL.GL_RENDERBUFFER, OpenGL.GL_DEPTH_ATTACHMENT, OpenGL.GL_RENDERBUFFER, renderbufferId); 19 20 glBindFramebuffer(OpenGL.GL_RENDERBUFFER, 0); 21 22 return frameBufferId; 23 }使用Framebuffer
使用方式與Texture類似,只要綁定就可以了。
glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, frameBufferId);用完再解綁。
glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, 0);封裝的Framebuffer
Framebuffer就是一個(gè)盒子,單獨(dú)創(chuàng)建一個(gè)Framebuffer基本上是沒什么用的。必須Attach一些colorbuffer/depthbuffer/texture才能發(fā)揮作用。
一個(gè)Framebuffer能夠綁定多個(gè)texture和colorbuffer,只能綁定一個(gè)depthbuffer。
Renderbuffer
colorbuffer和depthbuffer都屬于Renderbuffer的一種,其創(chuàng)建方式相同,只不過有一個(gè)標(biāo)識(shí)其為colorbuffer還是depthbuffer的標(biāo)志不同。
創(chuàng)建Renderbuffer很簡單。
1 /// <summary> 2 /// Create, update, use and delete a renderbuffer object. 3 /// </summary> 4 public partial class Renderbuffer 5 { 6 uint[] renderbuffer = new uint[1]; 7 /// <summary> 8 /// Framebuffer Id. 9 /// </summary> 10 public uint Id { get { return renderbuffer[0]; } } 11 12 /// <summary> 13 /// Create, update, use and delete a renderbuffer object. 14 /// </summary> 15 /// <param name="width"></param> 16 /// <param name="height"></param> 17 /// <param name="internalformat">GL_DEPTH_COMPONENT, GL_RGBA etc.</param> 18 /// <param name="bufferType"></param> 19 public Renderbuffer(int width, int height, uint internalformat, RenderbufferType bufferType) 20 { 21 this.Width = width; 22 this.Height = height; 23 this.BufferType = bufferType; 24 25 glGenRenderbuffers(1, renderbuffer); 26 glBindRenderbuffer(OpenGL.GL_RENDERBUFFER, renderbuffer[0]); 27 glRenderbufferStorage(OpenGL.GL_RENDERBUFFER, 28 internalformat, width, height); 29 } 30 31 public int Width { get; set; } 32 public int Height { get; set; } 33 public RenderbufferType BufferType { get; private set; } 34 } 35 36 public enum RenderbufferType 37 { 38 DepthBuffer, 39 ColorBuffer, 40 } +BIT祝威+悄悄在此留下版了個(gè)權(quán)的信息說:創(chuàng)建Framebuffer
創(chuàng)建Framebuffer也很簡單,實(shí)際上只是調(diào)用了一個(gè)?glGenFramebuffers(1, frameBuffer);?命令。
1 /// <summary> 2 /// Create, update, use and delete a framebuffer object. 3 /// </summary> 4 public partial class Framebuffer : IDisposable 5 { 6 uint[] frameBuffer = new uint[1]; 7 /// <summary> 8 /// Framebuffer Id. 9 /// </summary> 10 public uint Id { get { return frameBuffer[0]; } } 11 12 /// <summary> 13 /// Create an empty framebuffer object. 14 /// </summary> 15 public Framebuffer() 16 { 17 glGenFramebuffers(1, frameBuffer); 18 } 19 } 20 21 /// <summary> 22 /// 23 /// </summary> 24 public enum FramebufferTarget : uint 25 { 26 /// <summary> 27 /// used to draw(write only) something. 28 /// </summary> 29 DrawFramebuffer = OpenGL.GL_DRAW_FRAMEBUFFER, 30 /// <summary> 31 /// used to read from(read only). 32 /// </summary> 33 ReadFramebuffer = OpenGL.GL_READ_FRAMEBUFFER, 34 /// <summary> 35 /// both read/write. 36 /// </summary> 37 Framebuffer = OpenGL.GL_FRAMEBUFFER, 38 }使用Framebuffer
使用方式與Texture類似,只要綁定就可以了。
framebuffer.Bind();// glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, framebufferId);用完再解綁。
framebuffer.Unbind();// glBindFramebuffer(OpenGL.GL_FRAMEBUFFER, 0);這與未封裝的使用方式?jīng)]什么區(qū)別。
總結(jié)
基于目前我對Texture和Framebuffer的了解,現(xiàn)在只能封裝到這個(gè)地步。
?
+BIT祝威+悄悄在此留下版了個(gè)權(quán)的信息說:總結(jié)
以上是生活随笔為你收集整理的CSharpGL(29)初步封装Texture和Framebuffer的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为访问列表traffic-policy
- 下一篇: 从web移动端布局到react nati