Anonymous
Рендеринг текстур OpenGL поверх других с помощью 3D Batch Renderer
Сообщение
Anonymous » 28 июн 2024, 06:37
Итак, мой текущий рендерер OpenGL по какой-то причине рисует текстуру B с текстурой A. Я проверил слоты в RenderDoc, и они, кажется, правильно связаны с glBindTexture() и glActiveTexture(). Я не совсем понимаю, что происходит. Я заметил, что, когда камера вообще не перемещается, проблема исчезает.
Скриншот
Это основной класс:
Скриншот
Это основной класс:
р>
Код: Выделить всё
package demo;
import org.joml.Matrix4f;
import org.lwjgl.opengl.GL46;
import rebel.graphics.*;
public class Test3D {
public static void main(String[] args) {
Window window = new Window(1000, 600, "");
Renderer3D renderer3D = new Renderer3D(window.getWidth(), window.getHeight(), true);
Texture2D a = new Texture2D("project/logo.png");
Texture2D b = new Texture2D("project/texture.png");
float rotX = 0f, rotY = 0f, rotZ = 0f;
while(!window.shouldClose()){
renderer3D.clear(Color.WHITE);
renderer3D.setOrigin(0, 0);
renderer3D.drawTexture(0.5f / -2f, 0.5f / -2f, 0.5f, 0.5f, a, Color.RED);
renderer3D.drawTexture((0.5f / -2f) + 0.5f, 0.5f / -2f, 1f, 1f, b, Color.BLUE);
renderer3D.resetTransform();
renderer3D.getCamera().getViewMatrix().rotate((float) Math.toRadians(rotX), 1, 0, 0);
renderer3D.getCamera().getViewMatrix().rotate((float) Math.toRadians(rotY), 0, 1, 0);
renderer3D.getCamera().getViewMatrix().translate(0, 0, 1f);
rotX = 360 * -(window.getMouseY() / window.getHeight());
rotY = 360 * (window.getMouseX() / window.getWidth());
renderer3D.updateCamera2D();
renderer3D.render();
renderer3D.getCamera().getViewMatrix().set(new Matrix4f().identity());
System.out.println(GL46.glGetError());
window.update();
}
window.close();
}
}
И Renderer3D:
Код: Выделить всё
package rebel.graphics;
import org.joml.*;
import org.lwjgl.BufferUtils;
import rebel.FileReader;
import java.lang.Math;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
import static org.lwjgl.opengl.GL46.*;
public class Renderer3D {
private int width;
private int height;
private Matrix4f proj;
private Camera camera;
private Matrix4f translation;
private VertexBuffer vertexBuffer;
private float[] vertexData;
private int maxTextureSlots;
private ShaderProgram defaultShaderProgram, currentShaderProgram;
private ArrayList renderCallNames = new ArrayList(50);
private boolean debug = false;
private FastTextureLookup textureLookup;
private static final float FOV = (float) Math.toRadians(60.0f);
private static final float Z_NEAR = 0.01f;
private static final float Z_FAR = 1000.f;
public Renderer3D(int width, int height, boolean msaa) {
this.width = width;
this.height = height;
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_NOTEQUAL);
float aspectRatio = (float) getWidth() / getHeight();
proj = new Matrix4f().perspective(FOV, aspectRatio,
Z_NEAR, Z_FAR);
camera = new Camera();
translation = new Matrix4f().identity();
IntBuffer d = BufferUtils.createIntBuffer(1);
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, d);
maxTextureSlots = d.get();
textureLookup = new FastTextureLookup(maxTextureSlots);
defaultShaderProgram = new ShaderProgram(
FileReader.readFile(Renderer2D.class.getClassLoader().getResourceAsStream("3DBatchVertexShader.glsl")),
FileReader.readFile(Renderer2D.class.getClassLoader().getResourceAsStream("3DBatchFragmentShader.glsl"))
);
defaultShaderProgram.prepare();
currentShaderProgram = defaultShaderProgram;
currentShaderProgram.bind();
updateCamera2D();
VertexArray vertexArray = new VertexArray();
vertexArray.bind();
vertexArray.setVertexAttributes(
new VertexAttribute(0, 3, false, "v_pos"),
new VertexAttribute(1, 2, false, "v_uv"),
new VertexAttribute(2, 1, false, "v_texindex"),
new VertexAttribute(3, 4, false, "v_color"),
new VertexAttribute(4, 1, false, "v_thickness")
);
vertexBuffer = new VertexBuffer(1000, vertexArray.getStride());
vertexArray.build();
vertexData = new float[vertexBuffer.getNumOfVertices() * vertexBuffer.getVertexDataSize()];
}
/***
* Sets the current shader. This shader must be compiled before calling this method!
* @param shaderProgram
*/
public void setShader(ShaderProgram shaderProgram){
if(currentShaderProgram != shaderProgram) {
currentShaderProgram = shaderProgram;
currentShaderProgram.bind();
updateCamera2D();
}
}
public void updateCamera2D(){
currentShaderProgram.setMatrix4f("v_model", getTranslation());
currentShaderProgram.setMatrix4f("v_view", getView());
currentShaderProgram.setMatrix4f("v_projection", getProj());
currentShaderProgram.setIntArray("u_textures", createTextureSlots());
}
private int[] createTextureSlots() {
int[] slots = new int[maxTextureSlots];
for (int i = 0; i < maxTextureSlots; i++) {
slots[i] = i;
}
return slots;
}
public VertexBuffer getVertexBuffer() {
return vertexBuffer;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public Matrix4f getProj() {
return proj;
}
public Camera getCamera() {
return camera;
}
public Matrix4f getView() {
return camera.getViewMatrix();
}
public Matrix4f getTranslation() {
return translation;
}
private int quadIndex;
private int nextTextureSlot;
private Matrix4f transform = new Matrix4f().identity();
private float originX, originY;
public Matrix4f getTransform() {
return transform;
}
public void setTransform(Matrix4f transform) {
this.transform = transform;
}
public void resetTransform(){
setTransform(new Matrix4f().identity());
}
public void drawTexture(float x, float y, float w, float h, Texture2D texture){
drawTexture(x, y, w, h, texture, Color.WHITE);
}
public void setOrigin(float x, float y){
this.originX = x;
this.originY = y;
}
public void drawTexture(float x, float y, float w, float h, Texture2D texture, Color color){
drawTexture(x, y, w, h, texture, color, new Rect2D(0, 0, 1, 1), false, false);
}
public void drawTexture(float x, float y, float w, float h, Texture2D texture, Color color, Rect2D rect2D, boolean xFlip, boolean yFlip) {
int slot = nextTextureSlot;
boolean isUniqueTexture = false;
//Existing texture
if (textureLookup.hasTexture(texture)) {
slot = textureLookup.getTexture(texture);
}
//Unique Texture
else {
glActiveTexture(GL_TEXTURE0 + slot);
texture.bind();
texture.setSlot(slot);
textureLookup.registerTexture(texture, slot);
isUniqueTexture = true;
}
drawQuadGL(x, y, w, h, slot, color, originX, originY, rect2D, -1, xFlip, yFlip);
if(isUniqueTexture) nextTextureSlot++;
if(nextTextureSlot == maxTextureSlots)
render("Next Batch Render [No more rebel.engine.graphics.Texture slots out of " + maxTextureSlots + "]");
}
public void drawQuadGL(float x, float y, float w, float h, int slot, Color color, float originX, float originY, Rect2D region, float thickness, boolean xFlip, boolean yFlip){
//Translate back by origin (for rotation math)
//This usually takes everything near (0, 0)
Rect2D copy = new Rect2D(region.x, region.y, region.w, region.h);
if(xFlip){
float temp = copy.x;
copy.x = copy.w;
copy.w = temp;
}
if(yFlip){
float temp = copy.y;
copy.y = copy.h;
copy.h = temp;
}
float z = -0.25f;
Vector4f topLeft = new Vector4f(x - originX, y - originY, z, 1);
Vector4f topRight = new Vector4f(x + w - originX, y - originY, z, 1);
Vector4f bottomLeft = new Vector4f(x - originX, y + h - originY, z, 1);
Vector4f bottomRight = new Vector4f(x + w - originX, y + h - originY, z, 1);
topLeft.mul(transform);
topRight.mul(transform);
bottomLeft.mul(transform);
bottomRight.mul(transform);
//Translate forward by origin back to the current position
topLeft.x += originX;
topRight.x += originX;
bottomLeft.x += originX;
bottomRight.x += originX;
topLeft.y += originY;
topRight.y += originY;
bottomLeft.y += originY;
bottomRight.y += originY;
{
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 0] = topLeft.x;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 1] = topLeft.y;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 2] = topLeft.z;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 3] = copy.x;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 4] = copy.y;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 5] = slot;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 6] = color.r;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 7] = color.g;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 8] = color.b;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 9] = color.a;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 10] = thickness;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 11] = bottomLeft.x;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 12] = bottomLeft.y;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 13] = bottomLeft.z;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 14] = copy.x;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 15] = copy.h;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 16] = slot;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 17] = color.r;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 18] = color.g;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 19] = color.b;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 20] = color.a;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 21] = thickness;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 22] = bottomRight.x;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 23] = bottomRight.y;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 24] = bottomRight.z;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 25] = copy.w;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 26] = copy.h;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 27] = slot;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 28] = color.r;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 29] = color.g;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 30] = color.b;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 31] = color.a;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 32] = thickness;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 33] = topRight.x;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 34] = topRight.y;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 35] = topRight.z;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 36] = copy.w;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 37] = copy.y;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 38] = slot;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 39] = color.r;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 40] = color.g;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 41] = color.b;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 42] = color.a;
vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 43] = thickness;
}
quadIndex++;
if(quadIndex == vertexBuffer.maxQuads()) render("Next Batch Render");
}
public void render(){
render("Final Draw Call [rebel.engine.graphics.Renderer2D.render()]");
if(debug){
System.out.println("Renderer2D (" + this + ") - Debug");
for(String call : getRenderCalls()){
System.out.print("\t" + call + "\n");
}
System.out.println("\n");
}
renderCallNames.clear();
}
public void render(String renderName) {
renderCallNames.add(renderName);
glBindBuffer(GL_ARRAY_BUFFER, getVertexBuffer().myVbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexData);
int numOfIndices = quadIndex * 6;
int[] indices = new int[numOfIndices];
int offset = 0;
for (int j = 0; j < numOfIndices; j += 6) {
indices[j] = offset;
indices[j + 1] = 1 + offset;
indices[j + 2] = 2 + offset;
indices[j + 3] = 2 + offset;
indices[j + 4] = 3 + offset;
indices[j + 5] = offset;
offset += 4;
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getVertexBuffer().myEbo);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indices);
glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_INT, 0);
vertexData = new float[vertexBuffer.getNumOfVertices() * vertexBuffer.getVertexDataSize()];
quadIndex = 0;
nextTextureSlot = 0;
textureLookup.clear();
}
public List getRenderCalls(){
return new ArrayList(renderCallNames);
}
public void clear(Color color) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(color.r, color.g, color.b, color.a);
}
}
Это мой вершинный шейдер:
Код: Выделить всё
#version 330 core
layout (location = 0) in vec3 v_pos;
layout (location = 1) in vec2 v_uv;
layout (location = 2) in float v_texindex;
layout (location = 3) in vec4 v_color;
layout (location = 4) in float v_thickness;
out vec2 f_uv;
out float f_texindex;
out vec4 f_color;
out vec2 f_origin;
out vec2 f_size;
out float f_thickness;
uniform mat4 v_model;
uniform mat4 v_view;
uniform mat4 v_projection;
void main() {
f_texindex = v_texindex;
f_uv = v_uv;
f_color = v_color;
f_thickness = v_thickness;
gl_Position = v_projection * v_view * v_model * vec4(v_pos, 1.0);
}
И мой фрагментный шейдер
Код: Выделить всё
#version 330 core
out vec4 FragColor;
in vec2 f_uv;
uniform sampler2D u_textures[32];
in float f_texindex;
in vec4 f_color;
in float f_thickness;
layout(origin_upper_left) in vec4 gl_FragCoord;
void main()
{
int index = int(f_texindex);
if(index == -1){
FragColor = f_color;
}
else if(index == -2){
vec2 uv = f_uv * 2.0 - 1.0;
float distance = length(uv);
if(distance = (1.0 - f_thickness))
FragColor = f_color;
else
discard;
}
else {
if(index == 0) FragColor += texture(u_textures[0], f_uv) * f_color;
if(index == 1) FragColor += texture(u_textures[1], f_uv) * f_color;
if(index == 2) FragColor += texture(u_textures[2], f_uv) * f_color;
if(index == 3) FragColor += texture(u_textures[3], f_uv) * f_color;
if(index == 4) FragColor += texture(u_textures[4], f_uv) * f_color;
if(index == 5) FragColor += texture(u_textures[5], f_uv) * f_color;
if(index == 6) FragColor += texture(u_textures[6], f_uv) * f_color;
if(index == 7) FragColor += texture(u_textures[7], f_uv) * f_color;
if(index == 8) FragColor += texture(u_textures[8], f_uv) * f_color;
if(index == 9) FragColor += texture(u_textures[9], f_uv) * f_color;
if(index == 10) FragColor += texture(u_textures[10], f_uv) * f_color;
if(index == 11) FragColor += texture(u_textures[11], f_uv) * f_color;
if(index == 12) FragColor += texture(u_textures[12], f_uv) * f_color;
if(index == 13) FragColor += texture(u_textures[13], f_uv) * f_color;
if(index == 14) FragColor += texture(u_textures[14], f_uv) * f_color;
if(index == 15) FragColor += texture(u_textures[15], f_uv) * f_color;
if(index == 16) FragColor += texture(u_textures[16], f_uv) * f_color;
if(index == 17) FragColor += texture(u_textures[17], f_uv) * f_color;
if(index == 18) FragColor += texture(u_textures[18], f_uv) * f_color;
if(index == 19) FragColor += texture(u_textures[19], f_uv) * f_color;
if(index == 20) FragColor += texture(u_textures[20], f_uv) * f_color;
if(index == 21) FragColor += texture(u_textures[21], f_uv) * f_color;
if(index == 22) FragColor += texture(u_textures[22], f_uv) * f_color;
if(index == 23) FragColor += texture(u_textures[23], f_uv) * f_color;
if(index == 24) FragColor += texture(u_textures[24], f_uv) * f_color;
if(index == 25) FragColor += texture(u_textures[25], f_uv) * f_color;
if(index == 26) FragColor += texture(u_textures[26], f_uv) * f_color;
if(index == 27) FragColor += texture(u_textures[27], f_uv) * f_color;
if(index == 28) FragColor += texture(u_textures[28], f_uv) * f_color;
if(index == 29) FragColor += texture(u_textures[29], f_uv) * f_color;
if(index == 30) FragColor += texture(u_textures[30], f_uv) * f_color;
if(index == 31) FragColor += texture(u_textures[31], f_uv) * f_color;
}
}
Я ожидал, что текстуры будут отображаться без каких-либо сбоев, в основном потому, что я перенес логику пакетной обработки текстур из своего 2D-рендерера. Я уверен, что мне не хватает чего-то простого. Я использую NVIDIA GeForce MX450 PCIe/SSE2.
glGetError() не сообщил об ошибках, а обратный вызов LWJGL OpenGL все время молчал. С помощью RenderDoc я проверил, что текстуры привязаны к правильным слотам.
Подробнее здесь:
https://stackoverflow.com/questions/777 ... h-renderer
1719545856
Anonymous
Итак, мой текущий рендерер OpenGL по какой-то причине рисует текстуру B с текстурой A. Я проверил слоты в RenderDoc, и они, кажется, правильно связаны с glBindTexture() и glActiveTexture(). Я не совсем понимаю, что происходит. Я заметил, что, когда камера вообще не перемещается, проблема исчезает. Скриншот Это основной класс: Скриншот Это основной класс: р> [code]package demo; import org.joml.Matrix4f; import org.lwjgl.opengl.GL46; import rebel.graphics.*; public class Test3D { public static void main(String[] args) { Window window = new Window(1000, 600, ""); Renderer3D renderer3D = new Renderer3D(window.getWidth(), window.getHeight(), true); Texture2D a = new Texture2D("project/logo.png"); Texture2D b = new Texture2D("project/texture.png"); float rotX = 0f, rotY = 0f, rotZ = 0f; while(!window.shouldClose()){ renderer3D.clear(Color.WHITE); renderer3D.setOrigin(0, 0); renderer3D.drawTexture(0.5f / -2f, 0.5f / -2f, 0.5f, 0.5f, a, Color.RED); renderer3D.drawTexture((0.5f / -2f) + 0.5f, 0.5f / -2f, 1f, 1f, b, Color.BLUE); renderer3D.resetTransform(); renderer3D.getCamera().getViewMatrix().rotate((float) Math.toRadians(rotX), 1, 0, 0); renderer3D.getCamera().getViewMatrix().rotate((float) Math.toRadians(rotY), 0, 1, 0); renderer3D.getCamera().getViewMatrix().translate(0, 0, 1f); rotX = 360 * -(window.getMouseY() / window.getHeight()); rotY = 360 * (window.getMouseX() / window.getWidth()); renderer3D.updateCamera2D(); renderer3D.render(); renderer3D.getCamera().getViewMatrix().set(new Matrix4f().identity()); System.out.println(GL46.glGetError()); window.update(); } window.close(); } } [/code] И Renderer3D: [code]package rebel.graphics; import org.joml.*; import org.lwjgl.BufferUtils; import rebel.FileReader; import java.lang.Math; import java.nio.IntBuffer; import java.util.ArrayList; import java.util.List; import static org.lwjgl.opengl.GL46.*; public class Renderer3D { private int width; private int height; private Matrix4f proj; private Camera camera; private Matrix4f translation; private VertexBuffer vertexBuffer; private float[] vertexData; private int maxTextureSlots; private ShaderProgram defaultShaderProgram, currentShaderProgram; private ArrayList renderCallNames = new ArrayList(50); private boolean debug = false; private FastTextureLookup textureLookup; private static final float FOV = (float) Math.toRadians(60.0f); private static final float Z_NEAR = 0.01f; private static final float Z_FAR = 1000.f; public Renderer3D(int width, int height, boolean msaa) { this.width = width; this.height = height; glEnable(GL_DEPTH_TEST); glDepthFunc(GL_NOTEQUAL); float aspectRatio = (float) getWidth() / getHeight(); proj = new Matrix4f().perspective(FOV, aspectRatio, Z_NEAR, Z_FAR); camera = new Camera(); translation = new Matrix4f().identity(); IntBuffer d = BufferUtils.createIntBuffer(1); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, d); maxTextureSlots = d.get(); textureLookup = new FastTextureLookup(maxTextureSlots); defaultShaderProgram = new ShaderProgram( FileReader.readFile(Renderer2D.class.getClassLoader().getResourceAsStream("3DBatchVertexShader.glsl")), FileReader.readFile(Renderer2D.class.getClassLoader().getResourceAsStream("3DBatchFragmentShader.glsl")) ); defaultShaderProgram.prepare(); currentShaderProgram = defaultShaderProgram; currentShaderProgram.bind(); updateCamera2D(); VertexArray vertexArray = new VertexArray(); vertexArray.bind(); vertexArray.setVertexAttributes( new VertexAttribute(0, 3, false, "v_pos"), new VertexAttribute(1, 2, false, "v_uv"), new VertexAttribute(2, 1, false, "v_texindex"), new VertexAttribute(3, 4, false, "v_color"), new VertexAttribute(4, 1, false, "v_thickness") ); vertexBuffer = new VertexBuffer(1000, vertexArray.getStride()); vertexArray.build(); vertexData = new float[vertexBuffer.getNumOfVertices() * vertexBuffer.getVertexDataSize()]; } /*** * Sets the current shader. This shader must be compiled before calling this method! * @param shaderProgram */ public void setShader(ShaderProgram shaderProgram){ if(currentShaderProgram != shaderProgram) { currentShaderProgram = shaderProgram; currentShaderProgram.bind(); updateCamera2D(); } } public void updateCamera2D(){ currentShaderProgram.setMatrix4f("v_model", getTranslation()); currentShaderProgram.setMatrix4f("v_view", getView()); currentShaderProgram.setMatrix4f("v_projection", getProj()); currentShaderProgram.setIntArray("u_textures", createTextureSlots()); } private int[] createTextureSlots() { int[] slots = new int[maxTextureSlots]; for (int i = 0; i < maxTextureSlots; i++) { slots[i] = i; } return slots; } public VertexBuffer getVertexBuffer() { return vertexBuffer; } public int getWidth() { return width; } public int getHeight() { return height; } public Matrix4f getProj() { return proj; } public Camera getCamera() { return camera; } public Matrix4f getView() { return camera.getViewMatrix(); } public Matrix4f getTranslation() { return translation; } private int quadIndex; private int nextTextureSlot; private Matrix4f transform = new Matrix4f().identity(); private float originX, originY; public Matrix4f getTransform() { return transform; } public void setTransform(Matrix4f transform) { this.transform = transform; } public void resetTransform(){ setTransform(new Matrix4f().identity()); } public void drawTexture(float x, float y, float w, float h, Texture2D texture){ drawTexture(x, y, w, h, texture, Color.WHITE); } public void setOrigin(float x, float y){ this.originX = x; this.originY = y; } public void drawTexture(float x, float y, float w, float h, Texture2D texture, Color color){ drawTexture(x, y, w, h, texture, color, new Rect2D(0, 0, 1, 1), false, false); } public void drawTexture(float x, float y, float w, float h, Texture2D texture, Color color, Rect2D rect2D, boolean xFlip, boolean yFlip) { int slot = nextTextureSlot; boolean isUniqueTexture = false; //Existing texture if (textureLookup.hasTexture(texture)) { slot = textureLookup.getTexture(texture); } //Unique Texture else { glActiveTexture(GL_TEXTURE0 + slot); texture.bind(); texture.setSlot(slot); textureLookup.registerTexture(texture, slot); isUniqueTexture = true; } drawQuadGL(x, y, w, h, slot, color, originX, originY, rect2D, -1, xFlip, yFlip); if(isUniqueTexture) nextTextureSlot++; if(nextTextureSlot == maxTextureSlots) render("Next Batch Render [No more rebel.engine.graphics.Texture slots out of " + maxTextureSlots + "]"); } public void drawQuadGL(float x, float y, float w, float h, int slot, Color color, float originX, float originY, Rect2D region, float thickness, boolean xFlip, boolean yFlip){ //Translate back by origin (for rotation math) //This usually takes everything near (0, 0) Rect2D copy = new Rect2D(region.x, region.y, region.w, region.h); if(xFlip){ float temp = copy.x; copy.x = copy.w; copy.w = temp; } if(yFlip){ float temp = copy.y; copy.y = copy.h; copy.h = temp; } float z = -0.25f; Vector4f topLeft = new Vector4f(x - originX, y - originY, z, 1); Vector4f topRight = new Vector4f(x + w - originX, y - originY, z, 1); Vector4f bottomLeft = new Vector4f(x - originX, y + h - originY, z, 1); Vector4f bottomRight = new Vector4f(x + w - originX, y + h - originY, z, 1); topLeft.mul(transform); topRight.mul(transform); bottomLeft.mul(transform); bottomRight.mul(transform); //Translate forward by origin back to the current position topLeft.x += originX; topRight.x += originX; bottomLeft.x += originX; bottomRight.x += originX; topLeft.y += originY; topRight.y += originY; bottomLeft.y += originY; bottomRight.y += originY; { vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 0] = topLeft.x; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 1] = topLeft.y; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 2] = topLeft.z; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 3] = copy.x; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 4] = copy.y; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 5] = slot; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 6] = color.r; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 7] = color.g; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 8] = color.b; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 9] = color.a; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 10] = thickness; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 11] = bottomLeft.x; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 12] = bottomLeft.y; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 13] = bottomLeft.z; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 14] = copy.x; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 15] = copy.h; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 16] = slot; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 17] = color.r; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 18] = color.g; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 19] = color.b; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 20] = color.a; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 21] = thickness; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 22] = bottomRight.x; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 23] = bottomRight.y; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 24] = bottomRight.z; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 25] = copy.w; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 26] = copy.h; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 27] = slot; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 28] = color.r; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 29] = color.g; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 30] = color.b; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 31] = color.a; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 32] = thickness; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 33] = topRight.x; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 34] = topRight.y; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 35] = topRight.z; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 36] = copy.w; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 37] = copy.y; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 38] = slot; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 39] = color.r; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 40] = color.g; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 41] = color.b; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 42] = color.a; vertexData[(quadIndex * vertexBuffer.getVertexDataSize()) + 43] = thickness; } quadIndex++; if(quadIndex == vertexBuffer.maxQuads()) render("Next Batch Render"); } public void render(){ render("Final Draw Call [rebel.engine.graphics.Renderer2D.render()]"); if(debug){ System.out.println("Renderer2D (" + this + ") - Debug"); for(String call : getRenderCalls()){ System.out.print("\t" + call + "\n"); } System.out.println("\n"); } renderCallNames.clear(); } public void render(String renderName) { renderCallNames.add(renderName); glBindBuffer(GL_ARRAY_BUFFER, getVertexBuffer().myVbo); glBufferSubData(GL_ARRAY_BUFFER, 0, vertexData); int numOfIndices = quadIndex * 6; int[] indices = new int[numOfIndices]; int offset = 0; for (int j = 0; j < numOfIndices; j += 6) { indices[j] = offset; indices[j + 1] = 1 + offset; indices[j + 2] = 2 + offset; indices[j + 3] = 2 + offset; indices[j + 4] = 3 + offset; indices[j + 5] = offset; offset += 4; } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getVertexBuffer().myEbo); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indices); glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_INT, 0); vertexData = new float[vertexBuffer.getNumOfVertices() * vertexBuffer.getVertexDataSize()]; quadIndex = 0; nextTextureSlot = 0; textureLookup.clear(); } public List getRenderCalls(){ return new ArrayList(renderCallNames); } public void clear(Color color) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(color.r, color.g, color.b, color.a); } } [/code] Это мой вершинный шейдер: [code]#version 330 core layout (location = 0) in vec3 v_pos; layout (location = 1) in vec2 v_uv; layout (location = 2) in float v_texindex; layout (location = 3) in vec4 v_color; layout (location = 4) in float v_thickness; out vec2 f_uv; out float f_texindex; out vec4 f_color; out vec2 f_origin; out vec2 f_size; out float f_thickness; uniform mat4 v_model; uniform mat4 v_view; uniform mat4 v_projection; void main() { f_texindex = v_texindex; f_uv = v_uv; f_color = v_color; f_thickness = v_thickness; gl_Position = v_projection * v_view * v_model * vec4(v_pos, 1.0); } [/code] И мой фрагментный шейдер [code]#version 330 core out vec4 FragColor; in vec2 f_uv; uniform sampler2D u_textures[32]; in float f_texindex; in vec4 f_color; in float f_thickness; layout(origin_upper_left) in vec4 gl_FragCoord; void main() { int index = int(f_texindex); if(index == -1){ FragColor = f_color; } else if(index == -2){ vec2 uv = f_uv * 2.0 - 1.0; float distance = length(uv); if(distance = (1.0 - f_thickness)) FragColor = f_color; else discard; } else { if(index == 0) FragColor += texture(u_textures[0], f_uv) * f_color; if(index == 1) FragColor += texture(u_textures[1], f_uv) * f_color; if(index == 2) FragColor += texture(u_textures[2], f_uv) * f_color; if(index == 3) FragColor += texture(u_textures[3], f_uv) * f_color; if(index == 4) FragColor += texture(u_textures[4], f_uv) * f_color; if(index == 5) FragColor += texture(u_textures[5], f_uv) * f_color; if(index == 6) FragColor += texture(u_textures[6], f_uv) * f_color; if(index == 7) FragColor += texture(u_textures[7], f_uv) * f_color; if(index == 8) FragColor += texture(u_textures[8], f_uv) * f_color; if(index == 9) FragColor += texture(u_textures[9], f_uv) * f_color; if(index == 10) FragColor += texture(u_textures[10], f_uv) * f_color; if(index == 11) FragColor += texture(u_textures[11], f_uv) * f_color; if(index == 12) FragColor += texture(u_textures[12], f_uv) * f_color; if(index == 13) FragColor += texture(u_textures[13], f_uv) * f_color; if(index == 14) FragColor += texture(u_textures[14], f_uv) * f_color; if(index == 15) FragColor += texture(u_textures[15], f_uv) * f_color; if(index == 16) FragColor += texture(u_textures[16], f_uv) * f_color; if(index == 17) FragColor += texture(u_textures[17], f_uv) * f_color; if(index == 18) FragColor += texture(u_textures[18], f_uv) * f_color; if(index == 19) FragColor += texture(u_textures[19], f_uv) * f_color; if(index == 20) FragColor += texture(u_textures[20], f_uv) * f_color; if(index == 21) FragColor += texture(u_textures[21], f_uv) * f_color; if(index == 22) FragColor += texture(u_textures[22], f_uv) * f_color; if(index == 23) FragColor += texture(u_textures[23], f_uv) * f_color; if(index == 24) FragColor += texture(u_textures[24], f_uv) * f_color; if(index == 25) FragColor += texture(u_textures[25], f_uv) * f_color; if(index == 26) FragColor += texture(u_textures[26], f_uv) * f_color; if(index == 27) FragColor += texture(u_textures[27], f_uv) * f_color; if(index == 28) FragColor += texture(u_textures[28], f_uv) * f_color; if(index == 29) FragColor += texture(u_textures[29], f_uv) * f_color; if(index == 30) FragColor += texture(u_textures[30], f_uv) * f_color; if(index == 31) FragColor += texture(u_textures[31], f_uv) * f_color; } } [/code] Я ожидал, что текстуры будут отображаться без каких-либо сбоев, в основном потому, что я перенес логику пакетной обработки текстур из своего 2D-рендерера. Я уверен, что мне не хватает чего-то простого. Я использую NVIDIA GeForce MX450 PCIe/SSE2. glGetError() не сообщил об ошибках, а обратный вызов LWJGL OpenGL все время молчал. С помощью RenderDoc я проверил, что текстуры привязаны к правильным слотам. Подробнее здесь: [url]https://stackoverflow.com/questions/77735195/opengl-texture-rendering-over-another-with-3d-batch-renderer[/url]