[DEV] tutorial 6 'texturing' implementation
This commit is contained in:
parent
7c1f3508c4
commit
e5467419ec
@ -805,5 +805,10 @@
|
|||||||
<attribute name="module" value="true"/>
|
<attribute name="module" value="true"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
|
<classpathentry kind="lib" path="lib/pngdecoder.jar">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="module" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</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;
|
package engineTester;
|
||||||
|
|
||||||
|
|
||||||
|
import models.RawModel;
|
||||||
|
import models.TexturedModel;
|
||||||
import renderEngine.DisplayManager;
|
import renderEngine.DisplayManager;
|
||||||
import renderEngine.DisplayManagerDraw;
|
import renderEngine.DisplayManagerDraw;
|
||||||
import renderEngine.Loader;
|
import renderEngine.Loader;
|
||||||
import renderEngine.RawModel;
|
|
||||||
import renderEngine.Renderer;
|
import renderEngine.Renderer;
|
||||||
import shaders.StaticShader;
|
import shaders.StaticShader;
|
||||||
|
import textures.ModelTexture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class contains the main method and is used to test the engine.
|
* This class contains the main method and is used to test the engine.
|
||||||
@ -37,20 +39,28 @@ public class MainGameLoop {
|
|||||||
0.5f, -0.5f, 0f,//v2
|
0.5f, -0.5f, 0f,//v2
|
||||||
0.5f, 0.5f, 0f,//v3
|
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 = {
|
int[] indices = {
|
||||||
0,1,3,//top left triangle (v0, v1, v3)
|
0,1,3,//top left triangle (v0, v1, v3)
|
||||||
3,1,2//bottom right triangle (v3, v1, v2)
|
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() {
|
manager.setDrawer(new DisplayManagerDraw() {
|
||||||
@Override
|
@Override
|
||||||
public void draw() {
|
public void draw() {
|
||||||
renderer.prepare();
|
renderer.prepare();
|
||||||
shader.start();
|
shader.start();
|
||||||
renderer.render(model);
|
renderer.render(texturedModel);
|
||||||
shader.stop();
|
shader.stop();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package renderEngine;
|
package models;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a loaded model. It contains the ID of the VAO that contains the
|
* 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.stb.natives;
|
||||||
requires transitive org.lwjgl.opengl;
|
requires transitive org.lwjgl.opengl;
|
||||||
requires transitive org.lwjgl.opengl.natives;
|
requires transitive org.lwjgl.opengl.natives;
|
||||||
|
requires org.lwjgl.openvr;
|
||||||
|
requires java.desktop;
|
||||||
|
requires pngdecoder;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package renderEngine;
|
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.FloatBuffer;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -7,9 +11,15 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.lwjgl.BufferUtils;
|
import org.lwjgl.BufferUtils;
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL13;
|
||||||
import org.lwjgl.opengl.GL15;
|
import org.lwjgl.opengl.GL15;
|
||||||
import org.lwjgl.opengl.GL20;
|
import org.lwjgl.opengl.GL20;
|
||||||
import org.lwjgl.opengl.GL30;
|
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
|
* 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> vaos = new ArrayList<Integer>();
|
||||||
private List<Integer> vbos = 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
|
* 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
|
* 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) {
|
public RawModel loadToVAO(float[] positions, int[] indices) {
|
||||||
int vaoID = createVAO();
|
int vaoID = createVAO();
|
||||||
bindIndicesBuffer(indices);
|
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();
|
unbindVAO();
|
||||||
return new RawModel(vaoID, indices.length);
|
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
|
* Deletes all the VAOs and VBOs when the game is closed. VAOs and VBOs are
|
||||||
* located in video memory.
|
* located in video memory.
|
||||||
@ -58,6 +145,9 @@ public class Loader {
|
|||||||
for (int vbo : vbos) {
|
for (int vbo : vbos) {
|
||||||
GL15.glDeleteBuffers(vbo);
|
GL15.glDeleteBuffers(vbo);
|
||||||
}
|
}
|
||||||
|
for (int texture : textures) {
|
||||||
|
GL11.glDeleteTextures(texture);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,46 +170,13 @@ public class Loader {
|
|||||||
return vaoID;
|
return vaoID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void storeDataInAttributeList(int attributeNumber, int coordinateSize, float[] data) {
|
||||||
* 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) {
|
|
||||||
int vboID = GL15.glGenBuffers();
|
int vboID = GL15.glGenBuffers();
|
||||||
vbos.add(vboID);
|
vbos.add(vboID);
|
||||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
|
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
|
||||||
FloatBuffer buffer = storeDataInFloatBuffer(data);
|
FloatBuffer buffer = storeDataInFloatBuffer(data);
|
||||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
|
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);
|
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package renderEngine;
|
package renderEngine;
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL13;
|
||||||
import org.lwjgl.opengl.GL20;
|
import org.lwjgl.opengl.GL20;
|
||||||
import org.lwjgl.opengl.GL30;
|
import org.lwjgl.opengl.GL30;
|
||||||
|
|
||||||
|
import models.RawModel;
|
||||||
|
import models.TexturedModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the rendering of a model to the screen.
|
* Handles the rendering of a model to the screen.
|
||||||
*
|
*
|
||||||
@ -54,5 +58,17 @@ public class Renderer {
|
|||||||
GL20.glDisableVertexAttribArray(0);
|
GL20.glDisableVertexAttribArray(0);
|
||||||
GL30.glBindVertexArray(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
|
@Override
|
||||||
protected void bindAttributes() {
|
protected void bindAttributes() {
|
||||||
super.bindAttribute(0, "position");
|
super.bindAttribute(0, "position");
|
||||||
|
super.bindAttribute(1, "textureCoords");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#version 400 core
|
#version 400 core
|
||||||
|
|
||||||
in vec3 colour;
|
in vec2 pass_textureCoords;
|
||||||
|
|
||||||
out vec4 out_Color;
|
out vec4 out_Color;
|
||||||
|
|
||||||
|
uniform sampler2D textureSampler;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
out_Color = vec4(colour, 1.0);
|
out_Color = texture(textureSampler,pass_textureCoords);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
#version 400 core
|
#version 400 core
|
||||||
|
|
||||||
in vec3 position;
|
in vec3 position;
|
||||||
|
in vec2 textureCoords;
|
||||||
|
|
||||||
out vec3 colour;
|
out vec2 pass_textureCoords;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
|
|
||||||
gl_Position = vec4(position, 1.0);
|
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…
x
Reference in New Issue
Block a user