如何在 LWJGL 中正确地将纹理映射到六边形?
How do I correctly map a texture to a hexagon in LWJGL?
我有一个脚本可以渲染六边形瓷砖的二维六边形网格。网格加载正常,但我的纹理缺少大量颜色。我的代码有什么问题?我是否错误地映射了坐标?
这是我正在加载的纹理图像:
这是纹理在我的游戏中的显示方式:
这是我的代码:
public class LWJGLHelloWorld {
public static int SCREEN_WIDTH;
public static int SCREEN_HEIGHT;
public static int WINDOW_WIDTH;
public static int WINDOW_HEIGHT;
public double WIDTH;
public double HEIGHT;
public ArrayList<Hexagon> hexagons = new ArrayList<Hexagon>();
public ArrayList<String> resources = new ArrayList<String>();
public Texture brick;
public Texture stone;
public Texture lumber;
public Texture wool;
public Texture wheat;
public Texture wasteland;
public int textureID;
private float[][] textureCoords = {
{0.5f, 0.5f},
{0.5f, 0.0f},
{0.0f, 0.25f},
{0.0f, 0.75f},
{0.5f, 0.0f},
{1.0f, 0.75f},
{1.0f, 0.25f}
};
private static enum State {
INTRO, MAIN_MENU, GAME;
}
private State state = State.INTRO;
public LWJGLHelloWorld(){
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double SCREEN_WIDTH = screenSize.getWidth();
double SCREEN_HEIGHT = screenSize.getHeight();
double WIDTH = SCREEN_WIDTH * .85;
double HEIGHT = SCREEN_HEIGHT * .85;
try {
Display.setDisplayMode(new DisplayMode((int)WIDTH, (int)HEIGHT));
Display.setTitle("Hello, LWJGL!");;
Display.create();
} catch (LWJGLException e){
e.printStackTrace();
}
resetResources();
brick = loadTexture("brick");
stone = loadTexture("stone");
lumber = loadTexture("lumber");
//Texture wheat = loadTexture("wheat");
wool = loadTexture("wool");
wasteland = loadTexture("wasteland");
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, WIDTH, HEIGHT, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
int originX = (int)(Display.getDisplayMode().getWidth() / 2);
int originY = (int)(Display.getDisplayMode().getHeight() / 2);
int radius = (int)(HEIGHT * .1);
int padding = (int)(HEIGHT * .005);
findHexCoords(originX, originY, 5, radius, padding);
while(!Display.isCloseRequested()){
checkInput();
glClear(GL_COLOR_BUFFER_BIT);
for(int h = 0; h < hexagons.size(); h++){
String rsrc = resources.get(h);
switch(rsrc){
case "brick":
brick.bind();
break;
case "stone":
stone.bind();
break;
case "lumber":
lumber.bind();
break;
case "wheat":
//wheat.bind();
break;
case "wool":
wool.bind();
break;
case "wasteland":
wasteland.bind();
break;
}
glBegin(GL_POLYGON);
Hexagon hex = hexagons.get(h);
for(int p = 0; p < hex.points.length; p++){
Point point = hex.points[p];
glVertex2f(point.x, point.y);
glTexCoord2f(textureCoords[p][0], textureCoords[p][0]);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
}
glEnd();
}
Display.update();
Display.sync(60);
}
Display.destroy();
}
private void bindTexture(String rsrc){
}
private void findHexCoords(int x, int y, int size, int radius, int padding) {
Point origin = new Point(x, y);
double ang30 = Math.toRadians(30);
double xOff = Math.cos(ang30) * (radius + padding);
double yOff = Math.sin(ang30) * (radius + padding);
int half = size / 2;
int i = 0;
for (int row = 0; row < size; row++) {
int cols = size - Math.abs(row - half);
for (int col = 0; col < cols; col++) {
int xLbl = row < half ? col - row : col - half;
int yLbl = row - half;
int centerX = (int) (origin.x + xOff * (col * 2 + 1 - cols));
int centerY = (int) (origin.y + yOff * (row - half) * 3);
Hexagon hex = new Hexagon(centerX, centerY, radius);
System.out.println(centerX+","+centerY);
hexagons.add(hex);
i++;
}
}
}
public void checkInput(){
switch(state){
case INTRO:
if(Keyboard.isKeyDown(Keyboard.KEY_S)){
state = State.MAIN_MENU;
}
if(Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)){
Display.destroy();
System.exit(0);;
}
break;
case GAME:
if(Keyboard.isKeyDown(Keyboard.KEY_BACK)){
state = State.MAIN_MENU;
}
break;
case MAIN_MENU:
if(Keyboard.isKeyDown(Keyboard.KEY_RETURN)){
state = State.GAME;
}
if(Keyboard.isKeyDown(Keyboard.KEY_SPACE)){
state = State.INTRO;
}
break;
}
}
private Texture loadTexture(String key){
try {
return TextureLoader.getTexture("PNG", new FileInputStream(new File("img/" + key + ".png")));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
new LWJGLHelloWorld();
}
public void resetResources(){
resources.clear();
resources.add("Brick");
resources.add("Brick");
resources.add("Brick");
resources.add("Wool");
resources.add("Wool");
resources.add("Wool");
resources.add("Wool");
resources.add("Lumber");
resources.add("Lumber");
resources.add("Lumber");
resources.add("Lumber");
resources.add("Stone");
resources.add("Stone");
resources.add("Stone");
resources.add("Wheat");
resources.add("Wheat");
resources.add("Wheat");
resources.add("Wheat");
long seed = System.nanoTime();
Collections.shuffle(resources, new Random(seed));
int randomIndex = ThreadLocalRandom.current().nextInt(0, 19);
resources.add(randomIndex, "Wasteland");
for(int r = 0; r < resources.size(); r++){
System.out.println(resources.get(r));
}
}
}
更新
我认为发生这种情况是因为我的纹理坐标不正确,因为每当我更改它们时,纹理中的黑色区域都会发生变化。
你的纹理坐标确实是错误的。由于您绘制的是一个整体的多边形,因此没有任何纹理坐标为 [0.5, 0.5] 的顶点,它是纹理的中心。
尝试使用下面的图像来正确确定您的纹理坐标。 :)
写下每个顶点的纹理坐标,并按照绘制顶点的顺序排列它们。
编辑:
公平地说,您最好将这些图块绘制为 rectangles/quads 并让它们稍微重叠一点。你的纹理坐标将是 {[0, 0], [0, 1], [1, 1], [1, 0]} 假设你从左下角开始顺时针绘制。见下图。
我有一个脚本可以渲染六边形瓷砖的二维六边形网格。网格加载正常,但我的纹理缺少大量颜色。我的代码有什么问题?我是否错误地映射了坐标?
这是我正在加载的纹理图像:
这是纹理在我的游戏中的显示方式:
这是我的代码:
public class LWJGLHelloWorld {
public static int SCREEN_WIDTH;
public static int SCREEN_HEIGHT;
public static int WINDOW_WIDTH;
public static int WINDOW_HEIGHT;
public double WIDTH;
public double HEIGHT;
public ArrayList<Hexagon> hexagons = new ArrayList<Hexagon>();
public ArrayList<String> resources = new ArrayList<String>();
public Texture brick;
public Texture stone;
public Texture lumber;
public Texture wool;
public Texture wheat;
public Texture wasteland;
public int textureID;
private float[][] textureCoords = {
{0.5f, 0.5f},
{0.5f, 0.0f},
{0.0f, 0.25f},
{0.0f, 0.75f},
{0.5f, 0.0f},
{1.0f, 0.75f},
{1.0f, 0.25f}
};
private static enum State {
INTRO, MAIN_MENU, GAME;
}
private State state = State.INTRO;
public LWJGLHelloWorld(){
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double SCREEN_WIDTH = screenSize.getWidth();
double SCREEN_HEIGHT = screenSize.getHeight();
double WIDTH = SCREEN_WIDTH * .85;
double HEIGHT = SCREEN_HEIGHT * .85;
try {
Display.setDisplayMode(new DisplayMode((int)WIDTH, (int)HEIGHT));
Display.setTitle("Hello, LWJGL!");;
Display.create();
} catch (LWJGLException e){
e.printStackTrace();
}
resetResources();
brick = loadTexture("brick");
stone = loadTexture("stone");
lumber = loadTexture("lumber");
//Texture wheat = loadTexture("wheat");
wool = loadTexture("wool");
wasteland = loadTexture("wasteland");
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, WIDTH, HEIGHT, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
int originX = (int)(Display.getDisplayMode().getWidth() / 2);
int originY = (int)(Display.getDisplayMode().getHeight() / 2);
int radius = (int)(HEIGHT * .1);
int padding = (int)(HEIGHT * .005);
findHexCoords(originX, originY, 5, radius, padding);
while(!Display.isCloseRequested()){
checkInput();
glClear(GL_COLOR_BUFFER_BIT);
for(int h = 0; h < hexagons.size(); h++){
String rsrc = resources.get(h);
switch(rsrc){
case "brick":
brick.bind();
break;
case "stone":
stone.bind();
break;
case "lumber":
lumber.bind();
break;
case "wheat":
//wheat.bind();
break;
case "wool":
wool.bind();
break;
case "wasteland":
wasteland.bind();
break;
}
glBegin(GL_POLYGON);
Hexagon hex = hexagons.get(h);
for(int p = 0; p < hex.points.length; p++){
Point point = hex.points[p];
glVertex2f(point.x, point.y);
glTexCoord2f(textureCoords[p][0], textureCoords[p][0]);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
}
glEnd();
}
Display.update();
Display.sync(60);
}
Display.destroy();
}
private void bindTexture(String rsrc){
}
private void findHexCoords(int x, int y, int size, int radius, int padding) {
Point origin = new Point(x, y);
double ang30 = Math.toRadians(30);
double xOff = Math.cos(ang30) * (radius + padding);
double yOff = Math.sin(ang30) * (radius + padding);
int half = size / 2;
int i = 0;
for (int row = 0; row < size; row++) {
int cols = size - Math.abs(row - half);
for (int col = 0; col < cols; col++) {
int xLbl = row < half ? col - row : col - half;
int yLbl = row - half;
int centerX = (int) (origin.x + xOff * (col * 2 + 1 - cols));
int centerY = (int) (origin.y + yOff * (row - half) * 3);
Hexagon hex = new Hexagon(centerX, centerY, radius);
System.out.println(centerX+","+centerY);
hexagons.add(hex);
i++;
}
}
}
public void checkInput(){
switch(state){
case INTRO:
if(Keyboard.isKeyDown(Keyboard.KEY_S)){
state = State.MAIN_MENU;
}
if(Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)){
Display.destroy();
System.exit(0);;
}
break;
case GAME:
if(Keyboard.isKeyDown(Keyboard.KEY_BACK)){
state = State.MAIN_MENU;
}
break;
case MAIN_MENU:
if(Keyboard.isKeyDown(Keyboard.KEY_RETURN)){
state = State.GAME;
}
if(Keyboard.isKeyDown(Keyboard.KEY_SPACE)){
state = State.INTRO;
}
break;
}
}
private Texture loadTexture(String key){
try {
return TextureLoader.getTexture("PNG", new FileInputStream(new File("img/" + key + ".png")));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
new LWJGLHelloWorld();
}
public void resetResources(){
resources.clear();
resources.add("Brick");
resources.add("Brick");
resources.add("Brick");
resources.add("Wool");
resources.add("Wool");
resources.add("Wool");
resources.add("Wool");
resources.add("Lumber");
resources.add("Lumber");
resources.add("Lumber");
resources.add("Lumber");
resources.add("Stone");
resources.add("Stone");
resources.add("Stone");
resources.add("Wheat");
resources.add("Wheat");
resources.add("Wheat");
resources.add("Wheat");
long seed = System.nanoTime();
Collections.shuffle(resources, new Random(seed));
int randomIndex = ThreadLocalRandom.current().nextInt(0, 19);
resources.add(randomIndex, "Wasteland");
for(int r = 0; r < resources.size(); r++){
System.out.println(resources.get(r));
}
}
}
更新
我认为发生这种情况是因为我的纹理坐标不正确,因为每当我更改它们时,纹理中的黑色区域都会发生变化。
你的纹理坐标确实是错误的。由于您绘制的是一个整体的多边形,因此没有任何纹理坐标为 [0.5, 0.5] 的顶点,它是纹理的中心。
尝试使用下面的图像来正确确定您的纹理坐标。 :)
写下每个顶点的纹理坐标,并按照绘制顶点的顺序排列它们。
编辑:
公平地说,您最好将这些图块绘制为 rectangles/quads 并让它们稍微重叠一点。你的纹理坐标将是 {[0, 0], [0, 1], [1, 1], [1, 0]} 假设你从左下角开始顺时针绘制。见下图。