<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Unigine整合Myra UI Library全紀錄(2):渲染

      TextureQuadBatcher

      由于Unigine沒有SpriteBatch類似物,需要手動實現一個。當然用Unigine.Ffp直接來搞也可以,只不過效率就會差一些了。

      因為我打算同時用Myra和ImGui.NET,因此這里偷了個懶,去借用Unigine示例里整合ImGui.NET用的Shader/Material了。不打算用ImGui的可以去把unigine-imgui-csharp-integration-sample\data\imgui.basemat拷貝到自己項目的data目錄下。

      接下來按照它這個Shader使用頂點的方式,定義頂點格式(其實就是ImGui的頂點格式):

      [StructLayout(LayoutKind.Sequential, Pack = 1)]
      struct VertexLayout(VertexPositionColorTexture vertexData)
      {
      	public vec2 Position = new(vertexData.Position.X, vertexData.Position.Y);
      	public vec2 TexCoord = new(vertexData.TextureCoordinate.X, vertexData.TextureCoordinate.Y);
      	public uint Color = vertexData.Color.PackedValue;
      }
      

      VertexPositionColorTexture是Myra傳遞過來的頂點數據格式。

      接下來聲明幾個會用到的常量和變量:

      const int MaxSprites = 2048;
      const int MaxVertices = MaxSprites * 4;
      const int MaxIndices = MaxSprites * 6;
      
      readonly MeshDynamic quadMesh;
      readonly Material quadMaterial;
      Texture? lastTexture;
      
      readonly VertexLayout[] vertexData = new VertexLayout[MaxVertices];
      int vertexCount;
      

      指定一次最多繪制2048個圖元,這個數量已經很多了,再多會導致Mesh的Index尺寸超過65536,效率就會有所降低(Unigine的Index是4字節int)。

      MeshDynamic是Unigine的動態Mesh對象,創建并指定頂點格式的過程也很簡單:

      quadMesh = new MeshDynamic(MeshDynamic.USAGE_DYNAMIC_VERTEX);
      var vertexFormat = new MeshDynamic.Attribute[3];
      vertexFormat[0].type = MeshDynamic.TYPE_FLOAT;
      vertexFormat[0].offset = 0;
      vertexFormat[0].size = 2;
      vertexFormat[1].type = MeshDynamic.TYPE_FLOAT;
      vertexFormat[1].offset = 8;
      vertexFormat[1].size = 2;
      vertexFormat[2].type = MeshDynamic.TYPE_UCHAR;
      vertexFormat[2].offset = 16;
      vertexFormat[2].size = 4;
      quadMesh.SetVertexFormat(vertexFormat);
      

      注意在創建的時候,指定USAGE_DYNAMIC_VERTEX,而不是USAGE_DYNAMIC_ALL。由于Myra會讓我們繪制的全都是單純的Quad,因此Index可以完全不動,提前創建好就不再更改了:

      var indexData = new int[MaxIndices];
      for (int i = 0, j = 0; i < MaxIndices; i += 6, j += 4) {
      	indexData[i + 0] = j + 0;
      	indexData[i + 1] = j + 1;
      	indexData[i + 2] = j + 2;
      	indexData[i + 3] = j + 3;
      	indexData[i + 4] = j + 2;
      	indexData[i + 5] = j + 1;
      }
      quadMesh.SetIndicesArray(indexData);
      quadMesh.FlushIndices();
      

      順便把Material也創建好:

      quadMaterial = Materials.FindManualMaterial("imgui").Inherit();
      

      基本的數據都準備好了之后,開始制作繪制Quad的過程。這里先采用和Xna的SpriteBatch類似的Begin/Draw/End結構。首先是Begin:

      public void Begin(TextureFiltering textureFiltering)
      {
      	//設置渲染狀態
      	RenderState.SaveState();
      	RenderState.ClearStates();
      	RenderState.SetBlendFunc(RenderState.BLEND_ONE, RenderState.BLEND_ONE_MINUS_SRC_ALPHA);
      	RenderState.PolygonCull = RenderState.CULL_NONE;
      	RenderState.DepthFunc = RenderState.DEPTH_NONE;
      
      	//用正交投影矩陣渲染
      	var clientRenderSize = WindowManager.MainWindow.ClientRenderSize;
      	float left = 0;
      	float right = clientRenderSize.x;
      	float top = 0;
      	float bottom = clientRenderSize.y;
      	var orthoProj = new mat4 {
      		m00 = 2.0f / (right - left),
      		m03 = (right + left) / (left - right),
      		m11 = 2.0f / (top - bottom),
      		m13 = (top + bottom) / (bottom - top),
      		m22 = 0.5f,
      		m23 = 0.5f,
      		m33 = 1.0f
      	};
      	Renderer.Projection = orthoProj;
      
      	//選定為當前渲染的Shader
      	var shader = quadMaterial.GetShaderForce("imgui");
      	var pass = quadMaterial.GetRenderPass("imgui");
      	Renderer.SetShaderParameters(pass, shader, quadMaterial, false);
      
      	//選定為當前渲染Mesh
      	quadMesh.Bind();
      }
      

      一目了然,沒什么好說的。要注意的就是RenderState.SetBlendFunc()這里,是One加上OneMinusSrcAlpha的模式,和傳統Alpha混合的SrcAlpha加OneMinusSrcAlpha模式不同。因為Myra使用的是Pre-Multiplied Alpha。

      順便把End也寫了:

      public void End()
      {
      	Flush();
      
      	//恢復渲染狀態
      	quadMesh.Unbind();
      	RenderState.RestoreState();
      }
      

      之后是和Myra對接的部分:

      public void DrawQuad(Texture texture, ref VertexPositionColorTexture topLeft, ref VertexPositionColorTexture topRight, ref VertexPositionColorTexture bottomLeft, ref VertexPositionColorTexture bottomRight)
      {
      	if (texture != lastTexture || vertexCount >= MaxVertices) {
      		Flush();
      		lastTexture = texture;
      	}
      
      	vertexData[vertexCount++] = new VertexLayout(topLeft);
      	vertexData[vertexCount++] = new VertexLayout(topRight);
      	vertexData[vertexCount++] = new VertexLayout(bottomLeft);
      	vertexData[vertexCount++] = new VertexLayout(bottomRight);
      }
      

      其實就是將Myra傳遞過來的數據緩存起來,當Texture發生了改變,或者頂點數量超過緩沖區上限了之后,再輸出。

      最后就是最重要的輸出部分了,然而這部分反而代碼很簡單:

      public void Flush()
      {
      	if (vertexCount == 0 || lastTexture == null) {
      		return;
      	}
      
      	//應用頂點數據
      	quadMesh.ClearVertex();
      	unsafe {
      		fixed (void* pVertexData = vertexData) {
      			quadMesh.SetVertexArray((nint)pVertexData, vertexCount);
      		}
      	}
      	quadMesh.FlushVertex();
      
      	//繪制
      	RenderState.SetTexture(RenderState.BIND_FRAGMENT, 0, lastTexture);
      	quadMesh.RenderSurface(MeshDynamic.MODE_TRIANGLES, 0, 0, vertexCount / 4 * 6);
      
      	//重置計數
      	vertexCount = 0;
      }
      

      Unigine提供的SetVertexArray不完整,因此這里多了一塊unsafe。

      繪制部分沒啥好說的:設置紋理,輸出三角形,通過vertexCount / 4 * 6計算得到繪制的Index總數量。

      IMyraRenderer

      MyraRenderer支持兩種模式,Sprite模式:給Xna的SpriteBatch類似物使用。Quad模式:直接繪制頂點。Unigine自然要使用Quad模式:

      RendererType IMyraRenderer.RendererType => RendererType.Quad;
      

      之后聲明幾個后面要用到的變量,并將其初始化:

      readonly TextureQuadBatcher quadBatcher = new();
      
      Rectangle currentScissor;
      bool isBeginCalled;
      
      public MyraRenderer()
      {
      	var clientRenderSize = WindowManager.MainWindow.ClientRenderSize;
      	currentScissor = new Rectangle(0, 0, clientRenderSize.x, clientRenderSize.y);
      }
      

      然后實現Myra的Scissor:

      Rectangle IMyraRenderer.Scissor
      {
      	get => currentScissor;
      	set {
      		if (value != currentScissor) {
      			Flush();
      			currentScissor = value;
      
      			var clientRenderSize = WindowManager.MainWindow.ClientRenderSize;
      			int y = clientRenderSize.y - (currentScissor.Y + currentScissor.Height); //ScissorTest是右手坐標系,Y軸從屏幕下方往上數
      			RenderState.SetScissorTest((float)currentScissor.X / clientRenderSize.x, (float)y / clientRenderSize.y, (float)currentScissor.Width / clientRenderSize.x, (float)currentScissor.Height / clientRenderSize.y);
      		}
      	}
      }
      

      每次Scissor變化的時候,都要將已有的緩存刷新,再調用RenderState.SetScissorTest。由于Unigine是右手坐標系,屏幕左下角是(0.0f,0.0f),右上角是(1.0f,1.0f)。而Myra傳遞過來的是傳統的屏幕像素坐標,左上角為(0,0)右下角是(ClientRenderSize.x,ClientRenderSize.y),因此這里要對坐標系進行轉換。

      剩下的幾個接口就很簡單了,把相應的參數傳給TextureQuadBatcher就可以。

      void IMyraRenderer.Begin(TextureFiltering textureFiltering)
      {
      	quadBatcher.Begin(textureFiltering);
      	isBeginCalled = true;
      }
      
      void IMyraRenderer.End()
      {
      	quadBatcher.End();
      	isBeginCalled = false;
      }
      
      void IMyraRenderer.DrawSprite(object texture, Vector2 pos, Rectangle? src, FSColor color, float rotation, Vector2 scale, float depth)
      {
      	//ignored
      }
      
      void IMyraRenderer.DrawQuad(object texture, ref VertexPositionColorTexture topLeft, ref VertexPositionColorTexture topRight, ref VertexPositionColorTexture bottomLeft, ref VertexPositionColorTexture bottomRight)
      {
      	quadBatcher.DrawQuad((Texture)texture, ref topLeft, ref topRight, ref bottomLeft, ref bottomRight);
      }
      
      void Flush()
      {
      	if (isBeginCalled) {
      		quadBatcher.Flush();
      	}
      }
      

      DrawSprite/DrawQuad二者只需實現其一,前面選擇了哪個模式就實現哪個模式即可。

      如此一來渲染的部分就實現完成了。這并不是效率最高的實現方式,但概念上最簡單。目前先這么做,先讓程序跑起來再優化。

      posted @ 2025-09-26 15:42  horeaper  閱讀(84)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲av永久无码精品水牛影视| 亚洲日韩av无码| 四虎永久精品免费视频| 国产成人片无码视频在线观看| 亚洲国产成人资源在线 | www射我里面在线观看| 国产亚洲一区二区三区av| 精品国产自线午夜福利| 国产又色又爽又高潮免费| 欧美xxxxhd高清| 亚洲第一视频区| 一级国产在线观看高清| 人妻少妇一区二区三区| 亚洲色偷拍区另类无码专区| 亚洲一区二区三区久久受| 天天爽夜夜爱| 天堂资源在线| 91久久精品国产性色也| 亚洲一区二区中文av| 护士张开腿被奷日出白浆| 国产精品午夜福利资源| 欧美成人va免费大片视频| 久久热精品视频在线视频| 亚洲国产韩国欧美在线 | 通海县| 中文毛片无遮挡高潮免费| 九九色这里只有精品国产| 久久夜色精品国产亚av| 国内精品一区二区不卡| 精品国产AV无码一区二区三区| 午夜福利片1000无码免费| 内射毛片内射国产夫妻| 东京热人妻无码人av| 天堂中文在线资源| 国产午夜福利在线视频| 国产精品论一区二区三区| 亚洲最大福利视频网| 亚洲大尺度一区二区av| 国产老熟女狂叫对白| 国产精品一二三区蜜臀av| 九九热免费精品视频在线|