[DEV] tutorial 6 'texturing' implementation
This commit is contained in:
parent
7c1f3508c4
commit
e5467419ec
@ -805,5 +805,10 @@
|
||||
<attribute name="module" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="lib" path="lib/pngdecoder.jar">
|
||||
<attributes>
|
||||
<attribute name="module" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
BIN
lib/pngdecoder.jar
Normal file
BIN
lib/pngdecoder.jar
Normal file
Binary file not shown.
BIN
res/tree_sample.png
Normal file
BIN
res/tree_sample.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
@ -1,12 +1,14 @@
|
||||
package engineTester;
|
||||
|
||||
|
||||
import models.RawModel;
|
||||
import models.TexturedModel;
|
||||
import renderEngine.DisplayManager;
|
||||
import renderEngine.DisplayManagerDraw;
|
||||
import renderEngine.Loader;
|
||||
import renderEngine.RawModel;
|
||||
import renderEngine.Renderer;
|
||||
import shaders.StaticShader;
|
||||
import textures.ModelTexture;
|
||||
|
||||
/**
|
||||
* This class contains the main method and is used to test the engine.
|
||||
@ -30,27 +32,35 @@ public class MainGameLoop {
|
||||
Renderer renderer = new Renderer();
|
||||
manager.init();
|
||||
StaticShader shader = new StaticShader();
|
||||
|
||||
|
||||
float[] vertices = {
|
||||
-0.5f, 0.5f, 0f,//v0
|
||||
-0.5f, -0.5f, 0f,//v1
|
||||
0.5f, -0.5f, 0f,//v2
|
||||
0.5f, 0.5f, 0f,//v3
|
||||
};
|
||||
float[] textureCoords = {
|
||||
0.0f, 0.0f,//v0
|
||||
0.0f, 1.0f,//v1
|
||||
1.0f, 1.0f,//v2
|
||||
1.0f, 0.0f,//v3
|
||||
};
|
||||
|
||||
int[] indices = {
|
||||
0,1,3,//top left triangle (v0, v1, v3)
|
||||
3,1,2//bottom right triangle (v3, v1, v2)
|
||||
};
|
||||
|
||||
RawModel model = loader.loadToVAO(vertices, indices);
|
||||
RawModel model = loader.loadToVAO(vertices, textureCoords, indices);
|
||||
ModelTexture texture = new ModelTexture(loader.loadTexture("tree_sample"));
|
||||
TexturedModel texturedModel = new TexturedModel(model, texture);
|
||||
|
||||
manager.setDrawer(new DisplayManagerDraw() {
|
||||
@Override
|
||||
public void draw() {
|
||||
renderer.prepare();
|
||||
shader.start();
|
||||
renderer.render(model);
|
||||
renderer.render(texturedModel);
|
||||
shader.stop();
|
||||
}
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
package renderEngine;
|
||||
package models;
|
||||
|
||||
/**
|
||||
* Represents a loaded model. It contains the ID of the VAO that contains the
|
31
src/models/TexturedModel.java
Normal file
31
src/models/TexturedModel.java
Normal file
@ -0,0 +1,31 @@
|
||||
package models;
|
||||
|
||||
import textures.ModelTexture;
|
||||
|
||||
public class TexturedModel {
|
||||
|
||||
private RawModel rawModel;
|
||||
private ModelTexture texture;
|
||||
|
||||
public TexturedModel(RawModel model, ModelTexture texture) {
|
||||
this.rawModel = model;
|
||||
this.texture = texture;
|
||||
}
|
||||
|
||||
public RawModel getRawModel() {
|
||||
return rawModel;
|
||||
}
|
||||
|
||||
public void setRawModel(RawModel rawModel) {
|
||||
this.rawModel = rawModel;
|
||||
}
|
||||
|
||||
public ModelTexture getTexture() {
|
||||
return texture;
|
||||
}
|
||||
|
||||
public void setTexture(ModelTexture texture) {
|
||||
this.texture = texture;
|
||||
}
|
||||
|
||||
}
|
@ -17,5 +17,8 @@ open module Tutorial {
|
||||
requires transitive org.lwjgl.stb.natives;
|
||||
requires transitive org.lwjgl.opengl;
|
||||
requires transitive org.lwjgl.opengl.natives;
|
||||
requires org.lwjgl.openvr;
|
||||
requires java.desktop;
|
||||
requires pngdecoder;
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
package renderEngine;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.ArrayList;
|
||||
@ -7,9 +11,15 @@ import java.util.List;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.openvr.Texture;
|
||||
|
||||
import de.matthiasmann.twl.utils.PNGDecoder;
|
||||
import de.matthiasmann.twl.utils.PNGDecoder.Format;
|
||||
import models.RawModel;
|
||||
|
||||
/**
|
||||
* Handles the loading of geometry data into VAOs. It also keeps track of all
|
||||
@ -23,7 +33,20 @@ public class Loader {
|
||||
|
||||
private List<Integer> vaos = new ArrayList<Integer>();
|
||||
private List<Integer> vbos = new ArrayList<Integer>();
|
||||
|
||||
private List<Integer> textures = new ArrayList<Integer>();
|
||||
|
||||
private void exitOnGLError(String errorMessage) {
|
||||
int errorValue = GL11.glGetError();
|
||||
|
||||
if (errorValue != GL11.GL_NO_ERROR) {
|
||||
System.err.println("ERROR - " + errorMessage + ": ???" );
|
||||
// String errorString = GLU.gluErrorString(errorValue);
|
||||
// System.err.println("ERROR - " + errorMessage + ": " + errorString);
|
||||
//
|
||||
// if (Display.isCreated()) Display.destroy();
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates a VAO and stores the position data of the vertices into attribute
|
||||
* 0 of the VAO. The indices are stored in an index buffer and bound to the
|
||||
@ -42,11 +65,75 @@ public class Loader {
|
||||
public RawModel loadToVAO(float[] positions, int[] indices) {
|
||||
int vaoID = createVAO();
|
||||
bindIndicesBuffer(indices);
|
||||
storeDataInAttributeList(0, positions);
|
||||
storeDataInAttributeList(0, 3, positions);
|
||||
unbindVAO();
|
||||
return new RawModel(vaoID, indices.length);
|
||||
}
|
||||
|
||||
public RawModel loadToVAO(float[] positions, float[] textureCoordinates, int[] indices) {
|
||||
int vaoID = createVAO();
|
||||
bindIndicesBuffer(indices);
|
||||
storeDataInAttributeList(0, 3, positions);
|
||||
storeDataInAttributeList(1, 2, textureCoordinates);
|
||||
unbindVAO();
|
||||
return new RawModel(vaoID, indices.length);
|
||||
}
|
||||
|
||||
public int loadTexture(String filename) {
|
||||
int textureId = loadPNGTexture("res/" + filename + ".png", GL13.GL_TEXTURE0);
|
||||
this.textures.add(textureId);
|
||||
return textureId;
|
||||
}
|
||||
|
||||
private int loadPNGTexture(String filename, int textureUnit) {
|
||||
ByteBuffer buf = null;
|
||||
int tWidth = 0;
|
||||
int tHeight = 0;
|
||||
try {
|
||||
// Open the PNG file as an InputStream
|
||||
InputStream in = new FileInputStream(filename);
|
||||
// Link the PNG decoder to this stream
|
||||
PNGDecoder decoder = new PNGDecoder(in);
|
||||
// Get the width and height of the texture
|
||||
tWidth = decoder.getWidth();
|
||||
tHeight = decoder.getHeight();
|
||||
// Decode the PNG file in a ByteBuffer
|
||||
buf = ByteBuffer.allocateDirect(
|
||||
4 * decoder.getWidth() * decoder.getHeight());
|
||||
decoder.decode(buf, decoder.getWidth() * 4, Format.RGBA);
|
||||
buf.flip();
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
// Create a new texture object in memory and bind it
|
||||
int texId = GL11.glGenTextures();
|
||||
GL13.glActiveTexture(textureUnit);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
|
||||
// All RGB bytes are aligned to each other and each component is 1 byte
|
||||
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
// Upload the texture data and generate mip maps (for scaling)
|
||||
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, tWidth, tHeight, 0,
|
||||
GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buf);
|
||||
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
|
||||
|
||||
// Setup the ST coordinate system
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
|
||||
// Setup what to do when the texture has to be scaled
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER,
|
||||
GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,
|
||||
GL11.GL_LINEAR_MIPMAP_LINEAR);
|
||||
|
||||
this.exitOnGLError("loadPNGTexture");
|
||||
|
||||
return texId;
|
||||
}
|
||||
/**
|
||||
* Deletes all the VAOs and VBOs when the game is closed. VAOs and VBOs are
|
||||
* located in video memory.
|
||||
@ -58,6 +145,9 @@ public class Loader {
|
||||
for (int vbo : vbos) {
|
||||
GL15.glDeleteBuffers(vbo);
|
||||
}
|
||||
for (int texture : textures) {
|
||||
GL11.glDeleteTextures(texture);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,46 +170,13 @@ public class Loader {
|
||||
return vaoID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the position data of the vertices into attribute 0 of the VAO. To
|
||||
* do this the positions must first be stored in a VBO. You can simply think
|
||||
* of a VBO as an array of data that is stored in memory on the GPU for easy
|
||||
* access during rendering.
|
||||
*
|
||||
* Just like with the VAO, we create a new VBO using a "gen" method, and
|
||||
* make it the active VBO (so that we do stuff to it) by binding it.
|
||||
*
|
||||
* We then store the positions data in the active VBO by using the
|
||||
* glBufferData method. We also indicate using GL_STATIC_DRAW that this data
|
||||
* won't need to be changed. If we wanted to edit the positions every frame
|
||||
* (perhaps to animate the quad) then we would use GL_DYNAMIC_DRAW instead.
|
||||
*
|
||||
* We the connect the VBO to the VAO using the glVertexAttribPointer()
|
||||
* method. This needs to know the attribute number of the VAO where we want
|
||||
* to put the data, the number of floats used for each vertex (3 floats in
|
||||
* this case, because each vertex has a 3D position, an x, y, and z value),
|
||||
* the type of data (in this case we used floats) and then some other more
|
||||
* complicated stuff for storing the data in more fancy ways. Don't worry
|
||||
* about the last 3 parameters for now, we don't need them here.
|
||||
*
|
||||
* Now that we've finished using the VBO we can unbind it. This isn't
|
||||
* totally necessary, but I think it's good practice to unbind the VBO when
|
||||
* you're done using it.
|
||||
*
|
||||
* @param attributeNumber
|
||||
* - The number of the attribute of the VAO where the data is to
|
||||
* be stored.
|
||||
* @param data
|
||||
* - The geometry data to be stored in the VAO, in this case the
|
||||
* positions of the vertices.
|
||||
*/
|
||||
private void storeDataInAttributeList(int attributeNumber, float[] data) {
|
||||
private void storeDataInAttributeList(int attributeNumber, int coordinateSize, float[] data) {
|
||||
int vboID = GL15.glGenBuffers();
|
||||
vbos.add(vboID);
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
|
||||
FloatBuffer buffer = storeDataInFloatBuffer(data);
|
||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
|
||||
GL20.glVertexAttribPointer(attributeNumber, 3, GL11.GL_FLOAT, false, 0, 0);
|
||||
GL20.glVertexAttribPointer(attributeNumber, coordinateSize, GL11.GL_FLOAT, false, 0, 0);
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,13 @@
|
||||
package renderEngine;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
import models.RawModel;
|
||||
import models.TexturedModel;
|
||||
|
||||
/**
|
||||
* Handles the rendering of a model to the screen.
|
||||
*
|
||||
@ -54,5 +58,17 @@ public class Renderer {
|
||||
GL20.glDisableVertexAttribArray(0);
|
||||
GL30.glBindVertexArray(0);
|
||||
}
|
||||
public void render(TexturedModel texturedModel) {
|
||||
RawModel model = texturedModel.getRawModel();
|
||||
GL30.glBindVertexArray(model.getVaoID());
|
||||
GL20.glEnableVertexAttribArray(0);
|
||||
GL20.glEnableVertexAttribArray(1);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texturedModel.getTexture().getTexturedID());
|
||||
GL11.glDrawElements(GL11.GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
|
||||
GL20.glDisableVertexAttribArray(0);
|
||||
GL20.glDisableVertexAttribArray(1);
|
||||
GL30.glBindVertexArray(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ public class StaticShader extends ShaderProgram {
|
||||
@Override
|
||||
protected void bindAttributes() {
|
||||
super.bindAttribute(0, "position");
|
||||
super.bindAttribute(1, "textureCoords");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
#version 400 core
|
||||
|
||||
in vec3 colour;
|
||||
in vec2 pass_textureCoords;
|
||||
|
||||
out vec4 out_Color;
|
||||
|
||||
uniform sampler2D textureSampler;
|
||||
|
||||
void main(void) {
|
||||
out_Color = vec4(colour, 1.0);
|
||||
out_Color = texture(textureSampler,pass_textureCoords);
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
#version 400 core
|
||||
|
||||
in vec3 position;
|
||||
in vec2 textureCoords;
|
||||
|
||||
out vec3 colour;
|
||||
out vec2 pass_textureCoords;
|
||||
|
||||
void main(void) {
|
||||
|
||||
gl_Position = vec4(position, 1.0);
|
||||
colour = vec3(position.x+0.5, 1.0, position.y+0.5);
|
||||
pass_textureCoords = textureCoords;
|
||||
}
|
||||
|
||||
|
15
src/textures/ModelTexture.java
Normal file
15
src/textures/ModelTexture.java
Normal file
@ -0,0 +1,15 @@
|
||||
package textures;
|
||||
|
||||
public class ModelTexture {
|
||||
|
||||
private int textureID;
|
||||
|
||||
public ModelTexture(int id) {
|
||||
this.textureID = id;
|
||||
}
|
||||
|
||||
public int getTexturedID() {
|
||||
return textureID;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user