Привет, я работал над проектом для моего класса в университете и наткнулся на проблему во время рендеринга в OpenGL. Gameloop, кажется, работает отлично шейдером, читается, скомпилируется и подтверждается без исключений. У класса сетки, похоже, нет проблемы. Но появляется простой черный экран. Невозможно отобразить этот куб на сцене: < /p>
public class Game implements IAppLogic {
Scene scene;
@Override
public void init() {
scene = new Scene();
float[] cubePositions = new float[]{
// Front face
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // v0
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // v1
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // v2
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, // v3
// Back face
-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // v4
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // v5
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // v6
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // v7
// Top face
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, // v8 (same as v3)
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // v9 (same as v2)
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, // v10 (same as v6)
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, // v11 (same as v7)
// Bottom face
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // v12 (same as v0)
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // v13 (same as v1)
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, // v14 (same as v5)
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // v15 (same as v4)
// Right face
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // v16 (same as v1)
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // v17 (same as v5)
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // v18 (same as v6)
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, // v19 (same as v2)
// Left face
-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // v20 (same as v0)
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // v21 (same as v4)
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // v22 (same as v7)
-0.5f, 0.5f, 0.5f, 1.0f, 1.0f // v23 (same as v3)
};
float[] cubeTextCoords = new float[]{
// Front face
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
// Back face
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
// Top face
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f,
// Bottom face
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
// Right face
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
// Left face
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f
};
int[] cubeIndices = new int[]{
0, 1, 3, 3, 1, 2, // Front face
4, 5, 7, 7, 5, 6, // Back face
8, 9, 11, 11, 9, 10, // Top face
12, 13, 15, 15, 13, 14, // Bottom face
16, 17, 19, 19, 17, 18, // Right face
20, 21, 23, 23, 21, 22 // Left face
};
Mesh cubeMesh = new Mesh(cubePositions, cubeTextCoords, cubeIndices);
Model cube = new Model(cubeMesh, new Texture());
GameObject gameObject = new GameObject(cube);
gameObject.transform.position = new Vector3f(0, 0, -2);
scene.addGameObject(gameObject);
}
@Override
public void input() {
}
@Override
public void update() {
for (GameObject gameObject: scene.getGameObjects()){
gameObject.updateModelMatrix();
gameObject.update();
}
}
@Override
public void cleanup() {
}
public Scene getScene() {
return scene;
}
< /code>
} < /p>
Вот мой метод рендеринга в классе по сценарии: < /p>
public void render(Scene scene) {
shaderProgram.bind();
uniformsMap.setUniform("projectionMatrix", scene.getProjection().getProjectionMatrix());
uniformsMap.setUniform("txtSampler", 0);
List gameObjects = scene.getGameObjects();
for (GameObject gameObject : gameObjects) {
Model model = gameObject.getModel();
Mesh mesh = model.getMesh();
Material material = model.getMaterial();
// Bind texture
Texture texture = material.getTexture();
glActiveTexture(GL_TEXTURE0);
texture.bind();
// Set uniforms
uniformsMap.setUniform("material.diffuse", material.getDiffuseColor());
uniformsMap.setUniform("modelMatrix", gameObject.getModelMatrix());
// Render mesh
glBindVertexArray(mesh.getVaoId());
glDrawElements(GL_TRIANGLES, mesh.getNumVertices(), GL_UNSIGNED_INT, 0);
}
glBindVertexArray(0);
shaderProgram.unbind();
}
< /code>
Все униформы создаются правильно. < /p>
Вот класс сетки: < /p>
public Mesh(float[] positions, float[] textCoords, int[] indices) {
numVertices = indices.length;
vboIdList = new List();
vaoId = glGenVertexArrays();
glBindVertexArray(vaoId);
// Positions VBO
int vboId = glGenBuffers();
vboIdList.add(vboId);
FloatBuffer positionsBuffer = MemoryUtil.memCallocFloat(positions.length);
positionsBuffer.put(0, positions).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, positionsBuffer, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
// Texture coordinates VBO
vboId = glGenBuffers();
vboIdList.add(vboId);
FloatBuffer textCoordsBuffer = MemoryUtil.memCallocFloat(textCoords.length);
textCoordsBuffer.put(0, textCoords).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, textCoordsBuffer, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
// Index VBO
vboId = glGenBuffers();
vboIdList.add(vboId);
IntBuffer indicesBuffer = MemoryUtil.memCallocInt(indices.length);
indicesBuffer.put(0, indices).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
MemoryUtil.memFree(positionsBuffer);
MemoryUtil.memFree(textCoordsBuffer);
MemoryUtil.memFree(indicesBuffer);
}
< /code>
Класс модели содержит экземпляр сетки, а материал. Класс материала содержит экземпляр текстуры. Вот соответствующий код для класса текстуры: < /p>
public class Texture {
private int textureId;
private String texturePath;
public static final String DEFAULT_TEXTURE = "src/main/resources/models/default/default_texture.png";
public Texture(){
texturePath = DEFAULT_TEXTURE;
extracted(texturePath);
}
public Texture(String texturePath) {
extracted(texturePath);
}
private void extracted(String texturePath) {
try (MemoryStack stack = MemoryStack.stackPush()) {
this.texturePath = texturePath;
IntBuffer w = stack.mallocInt(1);
IntBuffer h = stack.mallocInt(1);
IntBuffer channels = stack.mallocInt(1);
ByteBuffer buffer = stbi_load(texturePath, w, h, channels, 4);
if (buffer == null) {
throw new RuntimeException("Image file [" + texturePath + "] not loaded: " + stbi_failure_reason());
}
int width = w.get();
int height = h.get();
generateTexture(width, height, buffer);
stbi_image_free(buffer);
}
}
public void bind() {
if (textureId > 0) {
glBindTexture(GL_TEXTURE_2D, textureId);
} else {
System.err.println("Texture not loaded properly. Texture ID: " + textureId);
}
}
public void cleanup() {
glDeleteTextures(textureId);
}
private void generateTexture(int width, int height, ByteBuffer buf) {
textureId = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, buf);
glGenerateMipmap(GL_TEXTURE_2D);
}
public String getTexturePath() {
return texturePath;
}
}
< /code>
код для Shaderprogram: < /p>
package Core.Render;
import Utils.Generics.List;
import Utils.Utils;
import org.lwjgl.opengl.GL30;
import static org.lwjgl.opengl.GL20.*;
public class ShaderProgram {
private final int programId;
public ShaderProgram(List shaderModuleDataList) {
programId = glCreateProgram();
if (programId == 0) {
throw new RuntimeException("Could not create Shader");
}
List shaderModules = new List();
shaderModuleDataList.forEach(s -> shaderModules.add(createShader(Utils.readFile(s.shaderFile), s.shaderType)));
link(shaderModules);
}
public void bind() {
glUseProgram(programId);
}
public void cleanup() {
unbind();
if (programId != 0) {
glDeleteProgram(programId);
}
}
protected int createShader(String shaderCode, int shaderType) {
int shaderId = glCreateShader(shaderType);
if (shaderId == 0) {
throw new RuntimeException("Error creating shader. Type: " + shaderType);
}
glShaderSource(shaderId, shaderCode);
glCompileShader(shaderId);
if (glGetShaderi(shaderId, GL_COMPILE_STATUS) == 0) {
throw new RuntimeException("Error compiling Shader code: " + glGetShaderInfoLog(shaderId, 1024));
}
glAttachShader(programId, shaderId);
return shaderId;
}
public int getProgramId() {
return programId;
}
private void link(List shaderModules) {
glLinkProgram(programId);
if (glGetProgrami(programId, GL_LINK_STATUS) == 0) {
throw new RuntimeException("Error linking Shader code: " + glGetProgramInfoLog(programId, 1024));
}
shaderModules.forEach(s -> glDetachShader(programId, s));
validate();
shaderModules.forEach(GL30::glDeleteShader);
}
public void unbind() {
glUseProgram(0);
}
public void validate() {
glValidateProgram(programId);
if (glGetProgrami(programId, GL_VALIDATE_STATUS) == 0) {
throw new RuntimeException("Error validating Shader code: " + glGetProgramInfoLog(programId, 1024));
}
}
public record ShaderModuleData(String shaderFile, int shaderType) {
}
}
< /code>
Карта униформы: < /p>
package Core.Render;
import Utils.Generics.HashMap;
import org.joml.Matrix4f;
import org.joml.Vector4f;
import org.lwjgl.system.MemoryStack;
import static org.lwjgl.opengl.GL20.*;
public class UniformsMap {
private int programId;
private HashMap uniforms;
public UniformsMap(int programId) {
this.programId = programId;
uniforms = new HashMap();
}
public void createUniform(String uniformName) {
int uniformLocation = glGetUniformLocation(programId, uniformName);
if (uniformLocation < 0) {
throw new RuntimeException("Could not find uniform [" + uniformName + "] in shader program [" + programId + "]");
}
uniforms.put(uniformName, uniformLocation);
}
private int getUniformLocation(String uniformName) {
Integer location = uniforms.get(uniformName);
if (location == null) {
throw new RuntimeException("Could not find uniform [" + uniformName + "]");
}
return location.intValue();
}
public void setUniform(String uniformName, int value) {
glUniform1i(getUniformLocation(uniformName), value);
}
public void setUniform(String uniformName, Matrix4f value) {
try (MemoryStack stack = MemoryStack.stackPush()) {
glUniformMatrix4fv(getUniformLocation(uniformName), false, value.get(stack.mallocFloat(16)));
}
}
public void setUniform(String uniformName, Vector4f value) {
glUniform4f(getUniformLocation(uniformName), value.x, value.y, value.z, value.w);
}
}
< /code>
GameObject Class: < /p>
package Core.Scene.Entity;
import Core.Scene.Entity.Component.BaseComponent;
import Utils.Generics.HashMap;
import org.joml.*;
public class GameObject {
private HashMap
Подробнее здесь: https://stackoverflow.com/questions/796 ... r-in-lwjgl