- added materials
- simplified uniforms set - autogenerated gl interface
This commit is contained in:
Родитель
6aec0e58cb
Коммит
c392814c5a
|
@ -23,6 +23,9 @@
|
|||
<None Update="data\cube.obj">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="data\monkey.obj">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="0.10.12" />
|
||||
|
|
|
@ -10,6 +10,7 @@ using SomeChartsUi.themes.themes;
|
|||
using SomeChartsUi.ui.elements;
|
||||
using SomeChartsUi.utils;
|
||||
using SomeChartsUi.utils.mesh;
|
||||
using SomeChartsUi.utils.shaders;
|
||||
using SomeChartsUi.utils.vectors;
|
||||
using SomeChartsUiAvalonia.controls;
|
||||
using SomeChartsUiAvalonia.controls.gl;
|
||||
|
@ -46,7 +47,9 @@ public static class ElementsExamples {
|
|||
r.transform = new(new(0, -100), float3.one * 32, 0);
|
||||
canvas.AddElement(r);
|
||||
r.GenerateMesh();
|
||||
r.shader = GlShaders.diffuse;
|
||||
r.material = new(GlShaders.diffuse);
|
||||
//r.material.SetProperty("lightCol", new float3(1,0,0));
|
||||
r.material.SetProperty("shininess", 32);
|
||||
MeshRenderer r2 = r;
|
||||
r.beforeRender += () => {
|
||||
float time = (float)DateTime.Now.TimeOfDay.TotalMilliseconds;
|
||||
|
|
|
@ -27,7 +27,7 @@ public abstract class ChartsBackendBase {
|
|||
|
||||
public abstract void ClearScreen(color col);
|
||||
|
||||
public abstract void DrawMesh(Mesh mesh, Shader? shader, RenderableTransform transform);
|
||||
public abstract void DrawMesh(Mesh mesh, Material? material, RenderableTransform transform);
|
||||
|
||||
//public abstract void DestroyObject(RenderableBase obj);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ public abstract partial class RenderableBase {
|
|||
/// <summary>set to true if data updates frequently <br/>default is false <br/>affects on caching in some elements</summary>
|
||||
public bool isDynamic = false;
|
||||
|
||||
public Shader? shader;
|
||||
public Material? material;
|
||||
|
||||
public RenderableBase(ChartsCanvas owner) {
|
||||
canvas = owner;
|
||||
|
@ -32,7 +32,7 @@ public abstract partial class RenderableBase {
|
|||
public void Render() {
|
||||
beforeRender();
|
||||
if (CheckMeshForUpdate()) GenerateMesh();
|
||||
DrawMesh(shader);
|
||||
DrawMesh(material);
|
||||
AfterDraw();
|
||||
}
|
||||
//protected abstract void Render();
|
||||
|
|
|
@ -25,8 +25,8 @@ public abstract partial class RenderableBase {
|
|||
// protected void DrawVertices(float2[] points, float2[]? uvs, color[]? colors, ushort[] indexes) =>
|
||||
// renderer.backend.DrawMesh(points, uvs, colors, indexes, transform.Get(this));
|
||||
|
||||
protected void DrawMesh(Shader? shader) {
|
||||
canvas.renderer.backend.DrawMesh(mesh!, shader, transform);
|
||||
protected void DrawMesh(Material? material) {
|
||||
canvas.renderer.backend.DrawMesh(mesh!, material, transform);
|
||||
}
|
||||
|
||||
protected void DrawText(string txt, float2 pos, color col, FontData font, float scale = 12) =>
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
namespace SomeChartsUi.utils.shaders;
|
||||
|
||||
public class Material {
|
||||
public Shader shader;
|
||||
|
||||
public List<MaterialProperty> properties = new();
|
||||
|
||||
public Material(Shader shader) => this.shader = shader;
|
||||
public Material(Shader shader, params MaterialProperty[] properties) : this(shader) => this.properties = properties.ToList();
|
||||
public Material(Shader shader, params (string name, object val)[] properties) : this(shader) => this.properties = properties.Select(v => new MaterialProperty(v.name, v.val)).ToList();
|
||||
|
||||
public void SetProperty<T>(string name, T v) {
|
||||
int index = properties.FindIndex(p => p.name == name);
|
||||
if (index == -1) properties.Add(new(name, v!));
|
||||
else properties[index].value = v!;
|
||||
}
|
||||
}
|
||||
|
||||
public class MaterialProperty {
|
||||
public readonly string name;
|
||||
public object value;
|
||||
|
||||
public MaterialProperty(string name, object value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,8 @@ public class Shader {
|
|||
public string vertexShaderSrc;
|
||||
public string fragmentShaderSrc;
|
||||
|
||||
public ShaderUniform[] uniforms = Array.Empty<ShaderUniform>();
|
||||
|
||||
public Shader(string name, string vertexShaderSrc, string fragmentShaderSrc) {
|
||||
this.name = name;
|
||||
this.vertexShaderSrc = vertexShaderSrc;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
namespace SomeChartsUi.utils.shaders;
|
||||
|
||||
public readonly struct ShaderUniform {
|
||||
public readonly string name;
|
||||
public readonly int location = -1;
|
||||
public readonly int type;
|
||||
public readonly int size;
|
||||
|
||||
public ShaderUniform(string name, int location, int type, int size) {
|
||||
this.name = name;
|
||||
this.location = location;
|
||||
this.type = type;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public override string ToString() => $"(loc:{location}, name:'{name}', type:{type}, size:{size})";
|
||||
}
|
|
@ -14,6 +14,10 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove=".gitignore" />
|
||||
<None Update="src\controls\gl\GlInterfaceGen.tt">
|
||||
<Generator>TextTemplatingFileGenerator</Generator>
|
||||
<LastGenOutput>GlInterfaceGen.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="0.10.12" />
|
||||
|
@ -31,4 +35,11 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\SomeChartsUi\SomeChartsUi.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="src\controls\gl\GlInterfaceGen.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>GlInterfaceGen.tt</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -40,7 +40,7 @@ public class GlChartsBackend : ChartsBackendBase {
|
|||
gl.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
public override void DrawMesh(Mesh mesh, Shader? shader, RenderableTransform transform) {
|
||||
public override void DrawMesh(Mesh mesh, Material? material, RenderableTransform transform) {
|
||||
if (mesh is not GlMesh obj) throw new NotImplementedException("opengl backend support only GlMesh mesh type; use CreateMesh() in ChartsBackendBase");
|
||||
|
||||
GlMesh.gl = gl;
|
||||
|
@ -56,14 +56,14 @@ public class GlChartsBackend : ChartsBackendBase {
|
|||
|
||||
float3 camPos = owner.transform.position.animatedValue;
|
||||
//Console.WriteLine(camPos);
|
||||
Matrix4x4 view = Matrix4x4.CreateLookAt(new(camPos.x, -camPos.y, z), new(camPos.x,-camPos.y,0), new(0, 1, 0));
|
||||
Matrix4x4 view = Matrix4x4.CreateLookAt(new(-camPos.x, camPos.y, z), new(-camPos.x,camPos.y,0), new(0, -1, 0));
|
||||
|
||||
float3 p = transform.position;
|
||||
// Matrix4x4 model = Matrix4x4.CreateScale(new Vector3(transform.scale.x, transform.scale.y, transform.scale.z), new(p.x, -p.y, p.z));
|
||||
Matrix4x4 model = Matrix4x4.CreateFromYawPitchRoll(transform.rotation.x, transform.rotation.y, transform.rotation.z) * Matrix4x4.CreateScale(new Vector3(transform.scale.x, -transform.scale.y, transform.scale.z)) * Matrix4x4.CreateTranslation(new(p.x, -p.y, p.z));
|
||||
Matrix4x4 model = Matrix4x4.CreateFromYawPitchRoll(transform.rotation.x, transform.rotation.y, transform.rotation.z) * Matrix4x4.CreateScale(new Vector3(transform.scale.x, transform.scale.y, transform.scale.z)) * Matrix4x4.CreateTranslation(new(p.x, -p.y, p.z));
|
||||
// Matrix4x4 model = Matrix4x4.CreateTranslation(new(p.x, -p.y, p.z));
|
||||
|
||||
obj.Render(shader, model, view, projection, camPos);
|
||||
obj.Render(material, model, view, projection, camPos);
|
||||
}
|
||||
|
||||
public override Mesh CreateMesh() => new GlMesh();
|
||||
|
|
|
@ -86,7 +86,7 @@ public class SkiaChartsBackend : ChartsBackendBase, IDisposable {
|
|||
public override void ClearScreen(color col) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public override void DrawMesh(Mesh mesh, Shader? shader, RenderableTransform transform) {
|
||||
public override void DrawMesh(Mesh mesh, Material? material, RenderableTransform transform) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
// public override void DrawRect(rect rectangle, color color) {
|
||||
|
|
|
@ -20,7 +20,7 @@ public class AvaloniaGlCanvasUiController : CanvasUiControllerBase {
|
|||
public override void OnKey(keycode key, keymods mods) {
|
||||
base.OnKey(key, mods);
|
||||
|
||||
if (key == keycode.y) GlMesh.wireframeMode = !GlMesh.wireframeMode;
|
||||
if (key == keycode.y) AvaloniaGlChartsCanvas.polygonMode = (PolygonMode)(((int)AvaloniaGlChartsCanvas.polygonMode + 1) % 3);
|
||||
if (key == keycode.p) GlChartsBackend.perspectiveMode = !GlChartsBackend.perspectiveMode;
|
||||
}
|
||||
}
|
|
@ -26,9 +26,17 @@ using static Avalonia.OpenGL.GlConsts;
|
|||
|
||||
namespace SomeChartsUiAvalonia.controls.gl;
|
||||
|
||||
public enum PolygonMode {
|
||||
fill,
|
||||
line,
|
||||
points
|
||||
}
|
||||
|
||||
public class AvaloniaGlChartsCanvas : OpenGlControlBase {
|
||||
private GlExtrasInterface _glExtras;
|
||||
public readonly ChartsCanvas canvas = CreateCanvas();
|
||||
|
||||
public static PolygonMode polygonMode = PolygonMode.fill;
|
||||
|
||||
/// <summary>pause redraw loop</summary>
|
||||
public bool stopRender;
|
||||
|
@ -66,6 +74,7 @@ public class AvaloniaGlChartsCanvas : OpenGlControlBase {
|
|||
GlMesh.glExtras = _glExtras;
|
||||
GlShader.glVersion = GlVersion;
|
||||
GlShader.gl = gl;
|
||||
GlShader.glExtras = _glExtras;
|
||||
GlChartsBackend.gl = gl;
|
||||
}
|
||||
|
||||
|
@ -81,8 +90,13 @@ public class AvaloniaGlChartsCanvas : OpenGlControlBase {
|
|||
gl.Enable(GL_DEPTH_TEST);
|
||||
|
||||
gl.Enable(GL_MULTISAMPLE);
|
||||
gl.Enable(GL_CULL_FACE);
|
||||
_glExtras.CullFace(GL_FRONT);
|
||||
switch (polygonMode) {
|
||||
case PolygonMode.fill: _glExtras.PolygonMode(GL_FRONT_AND_BACK, GL_FILL); break;
|
||||
case PolygonMode.line: _glExtras.PolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
|
||||
case PolygonMode.points: _glExtras.PolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
|
||||
}
|
||||
//gl.Enable(GL_CULL_FACE);
|
||||
//_glExtras.CullFace(GL_FRONT);
|
||||
|
||||
gl.Viewport(0, 0, (int)Bounds.Width, (int)Bounds.Height);
|
||||
|
||||
|
@ -370,53 +384,4 @@ void main() {
|
|||
gl_FragColor = fragCol;
|
||||
}
|
||||
");*/
|
||||
}
|
||||
|
||||
public class GlExtrasInterface : GlInterfaceBase<GlInterface.GlContextInfo>
|
||||
{
|
||||
public delegate void GlDeleteVertexArrays(int count, int[] buffers);
|
||||
public delegate void GlBindVertexArray(int array);
|
||||
public delegate void GlGenVertexArrays(int n, int[] rv);
|
||||
public unsafe delegate void GlBufferSubData(int trgt, nint offset, nint size, void* data);
|
||||
public delegate void GlCullFace(int n);
|
||||
|
||||
public delegate void GlUniform2f(int location, float x, float y);
|
||||
public delegate void GlUniform3f(int location, float x, float y, float z);
|
||||
public delegate void GlUniform4f(int location, float x, float y, float z, float w);
|
||||
|
||||
public GlExtrasInterface(GlInterface gl) : base(gl.GetProcAddress, gl.ContextInfo) { }
|
||||
|
||||
[GlMinVersionEntryPoint("glDeleteVertexArrays", 3,0)]
|
||||
[GlExtensionEntryPoint("glDeleteVertexArraysOES", "GL_OES_vertex_array_object")]
|
||||
public GlDeleteVertexArrays DeleteVertexArrays { get; } = null!;
|
||||
|
||||
[GlMinVersionEntryPoint("glBindVertexArray", 3,0)]
|
||||
[GlExtensionEntryPoint("glBindVertexArrayOES", "GL_OES_vertex_array_object")]
|
||||
public GlBindVertexArray BindVertexArray { get; } = null!;
|
||||
|
||||
[GlMinVersionEntryPoint("glGenVertexArrays",3,0)]
|
||||
[GlExtensionEntryPoint("glGenVertexArraysOES", "GL_OES_vertex_array_object")]
|
||||
public GlGenVertexArrays GenVertexArrays { get; } = null!;
|
||||
|
||||
[GlEntryPoint("glCullFace")]
|
||||
public GlCullFace CullFace { get; } = null!;
|
||||
|
||||
[GlEntryPoint("glUniform2f")]
|
||||
public GlUniform2f Uniform2f { get; } = null!;
|
||||
|
||||
[GlEntryPoint("glUniform3f")]
|
||||
public GlUniform3f Uniform3f { get; } = null!;
|
||||
|
||||
[GlEntryPoint("glUniform4f")]
|
||||
public GlUniform4f Uniform4f { get; } = null!;
|
||||
|
||||
[GlEntryPoint("glBufferSubData")]
|
||||
public GlBufferSubData BufferSubData { get; } = null!;
|
||||
|
||||
public int GenVertexArray()
|
||||
{
|
||||
int[] rv = new int[1];
|
||||
GenVertexArrays(1, rv);
|
||||
return rv[0];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using Avalonia.OpenGL;
|
||||
|
||||
namespace SomeChartsUiAvalonia.controls.gl;
|
||||
|
||||
public class GlExtrasInterface : GlInterfaceBase<GlInterface.GlContextInfo>
|
||||
{
|
||||
public GlExtrasInterface(GlInterface gl) : base(gl.GetProcAddress, gl.ContextInfo) { }
|
||||
|
||||
[GlEntryPoint("glDeleteVertexArrays")]
|
||||
public GlDeleteVertexArrays DeleteVertexArrays { get; } = null!;
|
||||
public unsafe delegate void GlDeleteVertexArrays(int count, int[] buffers);
|
||||
|
||||
[GlEntryPoint("glBindVertexArray")]
|
||||
public GlBindVertexArray BindVertexArray { get; } = null!;
|
||||
public unsafe delegate void GlBindVertexArray(int array);
|
||||
|
||||
[GlEntryPoint("glGenVertexArrays")]
|
||||
public GlGenVertexArrays GenVertexArrays { get; } = null!;
|
||||
public unsafe delegate void GlGenVertexArrays(int count, int[] arrays);
|
||||
|
||||
[GlEntryPoint("glBufferSubData")]
|
||||
public GlBufferSubData BufferSubData { get; } = null!;
|
||||
public unsafe delegate void GlBufferSubData(int buffer, int offset, int size, void* data);
|
||||
|
||||
[GlEntryPoint("glCullFace")]
|
||||
public GlCullFace CullFace { get; } = null!;
|
||||
public unsafe delegate void GlCullFace(int face);
|
||||
|
||||
[GlEntryPoint("glUniform2f")]
|
||||
public GlUniform2f Uniform2f { get; } = null!;
|
||||
public unsafe delegate void GlUniform2f(int location, float x, float y);
|
||||
|
||||
[GlEntryPoint("glUniform3f")]
|
||||
public GlUniform3f Uniform3f { get; } = null!;
|
||||
public unsafe delegate void GlUniform3f(int location, float x, float y, float z);
|
||||
|
||||
[GlEntryPoint("glUniform4f")]
|
||||
public GlUniform4f Uniform4f { get; } = null!;
|
||||
public unsafe delegate void GlUniform4f(int location, float x, float y, float z, float w);
|
||||
|
||||
[GlEntryPoint("glGetActiveUniform")]
|
||||
public GlGetActiveUniform GetActiveUniform { get; } = null!;
|
||||
public unsafe delegate void GlGetActiveUniform(int program, int index, int bufferSize, int* length, int* size, int* type, sbyte* name);
|
||||
|
||||
[GlEntryPoint("glPolygonMode")]
|
||||
public GlPolygonMode PolygonMode { get; } = null!;
|
||||
public unsafe delegate void GlPolygonMode(int face, int mode);
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<#@ template language="C#v3.5" #>
|
||||
<#@ import namespace="System"#>
|
||||
<#@ import namespace="System.Text"#>
|
||||
<#@ import namespace="System.Collections"#>
|
||||
<#@ import namespace="System.Collections.Generic"#>
|
||||
<#@ assembly name="System.Core"#>
|
||||
<#@ import namespace="System.Linq"#>
|
||||
<#
|
||||
var functions = new[] {
|
||||
new{name = "DeleteVertexArrays", ret = "void", args = "int count, int[] buffers"},
|
||||
new{name = "BindVertexArray", ret = "void", args = "int array"},
|
||||
new{name = "GenVertexArrays", ret = "void", args = "int count, int[] arrays"},
|
||||
new{name = "BufferSubData", ret = "void", args = "int buffer, int offset, int size, void* data"},
|
||||
new{name = "CullFace", ret = "void", args = "int face"},
|
||||
|
||||
new{name = "Uniform2f", ret = "void", args = "int location, float x, float y"},
|
||||
new{name = "Uniform3f", ret = "void", args = "int location, float x, float y, float z"},
|
||||
new{name = "Uniform4f", ret = "void", args = "int location, float x, float y, float z, float w"},
|
||||
|
||||
new{name = "GetActiveUniform", ret = "void", args = "int program, int index, int bufferSize, int* length, int* size, int* type, sbyte* name"},
|
||||
|
||||
new{name = "PolygonMode", ret = "void", args = "int face, int mode"},
|
||||
};
|
||||
#>
|
||||
using Avalonia.OpenGL;
|
||||
|
||||
namespace SomeChartsUiAvalonia.controls.gl;
|
||||
|
||||
public class GlExtrasInterface : GlInterfaceBase<GlInterface.GlContextInfo>
|
||||
{
|
||||
public GlExtrasInterface(GlInterface gl) : base(gl.GetProcAddress, gl.ContextInfo) { }
|
||||
|
||||
<#
|
||||
foreach (var function in functions) {
|
||||
#>
|
||||
[GlEntryPoint("<#=$"gl{function.name}"#>")]
|
||||
public <#=$"Gl{function.name}"#> <#=function.name#> { get; } = null!;
|
||||
public unsafe delegate <#=function.ret#> <#=$"Gl{function.name}"#>(<#=function.args#>);
|
||||
|
||||
<#
|
||||
}
|
||||
#>
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using Avalonia.OpenGL;
|
||||
using SomeChartsUi.utils.shaders;
|
||||
using SomeChartsUi.utils.vectors;
|
||||
using SomeChartsUiAvalonia.controls.gl;
|
||||
|
||||
namespace SomeChartsUiAvalonia.utils;
|
||||
|
||||
public class GlShader : Shader {
|
||||
public static GlVersion glVersion;
|
||||
public static GlInterface? gl;
|
||||
public static GlExtrasInterface? glExtras;
|
||||
public int vertexShader;
|
||||
public int fragmentShader;
|
||||
public int shaderProgram;
|
||||
|
||||
public void TryCompile() {
|
||||
if (gl == null) return;
|
||||
GetUniforms();
|
||||
|
||||
vertexShader = gl.CreateShader(GlConsts.GL_VERTEX_SHADER);
|
||||
Console.WriteLine(gl.CompileShaderAndGetError(vertexShader, vertexShaderSrc));
|
||||
|
||||
fragmentShader = gl.CreateShader(GlConsts.GL_FRAGMENT_SHADER);
|
||||
Console.WriteLine(gl.CompileShaderAndGetError(fragmentShader, fragmentShaderSrc));
|
||||
|
||||
shaderProgram = gl.CreateProgram();
|
||||
gl.AttachShader(shaderProgram, vertexShader);
|
||||
gl.AttachShader(shaderProgram, fragmentShader);
|
||||
|
||||
const int posLoc = 0;
|
||||
const int normalLoc = 1;
|
||||
const int uvLoc = 2;
|
||||
const int colLoc = 3;
|
||||
gl.BindAttribLocationString(shaderProgram, posLoc, "pos");
|
||||
gl.BindAttribLocationString(shaderProgram, normalLoc, "normal");
|
||||
gl.BindAttribLocationString(shaderProgram, uvLoc, "uv");
|
||||
gl.BindAttribLocationString(shaderProgram, colLoc, "col");
|
||||
|
||||
Console.WriteLine(gl.LinkProgramAndGetError(shaderProgram));
|
||||
|
||||
GetUniforms();
|
||||
}
|
||||
|
||||
public static string ProcessShader(bool isFragment, string shader) {
|
||||
bool isOsX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
bool isOpenGles = glVersion.Type == GlProfileType.OpenGLES;
|
||||
|
||||
shader = shader.Replace("// ADD ATTRIBUTES", @"
|
||||
attribute vec3 pos;
|
||||
attribute vec3 normal;
|
||||
attribute vec2 uv;
|
||||
attribute vec4 col;")
|
||||
.Replace("// ADD MATRICES", @"
|
||||
uniform mat4 model;
|
||||
uniform mat4 projection;
|
||||
uniform mat4 view;");
|
||||
|
||||
int version = !isOpenGles ? isOsX ? 150 : 120 : 100;
|
||||
|
||||
string data = "#version " + version + "\n";
|
||||
if (isOpenGles) data += "precision mediump float;\n";
|
||||
if (version >= 150)
|
||||
{
|
||||
shader = shader.Replace("attribute", "in");
|
||||
if (isFragment)
|
||||
shader = shader
|
||||
.Replace("varying", "in")
|
||||
.Replace("// DECLAREGLFRAG", "out vec4 outFragColor;")
|
||||
.Replace("gl_FragColor", "outFragColor");
|
||||
else
|
||||
shader = shader.Replace("varying", "out");
|
||||
}
|
||||
|
||||
data += shader.Replace("// PROCESS VERTEX", "").Replace("// PROCESS FRAGMENT", "");
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public GlShader(string name, string vertexShaderSrc, string fragmentShaderSrc) : base(name, vertexShaderSrc, fragmentShaderSrc) {
|
||||
if (vertexShaderSrc.Trim().StartsWith("// PROCESS VERTEX")) this.vertexShaderSrc = ProcessShader(false, vertexShaderSrc);
|
||||
if (fragmentShaderSrc.Trim().StartsWith("// PROCESS FRAGMENT")) this.fragmentShaderSrc = ProcessShader(true, fragmentShaderSrc);
|
||||
}
|
||||
|
||||
private unsafe void GetUniforms() {
|
||||
int uniformCount = 0;
|
||||
gl!.GetProgramiv(shaderProgram, GlConsts.GL_ACTIVE_UNIFORMS, &uniformCount);
|
||||
|
||||
const int stringBufferSize = 32;
|
||||
sbyte* namePtr = stackalloc sbyte[stringBufferSize];
|
||||
int size = 0; // size of var
|
||||
int length = 0; // name length
|
||||
int type = 0; // type of var
|
||||
|
||||
uniforms = new ShaderUniform[uniformCount];
|
||||
for (int i = 0; i < uniformCount; i++) {
|
||||
glExtras!.GetActiveUniform(shaderProgram, i, stringBufferSize, &length, &size, &type, namePtr);
|
||||
string varName = new(namePtr, 0, length);
|
||||
uniforms[i] = new(varName, i, type, size);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void TrySetUniform<T>(string uniformName, T v) {
|
||||
int loc = uniforms.FirstOrDefault(u => u.name == uniformName).location;
|
||||
if (loc == -1) return;
|
||||
|
||||
gl!.UseProgram(shaderProgram);
|
||||
|
||||
switch (v) {
|
||||
case float v0: gl.Uniform1f(loc, v0); return;
|
||||
case float2 v0: glExtras!.Uniform2f(loc, v0.x, v0.y); return;
|
||||
case float3 v0: glExtras!.Uniform3f(loc, v0.x, v0.y, v0.z); return;
|
||||
case float4 v0: glExtras!.Uniform4f(loc, v0.x, v0.y, v0.z, v0.w); return;
|
||||
case Matrix4x4 v0: gl.UniformMatrix4fv(loc, 1, false, &v0); return;
|
||||
case object obj:
|
||||
switch (obj) {
|
||||
case float v0: gl.Uniform1f(loc, v0); return;
|
||||
case float2 v0: glExtras!.Uniform2f(loc, v0.x, v0.y); return;
|
||||
case float3 v0: glExtras!.Uniform3f(loc, v0.x, v0.y, v0.z); return;
|
||||
case float4 v0: glExtras!.Uniform4f(loc, v0.x, v0.y, v0.z, v0.w); return;
|
||||
case Matrix4x4 v0: gl.UniformMatrix4fv(loc, 1, false, &v0); return;
|
||||
}
|
||||
return;
|
||||
default: throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public void TryApplyMaterial(Material mat) {
|
||||
foreach (MaterialProperty property in mat.properties)
|
||||
TrySetUniform(property.name, property.value);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Avalonia.OpenGL;
|
||||
using SomeChartsUi.utils.shaders;
|
||||
using static Avalonia.OpenGL.GlConsts;
|
||||
|
||||
namespace SomeChartsUiAvalonia.utils;
|
||||
|
||||
public static class GlShaders {
|
||||
|
@ -62,6 +56,7 @@ void main() {
|
|||
fragPos = vec3(model * vec4(pos,1.0));
|
||||
fragUv = uv;
|
||||
fragCol = col;
|
||||
//fragNormal = normal;
|
||||
fragNormal = normalize(mat3(transpose(inverse(model))) * normal);
|
||||
}
|
||||
", @"
|
||||
|
@ -75,98 +70,27 @@ varying vec4 fragCol;
|
|||
|
||||
uniform vec3 cameraPos;
|
||||
|
||||
uniform vec3 lightDir = normalize(vec3(-0.2,1,0.1));
|
||||
uniform float time = 0;
|
||||
uniform vec3 lightDirr = normalize(vec3(10,-1,-1));
|
||||
uniform float lightIntensity = 2;
|
||||
uniform vec3 lightCol = vec3(1, 0.6, 0.4);
|
||||
uniform vec3 ambientCol = vec3(0.1, 0.1, 0.15);
|
||||
uniform vec3 lightCol = vec3(255/255.0, 139/255.0, 73/255.0);
|
||||
uniform vec3 ambientCol = vec3(6/255.0, 12/255.0, 45/255.0);
|
||||
uniform vec3 diffuseCol = vec3(0.7, 0.7, 0.8);
|
||||
uniform float specularIntensity = 0.5;
|
||||
uniform float shininess = 4;
|
||||
uniform float specularIntensity = 2.5;
|
||||
|
||||
void main() {
|
||||
vec3 lightDir = normalize(vec3(sin(time * 0.001) * 10, sin(time * 0.0001) * 10, sin(time * 0.0005) * 20));
|
||||
|
||||
vec3 viewDir = normalize(cameraPos - fragPos);
|
||||
vec3 reflectDir = reflect(-lightDir, fragNormal);
|
||||
float specularStrength = pow(max(dot(viewDir, reflectDir), 0.0), 32);
|
||||
vec3 halfwayDir = normalize(lightDir + viewDir);
|
||||
float specularStrength = pow(max(dot(fragNormal, halfwayDir), 0.0), shininess);
|
||||
vec3 specular = specularIntensity * specularStrength * lightCol;
|
||||
|
||||
float diff = max(dot(fragNormal,lightDir), 0);
|
||||
vec3 diffuse = diff * lightCol * diffuseCol * lightIntensity;
|
||||
vec3 diffuse = diff * lightCol * lightIntensity;
|
||||
|
||||
gl_FragColor = vec4(diffuse + ambientCol + specular, 1);
|
||||
}
|
||||
");
|
||||
}
|
||||
|
||||
public class GlShader : Shader {
|
||||
|
||||
|
||||
public static GlVersion glVersion;
|
||||
public static GlInterface? gl;
|
||||
public int vertexShader;
|
||||
public int fragmentShader;
|
||||
public int shaderProgram;
|
||||
|
||||
public void TryCompile() {
|
||||
if (gl == null) return;
|
||||
|
||||
vertexShader = gl.CreateShader(GL_VERTEX_SHADER);
|
||||
Console.WriteLine(gl.CompileShaderAndGetError(vertexShader, vertexShaderSrc));
|
||||
|
||||
fragmentShader = gl.CreateShader(GL_FRAGMENT_SHADER);
|
||||
Console.WriteLine(gl.CompileShaderAndGetError(fragmentShader, fragmentShaderSrc));
|
||||
|
||||
shaderProgram = gl.CreateProgram();
|
||||
gl.AttachShader(shaderProgram, vertexShader);
|
||||
gl.AttachShader(shaderProgram, fragmentShader);
|
||||
|
||||
const int posLoc = 0;
|
||||
const int normalLoc = 1;
|
||||
const int uvLoc = 2;
|
||||
const int colLoc = 3;
|
||||
gl.BindAttribLocationString(shaderProgram, posLoc, "pos");
|
||||
gl.BindAttribLocationString(shaderProgram, normalLoc, "normal");
|
||||
gl.BindAttribLocationString(shaderProgram, uvLoc, "uv");
|
||||
gl.BindAttribLocationString(shaderProgram, colLoc, "col");
|
||||
|
||||
Console.WriteLine(gl.LinkProgramAndGetError(shaderProgram));
|
||||
}
|
||||
|
||||
public static string ProcessShader(bool isFragment, string shader) {
|
||||
bool isOsX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
bool isOpenGles = glVersion.Type == GlProfileType.OpenGLES;
|
||||
|
||||
shader = shader.Replace("// ADD ATTRIBUTES", @"
|
||||
attribute vec3 pos;
|
||||
attribute vec3 normal;
|
||||
attribute vec2 uv;
|
||||
attribute vec4 col;")
|
||||
.Replace("// ADD MATRICES", @"
|
||||
uniform mat4 model;
|
||||
uniform mat4 projection;
|
||||
uniform mat4 view;");
|
||||
|
||||
int version = !isOpenGles ? isOsX ? 150 : 120 : 100;
|
||||
|
||||
string data = "#version " + version + "\n";
|
||||
if (isOpenGles) data += "precision mediump float;\n";
|
||||
if (version >= 150)
|
||||
{
|
||||
shader = shader.Replace("attribute", "in");
|
||||
if (isFragment)
|
||||
shader = shader
|
||||
.Replace("varying", "in")
|
||||
.Replace("// DECLAREGLFRAG", "out vec4 outFragColor;")
|
||||
.Replace("gl_FragColor", "outFragColor");
|
||||
else
|
||||
shader = shader.Replace("varying", "out");
|
||||
}
|
||||
|
||||
data += shader.Replace("// PROCESS VERTEX", "").Replace("// PROCESS FRAGMENT", "");
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public GlShader(string name, string vertexShaderSrc, string fragmentShaderSrc) : base(name, vertexShaderSrc, fragmentShaderSrc) {
|
||||
if (vertexShaderSrc.Trim().StartsWith("// PROCESS VERTEX")) this.vertexShaderSrc = ProcessShader(false, vertexShaderSrc);
|
||||
if (fragmentShaderSrc.Trim().StartsWith("// PROCESS FRAGMENT")) this.fragmentShaderSrc = ProcessShader(true, fragmentShaderSrc);
|
||||
}
|
||||
}
|
|
@ -32,7 +32,8 @@ public class GlMesh : Mesh {
|
|||
gl.GenBuffers(2, buffers);
|
||||
vertexBufferObject = buffers[0];
|
||||
indexBufferObject = buffers[1];
|
||||
vertexArrayObject = glExtras.GenVertexArray();
|
||||
glExtras.GenVertexArrays(1, buffers);
|
||||
vertexArrayObject = buffers[0];
|
||||
|
||||
BindBuffers();
|
||||
|
||||
|
@ -95,27 +96,24 @@ public class GlMesh : Mesh {
|
|||
|
||||
public override void OnModified() => updateRequired = true;
|
||||
|
||||
public unsafe void Render(Shader? shader, Matrix4x4 model, Matrix4x4 view, Matrix4x4 projection, float3 cameraPos) {
|
||||
public unsafe void Render(Material? material, Matrix4x4 model, Matrix4x4 view, Matrix4x4 projection, float3 cameraPos) {
|
||||
if (vertexArrayObject == 0) GenBuffers();
|
||||
if (vertexArrayObject == 0) return;
|
||||
if (shader != null && shader is not GlShader) return;
|
||||
if (material is {shader: not GlShader}) return;
|
||||
|
||||
if (updateRequired | isDynamic) UpdateBuffers();
|
||||
GlShader shaderData = shader == null ? GlShaders.basic : (GlShader) shader;
|
||||
if (shaderData.shaderProgram == 0) shaderData.TryCompile();
|
||||
if (shaderData.shaderProgram == 0) return;
|
||||
GlShader shader = material == null ? GlShaders.basic : (GlShader) material.shader;
|
||||
if (shader.shaderProgram == 0) shader.TryCompile();
|
||||
if (shader.shaderProgram == 0) return;
|
||||
|
||||
gl!.UseProgram(shaderData.shaderProgram);
|
||||
gl!.UseProgram(shader.shaderProgram);
|
||||
|
||||
int modelLoc = gl.GetUniformLocationString(shaderData.shaderProgram, "model");
|
||||
int viewLoc = gl.GetUniformLocationString(shaderData.shaderProgram, "view");
|
||||
int projectionLoc = gl.GetUniformLocationString(shaderData.shaderProgram, "projection");
|
||||
int cameraLoc = gl.GetUniformLocationString(shaderData.shaderProgram, "cameraPos");
|
||||
|
||||
gl.UniformMatrix4fv(modelLoc, 1, false, &model);
|
||||
gl.UniformMatrix4fv(viewLoc, 1, false, &view);
|
||||
gl.UniformMatrix4fv(projectionLoc, 1, false, &projection);
|
||||
if (cameraLoc != -1) glExtras!.Uniform3f(cameraLoc, cameraPos.x, cameraPos.y, cameraPos.z);
|
||||
shader.TrySetUniform("model", model);
|
||||
shader.TrySetUniform("view", view);
|
||||
shader.TrySetUniform("projection", projection);
|
||||
shader.TrySetUniform("cameraPos", cameraPos);
|
||||
shader.TrySetUniform("time", (float)DateTime.Now.TimeOfDay.TotalMilliseconds);
|
||||
if (material != null) shader.TryApplyMaterial(material);
|
||||
|
||||
BindBuffers();
|
||||
gl.DrawElements(wireframeMode ? GL_LINES : GL_TRIANGLES, indexes.count, GL_UNSIGNED_SHORT, IntPtr.Zero);
|
||||
|
|
Загрузка…
Ссылка в новой задаче