using System.Drawing.Imaging;
|
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Mathematics;
|
|
namespace Yw.WinFrmUI.Test.Core
|
{
|
public partial class TextForm1 : Form
|
{
|
public TextForm1()
|
{
|
this.InitializeComponent();
|
this.glControl1.Paint += GLControl_Paint;
|
this.glControl1.Resize += GLControl_Resize;
|
|
|
this.glControl1.Load += GlControl1_Load;
|
this.glControl1.MouseWheel += GlControl1_MouseWheel;
|
this.glControl1.MouseMove += GlControl1_MouseMove;
|
this.glControl1.MouseDown += GlControl1_MouseDown;
|
this.glControl1.MouseUp += GlControl1_MouseUp;
|
}
|
|
private void GlControl1_MouseUp(object sender, MouseEventArgs e)
|
{
|
HandleMouseUp(e);
|
}
|
|
private void GlControl1_MouseDown(object sender, MouseEventArgs e)
|
{
|
HandleMouseDown(e);
|
}
|
|
private void GlControl1_MouseMove(object sender, MouseEventArgs e)
|
{
|
HandleMouseMove(e);
|
}
|
|
private void GlControl1_MouseWheel(object sender, MouseEventArgs e)
|
{
|
HandleMouseWheel(e);
|
}
|
|
private Vector3 _mc = new Vector3(0f);
|
private float _radius = 2f;
|
private float _rotationX = 0f;
|
private float _rotationY = 0f;
|
private Quaternion _rotation = Quaternion.Identity;
|
private float _translationX = 0f;
|
private float _translationY = 0f;
|
private float _zoom = 1f;
|
private Matrix4 _modelMatrix = Matrix4.Identity;
|
private Matrix4 _viewMatrix = Matrix4.Identity;
|
private Matrix4 _projMatrix = Matrix4.Identity;
|
private Vector3 _forward = Vector3.Zero;
|
private float _pw = 1f;
|
private float _ph = 1f;
|
private Dictionary<string, int> textureCache = new Dictionary<string, int>();
|
|
// 各面配置
|
private readonly Dictionary<string, FaceConfig> faceConfigs = new Dictionary<string, FaceConfig>
|
{
|
{ "+X", new FaceConfig("右", Color.Red, new Vector3(0.5f, 0, 0)) },
|
{ "-X", new FaceConfig("左", Color.Blue, new Vector3(-0.5f, 0, 0)) },
|
{ "+Y", new FaceConfig("上", Color.Green, new Vector3(0, 0.5f, 0)) },
|
{ "-Y", new FaceConfig("下", Color.Yellow, new Vector3(0, -0.5f, 0)) },
|
{ "+Z", new FaceConfig("前", Color.Purple, new Vector3(0, 0, 0.5f)) },
|
{ "-Z", new FaceConfig("后", Color.Cyan, new Vector3(0, 0, -0.5f)) }
|
};
|
|
|
/// <summary>
|
/// 缩放
|
/// </summary>
|
public float Zoom
|
{
|
get => _zoom;
|
set => _zoom = MathHelper.Clamp(value, 0.01f, 100.0f); // 限制缩放范围
|
}
|
|
//更新ViewPort
|
private void UpdateViewPort()
|
{
|
GL.Viewport(0, 0, this.glControl1.Width, this.glControl1.Height);
|
}
|
|
//更新ModelMatrix
|
private void UpdateModelMatrix()
|
{
|
_modelMatrix = Matrix4.CreateFromAxisAngle(Vector3.UnitX, _rotationX) *
|
Matrix4.CreateFromAxisAngle(Vector3.UnitY, _rotationY) *
|
Matrix4.CreateTranslation(_translationX * this.Zoom, _translationY * this.Zoom, 0f);
|
}
|
|
//更新ViewMatrix
|
private void UpdateViewMatrix()
|
{
|
var eye = new Vector3(_mc.X, _mc.Y, _mc.Z + _radius * 2);
|
var target = _mc;
|
var up = Vector3.UnitY;
|
//_rotation = Quaternion.Identity;
|
//var rotationX = Quaternion.FromAxisAngle(Vector3.UnitX, _rotationX);
|
//var rotationY = Quaternion.FromAxisAngle(Vector3.UnitY, _rotationY);
|
//_rotation = rotationY * rotationX * _rotation;
|
//_rotation.Normalize();
|
//var matrix = Matrix4.CreateFromQuaternion(_rotation);
|
//matrix.Invert();
|
//eye = Vector3.TransformPosition(eye, matrix);
|
//up = Vector3.TransformPosition(up, matrix);
|
_viewMatrix = Matrix4.LookAt(eye, target, up);
|
_forward = target - eye;
|
_forward.Normalize();
|
}
|
|
//更新投影矩阵
|
private void UpdateProjectionMatrix()
|
{
|
var aspect = this.glControl1.AspectRatio;
|
var size = _radius * 2;
|
_pw = size;
|
_ph = size;
|
|
if (aspect > 1)
|
{
|
_pw *= aspect;
|
}
|
else
|
{
|
_ph /= aspect;
|
}
|
_projMatrix = Matrix4.CreateOrthographic(_pw * this.Zoom, _ph * this.Zoom, _radius, _radius * 3);
|
}
|
|
//重绘
|
private void OnResize()
|
{
|
this.glControl1.MakeCurrent();
|
UpdateViewPort();
|
UpdateModelMatrix();
|
UpdateViewMatrix();
|
UpdateProjectionMatrix();
|
this.glControl1.Invalidate();
|
}
|
|
private void OnRender()
|
{
|
this.glControl1.MakeCurrent();
|
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
|
|
// 启用必要功能
|
GL.Enable(EnableCap.DepthTest);
|
GL.Enable(EnableCap.Blend);
|
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
|
|
//投影矩阵
|
GL.MatrixMode(MatrixMode.Projection);
|
GL.LoadMatrix(ref _projMatrix);
|
|
//视图矩阵
|
GL.MatrixMode(MatrixMode.Modelview);
|
var viewMatrix = _viewMatrix * _modelMatrix;
|
GL.LoadMatrix(ref viewMatrix);
|
|
DrawColoredCube();
|
|
foreach (var face in faceConfigs)
|
{
|
DrawFaceLabel(_modelMatrix, face.Key);
|
}
|
|
this.glControl1.SwapBuffers();
|
}
|
|
private void GlControl1_Load(object sender, EventArgs e)
|
{
|
GL.ClearColor(Color.Gray); // 背景颜色
|
GL.Enable(EnableCap.DepthTest);//深度测试
|
GL.DepthMask(true); // 允许写入深度缓冲区
|
GL.ShadeModel(ShadingModel.Smooth);
|
|
GL.Enable(EnableCap.PointSmooth);//启用点平滑
|
GL.Enable(EnableCap.LineSmooth);//启用线平滑
|
PreloadTextures();
|
OnResize();
|
}
|
|
private void GLControl_Resize(object sender, EventArgs e)
|
{
|
OnResize();
|
}
|
|
private void GLControl_Paint(object sender, PaintEventArgs e)
|
{
|
OnRender();
|
}
|
|
private void PreloadTextures()
|
{
|
foreach (var face in faceConfigs)
|
{
|
using (var bmp = CreateTextBitmap(face.Value.Text, "微软雅黑", 20, Color.White, face.Value.Color))
|
{
|
int textureId = UploadTexture(bmp);
|
textureCache.Add(face.Key, textureId);
|
}
|
}
|
}
|
|
private void DrawFaceLabel(Matrix4 modelMatrix, string faceKey)
|
{
|
if (!textureCache.ContainsKey(faceKey)) return;
|
|
var config = faceConfigs[faceKey];
|
|
//GL.PushMatrix();
|
//GL.MatrixMode(MatrixMode.Projection);
|
//GL.PushMatrix();
|
|
// 设置正交投影
|
//GL.LoadIdentity();
|
//GL.Ortho(-1, 1, -1, 1, -1, 1);
|
|
// 计算标签位置
|
//Matrix4 labelMatrix = modelMatrix *
|
//Matrix4.CreateTranslation(config.Position) *
|
//_viewMatrix;
|
|
// 移除旋转分量
|
//labelMatrix.ClearRotation();
|
|
// GL.MatrixMode(MatrixMode.Modelview);
|
// GL.LoadMatrix(ref labelMatrix);
|
|
// 绑定纹理
|
GL.Enable(EnableCap.Texture2D);
|
GL.BindTexture(TextureTarget.Texture2D, textureCache[faceKey]);
|
|
// 绘制标签
|
float scale = 0.15f;
|
GL.Begin(PrimitiveType.Quads);
|
GL.TexCoord2(0, 0); GL.Vertex2(-scale, -scale);
|
GL.TexCoord2(1, 0); GL.Vertex2(scale, -scale);
|
GL.TexCoord2(1, 1); GL.Vertex2(scale, scale);
|
GL.TexCoord2(0, 1); GL.Vertex2(-scale, scale);
|
GL.End();
|
|
//GL.PopMatrix();
|
// GL.MatrixMode(MatrixMode.Projection);
|
// GL.PopMatrix();
|
}
|
|
|
|
private Bitmap CreateTextBitmap(string text, string fontName, int fontSize, Color textColor, Color bgColor)
|
{
|
using (var font = new Font(fontName, fontSize, FontStyle.Bold, GraphicsUnit.Pixel))
|
using (var textBrush = new SolidBrush(textColor))
|
using (var bgBrush = new SolidBrush(bgColor))
|
{
|
SizeF textSize;
|
using (var tempG = Graphics.FromHwnd(IntPtr.Zero))
|
textSize = tempG.MeasureString(text, font);
|
|
int width = (int)Math.Ceiling(textSize.Width) + 4;
|
int height = (int)Math.Ceiling(textSize.Height) + 4;
|
|
var bmp = new Bitmap(width, height);
|
using (var g = Graphics.FromImage(bmp))
|
{
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
|
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
|
|
// 绘制背景
|
g.FillRectangle(bgBrush, 0, 0, width, height);
|
|
// 居中绘制文字
|
float x = (width - textSize.Width) / 2;
|
float y = (height - textSize.Height) / 2;
|
g.DrawString(text, font, textBrush, x, y);
|
}
|
return bmp;
|
}
|
}
|
|
//private Matrix4 CalculateBillboardMatrix(Vector3 position, Matrix4 modelMatrix)
|
//{
|
// // 获取世界空间位置
|
// Vector3 worldPos = Vector3.Transform(position, modelMatrix);
|
|
// // 计算面向相机的旋转
|
// Matrix4 viewRotation = viewMatrix.ClearTranslation();
|
// Matrix4 inverseViewRotation = Matrix4.Transpose(viewRotation);
|
|
// return inverseViewRotation * Matrix4.CreateTranslation(worldPos);
|
//}
|
|
private int UploadTexture(Bitmap bmp)
|
{
|
this.glControl1.MakeCurrent();
|
int textureId = GL.GenTexture();
|
GL.BindTexture(TextureTarget.Texture2D, textureId);
|
|
BitmapData data = bmp.LockBits(
|
new Rectangle(0, 0, bmp.Width, bmp.Height),
|
ImageLockMode.ReadOnly,
|
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
|
GL.TexImage2D(TextureTarget.Texture2D, 0,
|
PixelInternalFormat.Rgba,
|
data.Width, data.Height, 0,
|
OpenTK.Graphics.OpenGL.PixelFormat.Bgra,
|
PixelType.UnsignedByte,
|
data.Scan0);
|
|
bmp.UnlockBits(data);
|
|
GL.TexParameter(TextureTarget.Texture2D,
|
TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
GL.TexParameter(TextureTarget.Texture2D,
|
TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
|
return textureId;
|
}
|
|
public class FaceConfig
|
{
|
public string Text { get; }
|
public Color Color { get; }
|
public Vector3 Position { get; }
|
|
public FaceConfig(string text, Color color, Vector3 position)
|
{
|
Text = text;
|
Color = color;
|
Position = position;
|
}
|
}
|
|
|
//颜色字典
|
private readonly static Dictionary<string, Color> _colorDict = new Dictionary<string, Color>()
|
{
|
{ "右",ColorTranslator.FromHtml("#FF0000")},
|
{ "左",ColorTranslator.FromHtml("#87CEEB")},
|
{ "后",ColorTranslator.FromHtml("#008000")},
|
{ "前",ColorTranslator.FromHtml("#00008B")},
|
{ "上",ColorTranslator.FromHtml("#800080")},
|
{ "下",ColorTranslator.FromHtml("#242424")}
|
};
|
|
//绘制彩色立方体
|
private void DrawColoredCube()
|
{
|
|
GL.Begin(PrimitiveType.Quads);
|
|
// 前面(Z+)
|
GL.Color3(_colorDict["前"]);
|
GL.Vertex3(-0.5f, -0.5f, 0.5f);
|
GL.Vertex3(0.5f, -0.5f, 0.5f);
|
GL.Vertex3(0.5f, 0.5f, 0.5f);
|
GL.Vertex3(-0.5f, 0.5f, 0.5f);
|
|
// 背面(Z-)
|
GL.Color3(_colorDict["后"]);
|
GL.Vertex3(-0.5f, -0.5f, -0.5f);
|
GL.Vertex3(-0.5f, 0.5f, -0.5f);
|
GL.Vertex3(0.5f, 0.5f, -0.5f);
|
GL.Vertex3(0.5f, -0.5f, -0.5f);
|
|
// 顶面(Y+)
|
GL.Color3(_colorDict["上"]);
|
GL.Vertex3(-0.5f, 0.5f, -0.5f);
|
GL.Vertex3(0.5f, 0.5f, -0.5f);
|
GL.Vertex3(0.5f, 0.5f, 0.5f);
|
GL.Vertex3(-0.5f, 0.5f, 0.5f);
|
|
// 底面(Y-)
|
GL.Color3(_colorDict["下"]);
|
GL.Vertex3(-0.5f, -0.5f, -0.5f);
|
GL.Vertex3(0.5f, -0.5f, -0.5f);
|
GL.Vertex3(0.5f, -0.5f, 0.5f);
|
GL.Vertex3(-0.5f, -0.5f, 0.5f);
|
|
// 右面(X+)
|
GL.Color3(_colorDict["右"]);
|
GL.Vertex3(0.5f, -0.5f, -0.5f);
|
GL.Vertex3(0.5f, 0.5f, -0.5f);
|
GL.Vertex3(0.5f, 0.5f, 0.5f);
|
GL.Vertex3(0.5f, -0.5f, 0.5f);
|
|
// 左面(X-)
|
GL.Color3(_colorDict["左"]);
|
GL.Vertex3(-0.5f, -0.5f, -0.5f);
|
GL.Vertex3(-0.5f, 0.5f, -0.5f);
|
GL.Vertex3(-0.5f, 0.5f, 0.5f);
|
GL.Vertex3(-0.5f, -0.5f, 0.5f);
|
|
GL.End();
|
}
|
|
private bool _isDragging = false;//是否增在拖动
|
private bool _isRotating = false;//是否正在旋转
|
private Point _lastMousePos;//最近一次鼠标位置
|
|
/// <summary>
|
/// 处理鼠标滚轮
|
/// </summary>
|
public void HandleMouseWheel(MouseEventArgs e)
|
{
|
this.Zoom *= e.Delta > 0 ? 0.9f : 1.1f;
|
UpdateModelMatrix();
|
UpdateViewMatrix();
|
UpdateProjectionMatrix();
|
this.glControl1.Invalidate();
|
}
|
|
/// <summary>
|
/// 处理鼠标按下
|
/// </summary>
|
public void HandleMouseDown(MouseEventArgs e)
|
{
|
_lastMousePos = e.Location;
|
if (e.Button == MouseButtons.Right)
|
{
|
_isDragging = true;
|
this.glControl1.Cursor = Cursors.SizeAll; // 修改光标样式
|
}
|
else if (e.Button == MouseButtons.Left)
|
{
|
_isRotating = true;
|
this.glControl1.Cursor = Cursors.SizeAll; // 修改光标样式
|
}
|
}
|
|
/// <summary>
|
/// 处理鼠标弹起
|
/// </summary>
|
public void HandleMouseUp(MouseEventArgs e)
|
{
|
_lastMousePos = e.Location;
|
if (e.Button == MouseButtons.Right)
|
{
|
_isDragging = false;
|
this.glControl1.Cursor = Cursors.Default;
|
}
|
else if (e.Button == MouseButtons.Left)
|
{
|
_isRotating = false;
|
this.glControl1.Cursor = Cursors.Default;
|
}
|
|
this.glControl1.Invalidate();
|
}
|
|
/// <summary>
|
/// 处理鼠标移动
|
/// </summary>
|
public void HandleMouseMove(MouseEventArgs e)
|
{
|
float dx = e.X - _lastMousePos.X;
|
float dy = e.Y - _lastMousePos.Y;
|
|
if (_isRotating)
|
{
|
// 根据鼠标移动量计算旋转角度
|
var roation_dx = dy / _radius;
|
var rotaion_dy = dx / _radius;
|
_rotationX += roation_dx;
|
_rotationY += rotaion_dy;
|
|
UpdateModelMatrix();
|
UpdateViewMatrix();
|
UpdateProjectionMatrix();
|
}
|
else if (_isDragging)
|
{
|
float xratio = _pw / this.glControl1.Width;
|
float yratio = _ph / this.glControl1.Height;
|
_translationX += dx * xratio;
|
_translationY -= dy * yratio;
|
UpdateModelMatrix();
|
UpdateViewMatrix();
|
UpdateProjectionMatrix();
|
}
|
|
|
|
_lastMousePos = e.Location;
|
this.glControl1.Invalidate();
|
}
|
|
}
|
}
|