Async mesh reloading for planets
This commit is contained in:
@@ -32,7 +32,7 @@ public class LoadRenderer implements Disposable{
|
||||
private float testprogress = 0f;
|
||||
private StringBuilder assetText = new StringBuilder();
|
||||
private Bar[] bars;
|
||||
private Mesh mesh = MeshBuilder.buildLineHex(colorRed, 2);
|
||||
private Mesh mesh = MeshBuilder.buildPlanetGrid(PlanetGrid.create(2), colorRed, 1f);
|
||||
private Camera3D cam = new Camera3D();
|
||||
private int lastLength = -1;
|
||||
private FxProcessor fx;
|
||||
|
||||
@@ -21,7 +21,7 @@ public class HexMesh extends PlanetMesh{
|
||||
@Override
|
||||
public void preRender(PlanetParams params){
|
||||
Shaders.planet.planet = planet;
|
||||
Shaders.planet.emissive = planet.generator != null && planet.generator.hasEmissive();
|
||||
Shaders.planet.emissive = planet.generator != null;
|
||||
Shaders.planet.lightDir.set(planet.solarSystem.position).sub(planet.position).rotate(Vec3.Y, planet.getRotation()).nor();
|
||||
Shaders.planet.ambientColor.set(planet.solarSystem.lightColor);
|
||||
}
|
||||
|
||||
@@ -6,15 +6,16 @@ import arc.math.geom.*;
|
||||
/** Defines color and height for a planet mesh. */
|
||||
public interface HexMesher{
|
||||
|
||||
float getHeight(Vec3 position);
|
||||
Color getColor(Vec3 position);
|
||||
|
||||
default Color getEmissiveColor(Vec3 position){
|
||||
return Color.clear;
|
||||
default float getHeight(Vec3 position){
|
||||
return 0f;
|
||||
}
|
||||
|
||||
default boolean hasEmissive(){
|
||||
return false;
|
||||
default void getColor(Vec3 position, Color out){
|
||||
|
||||
}
|
||||
|
||||
default void getEmissiveColor(Vec3 position, Color out){
|
||||
|
||||
}
|
||||
|
||||
default boolean skip(Vec3 position){
|
||||
|
||||
@@ -21,8 +21,8 @@ public class HexSkyMesh extends PlanetMesh{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor(Vec3 position){
|
||||
return color;
|
||||
public void getColor(Vec3 position, Color out){
|
||||
out.set(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,65 +8,39 @@ import mindustry.graphics.g3d.PlanetGrid.*;
|
||||
import mindustry.maps.generators.*;
|
||||
|
||||
public class MeshBuilder{
|
||||
private static final Vec3 v1 = new Vec3(), v2 = new Vec3(), v3 = new Vec3(), v4 = new Vec3();
|
||||
private static final boolean gl30 = Core.gl30 != null;
|
||||
private static final float[] floats = new float[3 + (gl30 ? 1 : 3) + 1], emissiveFloats = new float[floats.length + 1];
|
||||
private static final short[] shorts = new short[3];
|
||||
private static float[] tmpHeights = new float[14580]; //highest amount of corners in vanilla
|
||||
private static Mesh mesh;
|
||||
|
||||
public static Mesh buildIcosphere(int divisions, float radius, Color color){
|
||||
begin(20 * (2 << (2 * divisions - 1)) * 3, 0, false);
|
||||
|
||||
float col = color.toFloatBits();
|
||||
private static volatile float[] tmpHeights = new float[14580]; //highest amount of corners in vanilla
|
||||
|
||||
/** Note that the resulting icosphere does not have normals or a color. */
|
||||
public static Mesh buildIcosphere(int divisions, float radius){
|
||||
MeshResult result = Icosphere.create(divisions);
|
||||
for(int i = 0; i < result.indices.size; i+= 3){
|
||||
v1.set(result.vertices.items, result.indices.items[i] * 3).setLength(radius);
|
||||
v2.set(result.vertices.items, result.indices.items[i + 1] * 3).setLength(radius);
|
||||
v3.set(result.vertices.items, result.indices.items[i + 2] * 3).setLength(radius);
|
||||
|
||||
verts(v1, v3, v2, normal(v1, v2, v3).scl(-1f), col, 0f);
|
||||
Mesh mesh = begin(result.vertices.size / 3, result.indices.size, false, false);
|
||||
|
||||
if(result.vertices.size >= 65535) throw new RuntimeException("Due to index size limits, only meshes with a maximum of 65535 vertices are supported. If you want more than that, make your own non-indexed mesh builder.");
|
||||
|
||||
float[] items = result.vertices.items;
|
||||
for(int i = 0; i < result.vertices.size; i ++){
|
||||
items[i] *= radius;
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
mesh.getVerticesBuffer().put(items, 0, result.vertices.size);
|
||||
|
||||
public static Mesh buildIcosphere(int divisions, float radius){
|
||||
return buildIcosphere(divisions, radius, Color.white);
|
||||
short[] indices = new short[result.indices.size];
|
||||
for(int i = 0; i < result.indices.size; i++){
|
||||
indices[i] = (short)result.indices.items[i];
|
||||
}
|
||||
|
||||
mesh.getIndicesBuffer().put(indices);
|
||||
|
||||
return end(mesh);
|
||||
}
|
||||
|
||||
public static Mesh buildPlanetGrid(PlanetGrid grid, Color color, float scale){
|
||||
int total = 0;
|
||||
for(Ptile tile : grid.tiles){
|
||||
total += tile.corners.length * 2;
|
||||
}
|
||||
|
||||
float col = color.toFloatBits();
|
||||
|
||||
begin(total, 0, false);
|
||||
for(Ptile tile : grid.tiles){
|
||||
Corner[] c = tile.corners;
|
||||
for(int i = 0; i < c.length; i++){
|
||||
Vec3 a = v1.set(c[i].v).scl(scale);
|
||||
Vec3 b = v2.set(c[(i + 1) % c.length].v).scl(scale);
|
||||
|
||||
vert(a, Vec3.Z, col, 0f);
|
||||
vert(b, Vec3.Z, col, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
public static Mesh buildLineHex(Color color, int divisions){
|
||||
PlanetGrid grid = PlanetGrid.create(divisions);
|
||||
|
||||
begin(grid.tiles.length * 12, 0, false);
|
||||
|
||||
Vec3 nor = v4.set(1f, 1f, 1f);
|
||||
Mesh mesh = begin(grid.tiles.length * 12, 0, false, false);
|
||||
|
||||
float col = color.toFloatBits();
|
||||
float[] floats = new float[8];
|
||||
|
||||
for(Ptile tile : grid.tiles){
|
||||
Corner[] c = tile.corners;
|
||||
@@ -75,12 +49,21 @@ public class MeshBuilder{
|
||||
Vec3 v1 = c[i].v;
|
||||
Vec3 v2 = c[(i + 1) % c.length].v;
|
||||
|
||||
vert(v1, nor, col, 0f);
|
||||
vert(v2, nor, col, 0f);
|
||||
floats[0] = v1.x * scale;
|
||||
floats[1] = v1.y * scale;
|
||||
floats[2] = v1.z * scale;
|
||||
floats[3] = col;
|
||||
|
||||
floats[4] = v2.x * scale;
|
||||
floats[5] = v2.y * scale;
|
||||
floats[6] = v2.z * scale;
|
||||
floats[7] = col;
|
||||
|
||||
mesh.getVerticesBuffer().put(floats);
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
return end(mesh);
|
||||
}
|
||||
|
||||
public static Mesh buildHex(Color color, int divisions, float radius){
|
||||
@@ -91,29 +74,24 @@ public class MeshBuilder{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor(Vec3 position){
|
||||
return color;
|
||||
public void getColor(Vec3 position, Color out){
|
||||
out.set(color);
|
||||
}
|
||||
}, divisions, radius, 0);
|
||||
}
|
||||
|
||||
//TODO: make this thread safe
|
||||
public static Mesh buildHex(HexMesher mesher, int divisions, float radius, float intensity){
|
||||
//TODO: in principle this should not be synchronized, but I would rather not realloc tmpHeights every time, and it is unlikely that two planets will be reloading at the same time
|
||||
public static synchronized Mesh buildHex(HexMesher mesher, int divisions, float radius, float intensity){
|
||||
PlanetGrid grid = PlanetGrid.create(divisions);
|
||||
|
||||
//TODO: this is NOT thread safe, but in practice, it should never cause a problem
|
||||
if(mesher instanceof PlanetGenerator generator){
|
||||
generator.seed = generator.baseSeed;
|
||||
}
|
||||
|
||||
boolean emit = mesher.hasEmissive();
|
||||
if(grid.tiles.length * 6 >= 65535) throw new RuntimeException("Due to index size limits, only meshes with a maximum of 65535 vertices are supported. If you want more than that, make your own non-indexed mesh builder.");
|
||||
|
||||
boolean indexed = grid.tiles.length * 6 < 65535;
|
||||
|
||||
if(indexed){
|
||||
begin(grid.tiles.length * 6, grid.tiles.length * 4 * 3, emit);
|
||||
}else{
|
||||
begin(grid.tiles.length * 12, 0, emit);
|
||||
}
|
||||
Mesh mesh = begin(grid.tiles.length * 6, grid.tiles.length * 4 * 3, true, true);
|
||||
|
||||
float[] heights;
|
||||
|
||||
@@ -130,6 +108,12 @@ public class MeshBuilder{
|
||||
|
||||
int position = 0;
|
||||
|
||||
short[] shorts = new short[12];
|
||||
float[] floats = new float[3 + (gl30 ? 1 : 3) + 1 + 1];
|
||||
Vec3 nor = new Vec3();
|
||||
|
||||
Color tmpCol = new Color();
|
||||
|
||||
for(Ptile tile : grid.tiles){
|
||||
if(mesher.skip(tile.v)){
|
||||
continue;
|
||||
@@ -137,60 +121,77 @@ public class MeshBuilder{
|
||||
|
||||
Corner[] c = tile.corners;
|
||||
|
||||
for(Corner corner : c){
|
||||
corner.v.scl((1f + heights[corner.id] * intensity) * radius);
|
||||
float
|
||||
h1 = (1f + heights[c[0].id] * intensity) * radius,
|
||||
h2 = (1f + heights[c[2].id] * intensity) * radius,
|
||||
h3 = (1f + heights[c[4].id] * intensity) * radius;
|
||||
|
||||
Vec3
|
||||
v1 = c[0].v,
|
||||
v2 = c[2].v,
|
||||
v3 = c[4].v;
|
||||
|
||||
normal(
|
||||
v1.x * h1, v1.y * h1, v1.z * h1,
|
||||
v2.x * h2, v2.y * h2, v2.z * h2,
|
||||
v3.x * h3, v3.y * h3, v3.z * h3,
|
||||
nor);
|
||||
|
||||
tmpCol.set(1f, 1f, 1f, 1f);
|
||||
mesher.getColor(tile.v, tmpCol);
|
||||
float color = tmpCol.toFloatBits();
|
||||
tmpCol.set(0f, 0f, 0f, 0f);
|
||||
mesher.getEmissiveColor(tile.v, tmpCol);
|
||||
float emissive = tmpCol.toFloatBits();
|
||||
|
||||
for(var corner : c){
|
||||
float height = (1f + heights[corner.id] * intensity) * radius;
|
||||
|
||||
vert(mesh, floats, corner.v.x * height, corner.v.y * height, corner.v.z * height, nor, color, emissive);
|
||||
}
|
||||
|
||||
Vec3 nor = normal(c[0].v, c[2].v, c[4].v);
|
||||
float color = mesher.getColor(tile.v).toFloatBits();
|
||||
float emissive = emit ? mesher.getEmissiveColor(tile.v).toFloatBits() : 0f;
|
||||
shorts[0] = (short)(position);
|
||||
shorts[1] = (short)(position + 1);
|
||||
shorts[2] = (short)(position + 2);
|
||||
|
||||
if(indexed){
|
||||
for(var corner : c){
|
||||
vert(corner.v, nor, color, emissive);
|
||||
}
|
||||
shorts[3] = (short)(position);
|
||||
shorts[4] = (short)(position + 2);
|
||||
shorts[5] = (short)(position + 3);
|
||||
|
||||
indices(position, position + 1, position + 2);
|
||||
indices(position, position + 2, position + 3);
|
||||
indices(position, position + 3, position + 4);
|
||||
if(c.length > 5){
|
||||
indices(position, position + 4, position + 5);
|
||||
}
|
||||
shorts[6] = (short)(position);
|
||||
shorts[7] = (short)(position + 3);
|
||||
shorts[8] = (short)(position + 4);
|
||||
|
||||
position += c.length;
|
||||
|
||||
}else{
|
||||
verts(c[0].v, c[1].v, c[2].v, nor, color, emissive);
|
||||
verts(c[0].v, c[2].v, c[3].v, nor, color, emissive);
|
||||
verts(c[0].v, c[3].v, c[4].v, nor, color, emissive);
|
||||
|
||||
if(c.length > 5){
|
||||
verts(c[0].v, c[4].v, c[5].v, nor, color, emissive);
|
||||
}
|
||||
if(c.length > 5){
|
||||
shorts[9] = (short)(position);
|
||||
shorts[10] = (short)(position + 4);
|
||||
shorts[11] = (short)(position + 5);
|
||||
}
|
||||
|
||||
//restore mutated corners
|
||||
for(Corner corner : c){
|
||||
corner.v.nor();
|
||||
}
|
||||
mesh.getIndicesBuffer().put(shorts, 0, c.length > 5 ? 12 : 9);
|
||||
position += c.length;
|
||||
}
|
||||
|
||||
return end();
|
||||
return end(mesh);
|
||||
}
|
||||
|
||||
private static void begin(int vertices, int indices, boolean emissive){
|
||||
private static Mesh begin(int vertices, int indices, boolean normal, boolean emissive){
|
||||
Seq<VertexAttribute> attributes = Seq.with(
|
||||
VertexAttribute.position3,
|
||||
//only GL30 supports GL_INT_2_10_10_10_REV
|
||||
gl30 ? VertexAttribute.packedNormal : VertexAttribute.normal,
|
||||
VertexAttribute.color
|
||||
VertexAttribute.position3
|
||||
);
|
||||
|
||||
if(normal){
|
||||
//only GL30 supports GL_INT_2_10_10_10_REV
|
||||
attributes.add(gl30 ? VertexAttribute.packedNormal : VertexAttribute.normal);
|
||||
}
|
||||
|
||||
attributes.add(VertexAttribute.color);
|
||||
|
||||
if(emissive){
|
||||
attributes.add(new VertexAttribute(4, GL20.GL_UNSIGNED_BYTE, true, "a_emissive"));
|
||||
}
|
||||
|
||||
mesh = new Mesh(true, vertices, indices, attributes.toArray(VertexAttribute.class));
|
||||
Mesh mesh = new Mesh(true, vertices, indices, attributes.toArray(VertexAttribute.class));
|
||||
|
||||
mesh.getVerticesBuffer().limit(mesh.getVerticesBuffer().capacity());
|
||||
mesh.getVerticesBuffer().position(0);
|
||||
@@ -199,56 +200,70 @@ public class MeshBuilder{
|
||||
mesh.getIndicesBuffer().limit(mesh.getIndicesBuffer().capacity());
|
||||
mesh.getIndicesBuffer().position(0);
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
private static Mesh end(){
|
||||
Mesh last = mesh;
|
||||
last.getVerticesBuffer().limit(last.getVerticesBuffer().position());
|
||||
if(last.getNumIndices() > 0){
|
||||
last.getIndicesBuffer().limit(last.getIndicesBuffer().position());
|
||||
private static Mesh end(Mesh mesh){
|
||||
mesh.getVerticesBuffer().limit(mesh.getVerticesBuffer().position());
|
||||
if(mesh.getNumIndices() > 0){
|
||||
mesh.getIndicesBuffer().limit(mesh.getIndicesBuffer().position());
|
||||
}
|
||||
mesh = null;
|
||||
|
||||
return last;
|
||||
return mesh;
|
||||
}
|
||||
|
||||
private static Vec3 normal(Vec3 v1, Vec3 v2, Vec3 v3){
|
||||
return v4.set(v2).sub(v1).crs(v3.x - v1.x, v3.y - v1.y, v3.z - v1.z).nor();
|
||||
private static void normal(Vec3 v1, Vec3 v2, Vec3 v3, Vec3 out){
|
||||
float
|
||||
x = v2.x - v1.x,
|
||||
y = v2.y - v1.y,
|
||||
z = v2.z - v1.z,
|
||||
vx = v3.x - v1.x,
|
||||
vy = v3.y - v1.y,
|
||||
vz = v3.z - v1.z;
|
||||
|
||||
float
|
||||
cx = y * vz - z * vy,
|
||||
cy = z * vx - x * vz,
|
||||
cz = x * vy - y * vx;
|
||||
|
||||
out.set(cx, cy, cz).nor();
|
||||
}
|
||||
|
||||
private static void indices(int a, int b, int c){
|
||||
shorts[0] = (short)a;
|
||||
shorts[1] = (short)b;
|
||||
shorts[2] = (short)c;
|
||||
mesh.getIndicesBuffer().put(shorts);
|
||||
private static void normal(float v1x, float v1y, float v1z, float v2x, float v2y, float v2z, float v3x, float v3y, float v3z, Vec3 out){
|
||||
float
|
||||
x = v2x - v1x,
|
||||
y = v2y - v1y,
|
||||
z = v2z - v1z,
|
||||
vx = v3x - v1x,
|
||||
vy = v3y - v1y,
|
||||
vz = v3z - v1z;
|
||||
|
||||
float
|
||||
cx = y * vz - z * vy,
|
||||
cy = z * vx - x * vz,
|
||||
cz = x * vy - y * vx;
|
||||
|
||||
out.set(cx, cy, cz).nor();
|
||||
}
|
||||
|
||||
private static void verts(Vec3 a, Vec3 b, Vec3 c, Vec3 normal, float color, float emissive){
|
||||
vert(a, normal, color, emissive);
|
||||
vert(b, normal, color, emissive);
|
||||
vert(c, normal, color, emissive);
|
||||
}
|
||||
|
||||
private static void vert(Vec3 a, Vec3 normal, float color, float emissive){
|
||||
boolean emit = mesh.getVertexSize() == emissiveFloats.length*4;
|
||||
float[] floats = emit ? emissiveFloats : MeshBuilder.floats;
|
||||
|
||||
floats[0] = a.x;
|
||||
floats[1] = a.y;
|
||||
floats[2] = a.z;
|
||||
private static void vert(Mesh mesh, float[] floats, float x, float y, float z, Vec3 normal, float color, float emissive){
|
||||
floats[0] = x;
|
||||
floats[1] = y;
|
||||
floats[2] = z;
|
||||
|
||||
if(gl30){
|
||||
floats[3] = packNormals(normal.x, normal.y, normal.z);
|
||||
|
||||
floats[4] = color;
|
||||
if(emit) floats[5] = emissive;
|
||||
floats[5] = emissive;
|
||||
}else{
|
||||
floats[3] = normal.x;
|
||||
floats[4] = normal.x;
|
||||
floats[5] = normal.x;
|
||||
|
||||
floats[6] = color;
|
||||
if(emit) floats[7] = emissive;
|
||||
floats[7] = emissive;
|
||||
}
|
||||
|
||||
mesh.getVerticesBuffer().put(floats);
|
||||
|
||||
@@ -18,8 +18,8 @@ public class NoiseMesh extends HexMesh{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor(Vec3 position){
|
||||
return color;
|
||||
public void getColor(Vec3 position, Color out){
|
||||
out.set(color);
|
||||
}
|
||||
}, divisions, radius, 0.2f);
|
||||
}
|
||||
@@ -35,8 +35,8 @@ public class NoiseMesh extends HexMesh{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor(Vec3 position){
|
||||
return Simplex.noise3d(8 + seed, coct, cper, cscl, 5f + position.x, 5f + position.y, 5f + position.z) > cthresh ? color2 : color1;
|
||||
public void getColor(Vec3 position, Color out){
|
||||
out.set(Simplex.noise3d(8 + seed, coct, cper, cscl, 5f + position.x, 5f + position.y, 5f + position.z) > cthresh ? color2 : color1);
|
||||
}
|
||||
}, divisions, radius, 0.2f);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class PlanetGrid{
|
||||
}
|
||||
}
|
||||
|
||||
public static PlanetGrid create(int size){
|
||||
public static synchronized PlanetGrid create(int size){
|
||||
//cache grids between calls, since only ~5 different grids total are needed
|
||||
if(size < cache.length && cache[size] != null){
|
||||
return cache[size];
|
||||
|
||||
@@ -3,7 +3,6 @@ package mindustry.graphics.g3d;
|
||||
import arc.graphics.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import arc.util.noise.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
@@ -19,9 +18,9 @@ public class SunMesh extends HexMesh{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor(Vec3 position){
|
||||
public void getColor(Vec3 position, Color out){
|
||||
double height = Math.pow(Simplex.noise3d(0, octaves, persistence, scl, position.x, position.y, position.z), pow) * mag;
|
||||
return Tmp.c1.set(colors[Mathf.clamp((int)(height * colors.length), 0, colors.length - 1)]).mul(colorScale);
|
||||
out.set(colors[Mathf.clamp((int)(height * colors.length), 0, colors.length - 1)]).mul(colorScale);
|
||||
}
|
||||
}, divisions, Shaders.unlit);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user