#c# #winforms #opengl #opentk
#c# #winforms #opengl #opentk
Вопрос:
Я пытаюсь реализовать освещение в моей визуализируемой сцене OpenTK. Странно то, что, поскольку я реализовал рассеянное освещение в своем шейдере и коде, все текстуры объектов видны только ВНУТРИ объектов. Или это только так выглядит.
Можете ли вы помочь мне с этим? Я надеюсь, что это всего лишь простая проблема для чайника.
Вы можете найти полный код здесь: https://github.com/BanditBloodwyn/TerritorySimulator .
Важные файлы:
- Рендеринг.Ядро.Рендеринг.Renderer.cs
- Rendering.Core.Classes.Формы.GLSphere.cs
- Rendering.Core.Classes.Shaders.GLSL.Fragment
Это шейдер:
#version 420 core
in vec3 normal;
in vec2 texCoord;
in vec3 FragPos;
out vec4 FragColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material material;
uniform Light light;
void main()
{
// Ambient
vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
// Diffuse
vec3 norm = normalize(normal);
vec3 lightDir = normalize(vec3(light.position - FragPos));
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
vec3 result = ambient diffuse;
//if(result.a < 0.1)
// discard;
FragColor = vec4(result, 1.0);
}
Это функция рендеринга:
public void Render()
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
if (Shapes == null || Shapes.Length == 0)
return;
IntPtr offset = (IntPtr)0;
foreach (GLShape shape in Shapes)
{
ApplyTextures(shape);
ApplyModelTransforms(shape, out Matrix4 model);
objectShader.SetMatrix4("model", model);
GL.DrawElements(PrimitiveType.Triangles, shape.Indices.Length, DrawElementsType.UnsignedInt, offset);
offset = shape.IndexBufferSize;
}
objectShader.SetVector3("material.ambient", new Vector3(1.0f, 0.5f, 0.31f));
objectShader.SetVector3("material.diffuse", new Vector3(1.0f, 0.5f, 0.31f));
objectShader.SetVector3("material.specular", new Vector3(0.5f, 0.5f, 0.5f));
objectShader.SetVector3("light.position", new Vector3(100f, 1.0f, 2.0f));
objectShader.SetVector3("light.ambient", new Vector3(1.0f));
objectShader.SetVector3("light.diffuse", new Vector3(0.5f));
objectShader.SetVector3("light.specular", new Vector3(1.0f));
objectShader.SetMatrix4("view", Camera.GetViewMatrix());
objectShader.SetMatrix4("projection", Camera.GetProjectionMatrix());
objectShader.Use();
}
To make it clearer: According to what I understand, I set the light source position to {100, 1, 2} in the world space. Since the world sphere’s radius is 20, the light should be located outside of it, so it should be illuminated from the outside.
All parameters for the material are from an OpenTK tutorial which shows me the basics of OpenGL and OpenTK, so I hope they are correct or at least not the reason for my problem.
The light parameters are similar to the same tutorial, except for the ambient strength, which I set to 1.0 to «disable» the dimming effect of ambient lighting.
«Shapes» is the Array which contains all objects in the world.
Here the shader is set:
private void SetupObjectShader()
{
string vertexPath = Path.Combine(Environment.CurrentDirectory, @"GLSL", "Vertex.vert");
string fragmentPath = Path.Combine(Environment.CurrentDirectory, @"GLSL", "Fragment.frag");
objectShader = new Shader(vertexPath, fragmentPath);
objectShader.Use();
int vertexLocation = objectShader.GetAttribLocation("aPosition");
GL.EnableVertexAttribArray(vertexLocation);
GL.VertexAttribPointer(
vertexLocation,
3,
VertexAttribPointerType.Float,
false,
8 * sizeof(float),
0);
int normCoordLocation = objectShader.GetAttribLocation("aNormal");
GL.EnableVertexAttribArray(normCoordLocation);
GL.VertexAttribPointer(
normCoordLocation,
3,
VertexAttribPointerType.Float,
false,
8 * sizeof(float),
3 * sizeof(float));
int texCoordLocation = objectShader.GetAttribLocation("aTexCoord");
GL.EnableVertexAttribArray(texCoordLocation);
GL.VertexAttribPointer(
texCoordLocation,
2,
VertexAttribPointerType.Float,
false,
8 * sizeof(float),
6 * sizeof(float));
objectShader.SetInt("texture0", 0);
objectShader.SetInt("texture1", 1);
}
Значения шага и смещения для функции vertexAttribPointer станут понятны в следующей функции, где вы можете увидеть, как построены вершины: 3 поплавка для позиции, 3 поплавка для нормали, 2 координаты текстуры.
Объекты создаются следующим образом (в моем случае все сферы). Пожалуйста, посмотрите, как создаются вершины и нормали:
private void RecreateVertices()
{
List<float> vertices = new List<float>();
float alpha = 2 * (float)Math.PI / rasterization;
for (int i = 0; i < rasterization 1; i )
{
for (int j = 0; j < rasterization 1; j )
{
float x = radius * (float)Math.Sin(i * alpha * 1.0) * (float)Math.Sin(j * alpha);
float y = radius * (float)Math.Sin(i * alpha * 1.0) * (float)Math.Cos(j * alpha);
float z = radius * (float)Math.Cos(i * alpha * 1.0);
float textureX = (float)j / rasterization;
float textureY = (float)i / rasterization * 2;
Vector3 normal = CreateNormal(x, y, z);
vertices.AddRange(new[] { x, y, z, normal[0], normal[1], normal[2], textureX, textureY });
}
}
Vertices = vertices.ToArray();
}
private Vector3 CreateNormal(float x, float y, float z)
{
Vector3 normVector3 = new Vector3(x, y, z);
normVector3.Normalize();
return normVector3;
}
Обновить:
Я провел несколько экспериментов с шейдером фрагментов.
Вместо текстур я попробовал белый свет и оранжевый цвет для объектов. Вместо видимых освещенных объектов я получил статическое оранжевое изображение. Возможно, это поможет с диагностикой.
#version 420 core
in vec3 normal;
in vec2 texCoord;
in vec3 FragPos;
out vec4 FragColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material material;
uniform Light light;
uniform vec3 viewPos;
void main()
{
// Ambient
// vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
vec3 ambient = light.ambient * vec3(1.0f, 1.0f, 1.0f);
// Diffuse
vec3 norm = normalize(normal);
vec3 lightDir = normalize(vec3(light.position - FragPos));
float diff = max(dot(norm, lightDir), 0.0);
//vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
vec3 diffuse = light.diffuse * diff * vec3(1.0f, 1.0f, 1.0f);
// Specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));
vec3 specular = light.specular * spec * vec3(1.0f, 1.0f, 1.0f);
vec3 result = (ambient diffuse specular) * vec3(1.0f, 0.5f, 0.31f);
//if(result.a < 0.1)
// discard;
FragColor = vec4(result, 1.0);
}
Комментарии:
1. Что произойдет, если вы сделаете
float diff = max(dot(-norm, lightDir), 0.0);
2. @Rabbid76 ничего не меняется.
3. Извините, но этого не может быть.
float diff = max(dot(-norm, lightDir), 0.0);
должно вызывать разницу по сравнению сfloat diff = max(dot(norm, lightDir), 0.0);
Ответ №1:
Программа для создания шейдеров должна быть установлена GL.UseProgram
до того, как будут установлены формы . GL.Uniform
* задает значение uniform в блоке uniform по умолчанию установленной в данный момент программы:
objectShader.Use();
objectShader.SetVector3("material.ambient", new Vector3(1.0f, 0.5f, 0.31f));
objectShader.SetVector3("material.diffuse", new Vector3(1.0f, 0.5f, 0.31f));
objectShader.SetVector3("material.specular", new Vector3(0.5f, 0.5f, 0.5f));
objectShader.SetVector3("light.position", new Vector3(100f, 1.0f, 2.0f));
objectShader.SetVector3("light.ambient", new Vector3(1.0f));
objectShader.SetVector3("light.diffuse", new Vector3(0.5f));
objectShader.SetVector3("light.specular", new Vector3(1.0f));
objectShader.SetMatrix4("view", Camera.GetViewMatrix());
objectShader.SetMatrix4("projection", Camera.GetProjectionMatrix());
Ответ №2:
Я обнаружил одну проблему. Неверно настроен вершинный шейдер. Я обновил его, как показано ниже. В результате я, наконец, могу видеть эффекты рассеянного и зеркального освещения, но все еще только ВНУТРИ моих сфер.
там вы можете видеть, как работает рассеянное и зеркальное освещение (я установил окружающий свет на 0.0, чтобы лучше видеть другие компоненты освещения). Положение освещения устанавливается равным x: 1000,0f, y: 1,0f, z: 0,0f, поскольку мировая сфера имеет радиус 20,0f. Я хотел, чтобы свет был СНАРУЖИ (конечно, я этого хочу) и подальше от него.
Что может решить эту «внешнюю проблему»? Неправильные нормали? Неправильное или отсутствующее отрицание где-либо?
Здесь «новый» вершинный шейдер:
#version 420 core
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoord;
out vec2 texCoord;
out vec3 FragPos;
out vec3 Normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main(void)
{
texCoord = aTexCoord;
FragPos = vec3(vec4(aPosition, 1.0) * model);
Normal = -aNormal * mat3(transpose(inverse(model)));
gl_Position = vec4(aPosition, 1.0) * model * view * projection;
}
И здесь текущее состояние фрагментного шейдера:
#version 420 core
in vec3 FragPos;
in vec3 Normal;
in vec2 texCoord;
out vec4 FragColor;
uniform sampler2D texture0;
uniform sampler2D texture1;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material material;
uniform Light light;
uniform vec3 viewPos;
void main()
{
// Ambient
vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
// Diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(vec3(light.position - FragPos));
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
// Specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));
vec3 result = ambient diffuse specular;
FragColor = vec4(result, 1.0);
}
Ответ №3:
Я нашел проблему. Я забыл упомянуть, что прямо над земной сферой находится другая сфера с прозрачной текстурой. С новой реализацией light альфа-смешивание не работает.
Я вставил это в новый вопрос. Спасибо Rabbid76 за ваше участие!