- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
警告:总的 OpenGL/TK 新手,请善待。我可能咬得太多了。
规范:
我正在尝试从 learnopengl.com(我设法开始工作)复制 Cubemap 教程。我对 C# 更熟悉,所以最好获得一个使用 OpenTK 的解决方案。我得到的只是一个空白屏幕。也许是图像的背面(太乐观了?)。任何帮助,将不胜感激。
如果我遗漏了什么,请告诉我。
这是代码:(我觉得我很接近。)
MainWindow.xaml.cs
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Forms;
using Path = System.IO.Path;
namespace OpenTKTesting
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private int _vertexBufferObject;
private int _vertexArrayObject;
private Shader shader;
// For documentation on this, check Texture.cs
private TextureCubemap cubemap;
private Camera camera;
GLControl glControl; // the winforms opentk control
public MainWindow()
{
InitializeComponent();
glControl = new GLControl(new GraphicsMode(32, 24, 0, 8)) { VSync = true };
windowsFormsHost.Child = glControl;
System.Windows.Forms.Integration.WindowsFormsHost.EnableWindowsFormsInterop();
Toolkit.Init();
}
private List<string> ImageFaces
{
get;
set;
}
public void GetImageFaces()
{
ImageFaces = new List<string>();
string dir = @"C:\\Development\\ScratchDev\\OpenTKTesting\\OpenTKTesting\\Resources";
ImageFaces.Add(Path.Combine(dir, "f.jpg"));
ImageFaces.Add(Path.Combine(dir, "b.jpg"));
ImageFaces.Add(Path.Combine(dir, "u.jpg"));
ImageFaces.Add(Path.Combine(dir, "d.jpg"));
ImageFaces.Add(Path.Combine(dir, "r.jpg"));
ImageFaces.Add(Path.Combine(dir, "l.jpg"));
}
private void SetupGLControl()
{
if (glControl == null)
{
return;
}
GetImageFaces();
foreach (var item in ImageFaces)
{
Debug.WriteLine(item);
}
glControl.MakeCurrent();
glControl.VSync = true;
glControl.Resize += GlControl_Resize;
glControl.Paint += GlControl_Paint;
shader = new Shader("Shaders/shader.vert", "Shaders/shader.frag");
shader.SetInt("cubeMapArray", 0);
// We initialize the camera so that it is 3 units back from where the rectangle is
// and give it the proper aspect ratio
camera = new Camera(Vector3.UnitZ, glControl.AspectRatio);
}
private void GlControl_Paint(object sender, PaintEventArgs e)
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
_vertexBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferObject);
GL.BufferData(BufferTarget.ArrayBuffer, _vertices.Length * sizeof(float), _vertices, BufferUsageHint.StaticDraw);
cubemap = new TextureCubemap(ImageFaces);
cubemap.UseCubemap();
_vertexArrayObject = GL.GenVertexArray();
GL.BindVertexArray(_vertexArrayObject);
GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferObject);
//GL.BindBuffer(BufferTarget.ElementArrayBuffer, _elementBufferObject);
var vertexLocation = shader.GetAttribLocation("aPos");
GL.EnableVertexAttribArray(vertexLocation);
GL.VertexAttribPointer(vertexLocation, 3, VertexAttribPointerType.Float, false, 3 * sizeof(float), 0);
//// Next, we also setup texture coordinates. It works in much the same way.
//// We add an offset of 3, since the first vertex coordinate comes after the first vertex
//// and change the amount of data to 2 because there's only 2 floats for vertex coordinates
//var texCoordLocation = shader.GetAttribLocation("TexCoords");
//GL.EnableVertexAttribArray(texCoordLocation);
//GL.VertexAttribPointer(texCoordLocation, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), 3 * sizeof(float));
GL.Clear(ClearBufferMask.ColorBufferBit);
cubemap.UseCubemap();
shader.Use();
shader.SetMatrix4("view", camera.GetViewMatrix());
shader.SetMatrix4("projection", camera.GetProjectionMatrix());
GL.DrawArrays(PrimitiveType.Triangles, 0, 36);
glControl.SwapBuffers();
}
private readonly float[] _vertices =
{
// positions
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f
};
private void GlControl_Resize(object sender, EventArgs e)
{
InitializeView();
Debug.WriteLine("Resizing...");
}
private void WindowsFormsHost_Loaded(object sender, RoutedEventArgs e)
{
Debug.WriteLine("WFH Loaded...");
SetupGLControl();
}
public void InitializeView()
{
double newWidth = glControl.ClientSize.Width;
double newHeight = glControl.ClientSize.Height;
GL.Viewport(0, 0, (int)newWidth, (int)newHeight);
// We enable depth testing here. If you try to draw something more complex than one plane without this,
// you'll notice that polygons further in the background will occasionally be drawn over the top of the ones in the foreground.
// Obviously, we don't want this, so we enable depth testing. We also clear the depth buffer in GL.Clear over in OnRenderFrame.
GL.Enable(EnableCap.DepthTest);
glControl.SwapBuffers();
}
}
}
TextureCubemap.cs
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat;
namespace OpenTKTesting
{
class TextureCubemap
{
public readonly int Handle;
// Create texture from path.
public TextureCubemap(List<string> imagePaths)
{
// Generate handle
Handle = GL.GenTexture();
// Bind the handle
UseCubemap();
for (int i = 0; i < imagePaths.Count; i++)
{
// Load the image
using (var image = new Bitmap(imagePaths[i]))
{
Debug.WriteLine(imagePaths[i]);
var data = image.LockBits(
new Rectangle(0, 0, image.Width, image.Height),
ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppRgb);
GL.TexImage2D(TextureTarget.TextureCubeMap,
0,
PixelInternalFormat.Rgb,
image.Width,
image.Height,
0,
PixelFormat.Rgb,
PixelType.UnsignedByte,
data.Scan0);
}
}
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapS, (int)TextureParameterName.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapT, (int)TextureParameterName.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapR, (int)TextureParameterName.ClampToEdge);
}
public void UseCubemap(TextureUnit unit = TextureUnit.Texture0)
{
GL.ActiveTexture(unit);
GL.BindTexture(TextureTarget.TextureCubeMap, Handle);
}
}
}
Shader.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
namespace OpenTKTesting
{
// A simple class meant to help create shaders.
public class Shader
{
public readonly int Handle;
private readonly Dictionary<string, int> _uniformLocations;
// This is how you create a simple shader.
// Shaders are written in GLSL, which is a language very similar to C in its semantics.
// The GLSL source is compiled *at runtime*, so it can optimize itself for the graphics card it's currently being used on.
// A commented example of GLSL can be found in shader.vert
public Shader(string vertPath, string fragPath)
{
// There are several different types of shaders, but the only two you need for basic rendering are the vertex and fragment shaders.
// The vertex shader is responsible for moving around vertices, and uploading that data to the fragment shader.
// The vertex shader won't be too important here, but they'll be more important later.
// The fragment shader is responsible for then converting the vertices to "fragments", which represent all the data OpenGL needs to draw a pixel.
// The fragment shader is what we'll be using the most here.
// Load vertex shader and compile
// LoadSource is a simple function that just loads all text from the file whose path is given.
var shaderSource = LoadSource(vertPath);
// GL.CreateShader will create an empty shader (obviously). The ShaderType enum denotes which type of shader will be created.
var vertexShader = GL.CreateShader(ShaderType.VertexShader);
// Now, bind the GLSL source code
GL.ShaderSource(vertexShader, shaderSource);
// And then compile
CompileShader(vertexShader);
// We do the same for the fragment shader
shaderSource = LoadSource(fragPath);
var fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragmentShader, shaderSource);
CompileShader(fragmentShader);
// These two shaders must then be merged into a shader program, which can then be used by OpenGL.
// To do this, create a program...
Handle = GL.CreateProgram();
// Attach both shaders...
GL.AttachShader(Handle, vertexShader);
GL.AttachShader(Handle, fragmentShader);
// And then link them together.
LinkProgram(Handle);
// When the shader program is linked, it no longer needs the individual shaders attacked to it; the compiled code is copied into the shader program.
// Detach them, and then delete them.
GL.DetachShader(Handle, vertexShader);
GL.DetachShader(Handle, fragmentShader);
GL.DeleteShader(fragmentShader);
GL.DeleteShader(vertexShader);
// The shader is now ready to go, but first, we're going to cache all the shader uniform locations.
// Querying this from the shader is very slow, so we do it once on initialization and reuse those values
// later.
// First, we have to get the number of active uniforms in the shader.
GL.GetProgram(Handle, GetProgramParameterName.ActiveUniforms, out var numberOfUniforms);
// Next, allocate the dictionary to hold the locations.
_uniformLocations = new Dictionary<string, int>();
// Loop over all the uniforms,
for (var i = 0; i < numberOfUniforms; i++)
{
// get the name of this uniform,
var key = GL.GetActiveUniform(Handle, i, out _, out _);
// get the location,
var location = GL.GetUniformLocation(Handle, key);
// and then add it to the dictionary.
_uniformLocations.Add(key, location);
}
}
private static void CompileShader(int shader)
{
// Try to compile the shader
GL.CompileShader(shader);
// Check for compilation errors
GL.GetShader(shader, ShaderParameter.CompileStatus, out var code);
if (code != (int)All.True)
{
// We can use `GL.GetShaderInfoLog(shader)` to get information about the error.
throw new Exception($"Error occurred whilst compiling Shader({shader})");
}
}
private static void LinkProgram(int program)
{
// We link the program
GL.LinkProgram(program);
// Check for linking errors
GL.GetProgram(program, GetProgramParameterName.LinkStatus, out var code);
if (code != (int)All.True)
{
// We can use `GL.GetProgramInfoLog(program)` to get information about the error.
throw new Exception($"Error occurred whilst linking Program({program})");
}
}
// A wrapper function that enables the shader program.
public void Use()
{
GL.UseProgram(Handle);
}
// The shader sources provided with this project use hardcoded layout(location)-s. If you want to do it dynamically,
// you can omit the layout(location=X) lines in the vertex shader, and use this in VertexAttribPointer instead of the hardcoded values.
public int GetAttribLocation(string attribName)
{
return GL.GetAttribLocation(Handle, attribName);
}
// Just loads the entire file into a string.
private static string LoadSource(string path)
{
using (var sr = new StreamReader(path, Encoding.UTF8))
{
return sr.ReadToEnd();
}
}
// Uniform setters
// Uniforms are variables that can be set by user code, instead of reading them from the VBO.
// You use VBOs for vertex-related data, and uniforms for almost everything else.
// Setting a uniform is almost always the exact same, so I'll explain it here once, instead of in every method:
// 1. Bind the program you want to set the uniform on
// 2. Get a handle to the location of the uniform with GL.GetUniformLocation.
// 3. Use the appropriate GL.Uniform* function to set the uniform.
/// <summary>
/// Set a uniform int on this shader.
/// </summary>
/// <param name="name">The name of the uniform</param>
/// <param name="data">The data to set</param>
public void SetInt(string name, int data)
{
GL.UseProgram(Handle);
GL.Uniform1(_uniformLocations[name], data);
}
/// <summary>
/// Set a uniform float on this shader.
/// </summary>
/// <param name="name">The name of the uniform</param>
/// <param name="data">The data to set</param>
public void SetFloat(string name, float data)
{
GL.UseProgram(Handle);
GL.Uniform1(_uniformLocations[name], data);
}
/// <summary>
/// Set a uniform Matrix4 on this shader
/// </summary>
/// <param name="name">The name of the uniform</param>
/// <param name="data">The data to set</param>
/// <remarks>
/// <para>
/// The matrix is transposed before being sent to the shader.
/// </para>
/// </remarks>
public void SetMatrix4(string name, Matrix4 data)
{
GL.UseProgram(Handle);
GL.UniformMatrix4(_uniformLocations[name], true, ref data);
}
/// <summary>
/// Set a uniform Vector3 on this shader.
/// </summary>
/// <param name="name">The name of the uniform</param>
/// <param name="data">The data to set</param>
public void SetVector3(string name, Vector3 data)
{
GL.UseProgram(Handle);
GL.Uniform3(_uniformLocations[name], data);
}
}
}
Camera.cs
using OpenTK;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenTKTesting
{
// This is the camera class as it could be set up after the tutorials on the website
// It is important to note there are a few ways you could have set up this camera, for example
// you could have also managed the player input inside the camera class, and a lot of the properties could have
// been made into functions.
// TL;DR: This is just one of many ways in which we could have set up the camera
// Check out the web version if you don't know why we are doing a specific thing or want to know more about the code
public class Camera
{
// Those vectors are directions pointing outwards from the camera to define how it rotated
private Vector3 _front = -Vector3.UnitZ;
private Vector3 _up = Vector3.UnitY;
private Vector3 _right = Vector3.UnitX;
// Rotation around the X axis (radians)
private float _pitch;
// Rotation around the Y axis (radians)
private float _yaw = -MathHelper.PiOver2; // Without this you would be started rotated 90 degrees right
// The field of view of the camera (radians)
private float _fov = MathHelper.PiOver2;
public Camera(Vector3 position, float aspectRatio)
{
Position = position;
AspectRatio = aspectRatio;
}
// The position of the camera
public Vector3 Position { get; set; }
// This is simply the aspect ratio of the viewport, used for the projection matrix
public float AspectRatio { private get; set; }
public Vector3 Front => _front;
public Vector3 Up => _up;
public Vector3 Right => _right;
// We convert from degrees to radians as soon as the property is set to improve performance
public float Pitch
{
get => MathHelper.RadiansToDegrees(_pitch);
set
{
// We clamp the pitch value between -89 and 89 to prevent the camera from going upside down, and a bunch
// of weird "bugs" when you are using euler angles for rotation.
// If you want to read more about this you can try researching a topic called gimbal lock
var angle = MathHelper.Clamp(value, -89f, 89f);
_pitch = MathHelper.DegreesToRadians(angle);
UpdateVectors();
}
}
// We convert from degrees to radians as soon as the property is set to improve performance
public float Yaw
{
get => MathHelper.RadiansToDegrees(_yaw);
set
{
_yaw = MathHelper.DegreesToRadians(value);
UpdateVectors();
}
}
// The field of view (FOV) is the vertical angle of the camera view, this has been discussed more in depth in a
// previous tutorial, but in this tutorial you have also learned how we can use this to simulate a zoom feature.
// We convert from degrees to radians as soon as the property is set to improve performance
public float Fov
{
get => MathHelper.RadiansToDegrees(_fov);
set
{
var angle = MathHelper.Clamp(value, 1f, 45f);
_fov = MathHelper.DegreesToRadians(angle);
}
}
// Get the view matrix using the amazing LookAt function described more in depth on the web tutorials
public Matrix4 GetViewMatrix()
{
return Matrix4.LookAt(Position, Position + _front, _up);
}
// Get the projection matrix using the same method we have used up until this point
public Matrix4 GetProjectionMatrix()
{
return Matrix4.CreatePerspectiveFieldOfView(_fov, AspectRatio, 0.01f, 100f);
}
// This function is going to update the direction vertices using some of the math learned in the web tutorials
private void UpdateVectors()
{
// First the front matrix is calculated using some basic trigonometry
_front.X = (float)Math.Cos(_pitch) * (float)Math.Cos(_yaw);
_front.Y = (float)Math.Sin(_pitch);
_front.Z = (float)Math.Cos(_pitch) * (float)Math.Sin(_yaw);
// We need to make sure the vectors are all normalized, as otherwise we would get some funky results
_front = Vector3.Normalize(_front);
// Calculate both the right and the up vector using cross product
// Note that we are calculating the right from the global up, this behaviour might
// not be what you need for all cameras so keep this in mind if you do not want a FPS camera
_right = Vector3.Normalize(Vector3.Cross(_front, Vector3.UnitY));
_up = Vector3.Normalize(Vector3.Cross(_right, _front));
}
}
}
shader.vert
#version 330 core
layout (location = 0) in vec3 aPos;
out vec3 TexCoords;
uniform mat4 projection;
uniform mat4 view;
void main()
{
TexCoords = aPos;
gl_Position = projection * view * vec4(aPos, 1.0);
}
shader.frag
#version 330 core
out vec4 FragColor;
in vec3 texDir;
in vec3 TexCoords;
uniform samplerCube cubeMapArray;
void main()
{
FragColor = texture(cubeMapArray, TexCoords);
}
编辑:
@Rabbid76 - 我已经按照你的建议进行了更新。不幸的是,我仍然遇到黑屏。我或多或少地听从了你的建议。您能否提出其他任何建议,可能与着色器或相机有关?
private void SetupGLControl()
{
if (glControl == null)
{
return;
}
GetImageFaces();
foreach (var item in ImageFaces)
{
Debug.WriteLine(item);
}
glControl.MakeCurrent();
glControl.VSync = true;
glControl.Resize += GlControl_Resize;
glControl.Paint += GlControl_Paint;
shader = new Shader("Shaders/shader.vert", "Shaders/shader.frag");
shader.SetInt("cubeMapArray", 0);
// We initialize the camera so that it is 3 units back from where the rectangle is
// and give it the proper aspect ratio
camera = new Camera(Vector3.UnitZ, glControl.AspectRatio);
cubemap = new TextureCubemap(ImageFaces);
_vertexBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferObject);
GL.BufferData(BufferTarget.ArrayBuffer, _vertices.Length * sizeof(float), _vertices, BufferUsageHint.StaticDraw);
_vertexArrayObject = GL.GenVertexArray();
GL.BindVertexArray(_vertexArrayObject);
GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferObject);
var vertexLocation = shader.GetAttribLocation("aPos");
GL.EnableVertexAttribArray(vertexLocation);
GL.VertexAttribPointer(vertexLocation, 3, VertexAttribPointerType.Float, false, 3 * sizeof(float), 0);
}
private void GlControl_Paint(object sender, PaintEventArgs e)
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
cubemap.UseCubemap();
shader.Use();
shader.SetMatrix4("view", camera.GetViewMatrix());
shader.SetMatrix4("projection", camera.GetProjectionMatrix());
GL.BindVertexArray(_vertexArrayObject);
GL.DrawArrays(PrimitiveType.Triangles, 0, 36);
glControl.SwapBuffers();
}
最佳答案
当您指定立方体贴图纹理的二维纹理图像时,您指定立方体贴图的单边,目标必须是其中之一TextureCubeMapNegativeX
、TextureCubeMapNegativeY
、TextureCubeMapNegativeZ
、TextureCubeMapPositiveX
、TextureCubeMapPositiveY
或 TextureCubeMapPositiveZ
:
TextureTarget[] targets =
{
TextureTarget.TextureCubeMapNegativeX, TextureTarget.TextureCubeMapNegativeY,
TextureTarget.TextureCubeMapNegativeZ, TextureTarget.TextureCubeMapPositiveX,
TextureTarget.TextureCubeMapPositiveY, TextureTarget.TextureCubeMapPositiveZ
}
for (int i = 0; i < imagePaths.Count; i++)
{
// Load the image
using (var image = new Bitmap(imagePaths[i]))
{
Debug.WriteLine(imagePaths[i]);
var data = image.LockBits(
new Rectangle(0, 0, image.Width, image.Height),
ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppRgb);
GL.TexImage2D(targets[i], // <------
0,
PixelInternalFormat.Rgb,
image.Width,
image.Height,
0,
PixelFormat.Rgb,
PixelType.UnsignedByte,
data.Scan0);
}
}
缓冲区对象和顶点数组对象在每一帧中创建。在初始化时创建一次对象并在每一帧中使用它。请注意,您不删除对象,GPU 没有“垃圾收集”。执行 Vertex Specification在 MainWindow.SetupGLControl
中。绑定(bind) Vertex Array Object 就足够了在抽签之前:
public partial class MainWindow : Window
{
private TextureCubemap cubemap;
// [...]
private void SetupGLControl()
{
// [...]
cubemap = new TextureCubemap(ImageFaces);
_vertexBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferObject);
GL.BufferData(BufferTarget.ArrayBuffer, _vertices.Length * sizeof(float), _vertices, BufferUsageHint.StaticDraw);
_vertexArrayObject = GL.GenVertexArray();
GL.BindVertexArray(_vertexArrayObject);
GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferObject);
var vertexLocation = shader.GetAttribLocation("aPos");
GL.EnableVertexAttribArray(vertexLocation);
GL.VertexAttribPointer(vertexLocation, 3, VertexAttribPointerType.Float, false, 3 * sizeof(float), 0);
//GL.BindBuffer(BufferTarget.ElementArrayBuffer, _elementBufferObject);
// [...]
}
private void GlControl_Paint(object sender, PaintEventArgs e)
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
cubemap.UseCubemap();
shader.Use();
shader.SetMatrix4("view", camera.GetViewMatrix());
shader.SetMatrix4("projection", camera.GetProjectionMatrix());
GL.BindVertexArray(_vertexArrayObject); // <------ bind vertex array object
GL.DrawArrays(PrimitiveType.Triangles, 0, 36);
glControl.SwapBuffers();
}
// [...]
}
``´
关于c# - OpenTK 中的立方体贴图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56680252/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!