My current goal is to render a quad with colors, but currently my quad is drawn as completely white. I am using the "modern method," with each vertex's position and color being interleaved into one VBO. The quad is being drawn correctly, but the entire quad is white. I have tried enabling blending and alpha.
My code is based around the tutorials found on the LWJGL wiki, with a few minor adjustments:
- My loop is found in my main class; the majority of my rendering code has been isolated to my QuadRendering class
- I load the element buffer in the very beginning and reuse it for every draw
- My vertex class is condensed with the order x, y, z, r, g, b, a
- Removed the magic numbers that the tutorial used to identify attributes; I defined them at the top of my QuadRendering class
I am relatively new to OpenGL, so any comments on how I structure things or my interpretation of the functions are appreciated.
Here is my code,
Main Render Method:
private void render(double dT) {
try(MemoryStack stack = stackPush()) {
IntBuffer pWidth = stack.mallocInt(1);
IntBuffer pHeight = stack.mallocInt(1);
glfwGetWindowSize(window, pWidth, pHeight);
glViewport(0, 0, pWidth.get(0), pHeight.get(0));
}
shader.bind();
QuadRendering.render(dT);
shader.unbind();
}
QuadRendering:
package com.kain.gp1;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import java.nio.*;
import org.lwjgl.*;
import org.lwjgl.opengl.*;
import com.kain.gp1.render.*;
public class QuadRendering {
public static final int POSITION = 0, COLOR = 1;
public static int quadIndicesVBOID, quadIndexCount;
public static void preloadData() {
byte[] indices = {
0, 1, 2,
2, 3, 0
};
quadIndexCount = indices.length;
ByteBuffer indicesBuffer = BufferUtils.createByteBuffer(quadIndexCount);
indicesBuffer.put(indices);
indicesBuffer.flip();
quadIndicesVBOID = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadIndicesVBOID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
public static void render(double dT) {
int vaoID = GL30.glGenVertexArrays();
int vboID = GL15.glGenBuffers();
FloatBuffer verticesBuffer = Vertex.combineVertices(
new Vertex(-0.5F, 0.5F, 0F, 1F, 0F, 0F, 1F),
new Vertex(-0.5F, -0.5F, 0F, 0F, 1F, 0F, 1F),
new Vertex(0.5F, -0.5F, 0F, 0F, 0F, 1F, 1F),
new Vertex(0.5F, 0.5F, 0F, 1F, 1F, 1F, 1F));
//Data variables created
//Now to send the data to the GPU
glBindVertexArray(vaoID);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(POSITION, Vertex.XYZ_SIZE, GL_FLOAT, false, Vertex.TOTAL_BYTE_SIZE, 0);
glVertexAttribPointer(COLOR, Vertex.COLOR_SIZE, GL_FLOAT, false, Vertex.TOTAL_BYTE_SIZE, Vertex.XYZ_BYTE_SIZE);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
//Data sent to the GPU
//Now to draw
glEnable(GL_BLEND); //These 2 methods are my attempts to get any color to appear
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindVertexArray(vaoID);
glEnableVertexAttribArray(POSITION);
glEnableVertexAttribArray(COLOR);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadIndicesVBOID);
glDrawElements(GL_TRIANGLES, quadIndexCount, GL_UNSIGNED_BYTE, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(POSITION);
glDisableVertexAttribArray(COLOR);
glBindVertexArray(0);
//After drawing, we have to dispose of the variables
glDeleteBuffers(vboID);
glDeleteVertexArrays(vaoID);
}
public static void dispose() {
glDeleteBuffers(quadIndicesVBOID);
}
}
Vertex:
package com.kain.gp1.render;
import java.nio.*;
import org.lwjgl.system.*;
public class Vertex {
public static int XYZ_SIZE = 3, COLOR_SIZE = 4, TOTAL_SIZE = XYZ_SIZE + COLOR_SIZE;
public static int FLOAT_BYTE_SIZE = 4;
public static int XYZ_BYTE_SIZE = XYZ_SIZE * FLOAT_BYTE_SIZE, COLOR_BYTE_SIZE = COLOR_SIZE * FLOAT_BYTE_SIZE, TOTAL_BYTE_SIZE = TOTAL_SIZE * FLOAT_BYTE_SIZE;
public float[] xyz, color, uv;
public Vertex(float x, float y, float z, float r, float g, float b, float a) {
setXYZ(x, y, z);
setColor(r, g, b, a);
}
public Vertex setXYZ(float x, float y, float z) {
xyz = new float[] { x, y, z };
return this;
}
public Vertex setColor(float r, float g, float b, float a) {
color = new float[] { r, g, b, a };
return this;
}
public FloatBuffer toFloatBuffer() {
FloatBuffer buf = MemoryUtil.memCallocFloat(TOTAL_SIZE);
buf.put(xyz);
buf.put(color);
buf.flip();
return buf;
}
public static FloatBuffer combineVertices(Vertex... vertices) {
FloatBuffer verticesBuf = MemoryUtil.memAllocFloat(TOTAL_SIZE * vertices.length);
for(Vertex vertex : vertices) {
verticesBuf.put(vertex.toFloatBuffer());
}
verticesBuf.flip();
return verticesBuf;
}
}
ShaderProgram:
package com.kain.gp1.shader;
import static org.lwjgl.opengl.GL20.*;
import java.io.*;
import java.nio.charset.*;
import java.nio.file.*;
import com.kain.gp1.*;
public class ShaderProgram {
public final int programID, vsID, fsID;
public ShaderProgram() throws Exception {
programID = glCreateProgram();
if(programID == 0) {
throw new Exception("Could not create Shader");
}
vsID = createShader(getFileText("./res/vertex.vs"), GL_VERTEX_SHADER);
fsID = createShader(getFileText("./res/fragment.fs"), GL_FRAGMENT_SHADER);
}
public void link() throws Exception {
glLinkProgram(programID);
if(glGetProgrami(programID, GL_LINK_STATUS) == 0) {
throw new Exception("Error linking shader program: " + glGetProgramInfoLog(programID, 1024));
}
if(vsID != 0) {
glDetachShader(programID, vsID);
}
if(fsID != 0) {
glDetachShader(programID, fsID);
glValidateProgram(programID);
if(glGetProgrami(programID, GL_VALIDATE_STATUS) == 0) {
System.err.println("Warning validating shader code: " + glGetProgramInfoLog(programID, 1024));
}
}
}
public void bind() {
glUseProgram(programID);
}
public void unbind() {
glUseProgram(0);
}
public void dispose() {
unbind();
if(programID != 0) {
glDeleteProgram(programID);
}
}
private int createShader(String shaderCode, int shaderType) throws Exception {
int shaderID = glCreateShader(shaderType);
if(shaderID == 0) {
throw new Exception("Error creating shader. Type: " + shaderType);
}
glShaderSource(shaderID, shaderCode);
glCompileShader(shaderID);
if(glGetShaderi(shaderID, GL_COMPILE_STATUS) == 0) {
throw new Exception("Error compiling shader code: " + glGetShaderInfoLog(shaderID, 1024));
}
glBindAttribLocation(programID, QuadRendering.POSITION, "in_Position");
glBindAttribLocation(programID, QuadRendering.COLOR, "in_Color");
glAttachShader(programID, shaderID);
return shaderID;
}
private String getFileText(String file) throws IOException {
byte[] encoded = Files.readAllBytes(Paths.get(file));
return new String(encoded, StandardCharsets.UTF_8);
}
}
Vertex Shader:
#version 150 core
in vec4 in_Position;
in vec4 in_Color;
in vec2 in_UV;
out vec4 pass_Color;
out vec2 pass_UV;
void main() {
gl_Position = in_Position;
pass_Color = in_Color;
pass_UV = in_UV;
}
Fragment Shader:
#version 150 core
uniform sampler2D texture_diffuse;
in vec4 pass_Color;
in vec2 pass_UV;
out vec4 out_Color;
out vec2 out_UV;
void main() {
out_Color = pass_Color;
out_Color = texture(texture_diffuse, pass_UV);
}
I'm new too but may be the problem in fragment shader
out_Color = pass_Color;
out_Color = texture(texture_diffuse, pass_UV);
first you set the out color to be pass_Color than set it again to be texture(texture_diffuse, pass_UV).
You must add values.
out_Color = pass_Color + texture(texture_diffuse, pass_UV);
the final code
#version 150 core
uniform sampler2D texture_diffuse;
in vec4 pass_Color;
in vec2 pass_UV;
out vec4 out_Color;
out vec2 out_UV;
void main() {
out_Color = pass_Color + texture(texture_diffuse, pass_UV);
}