~melchizedek6809/WolkenWelten

b604559f1359ef3dc10017ec47bd1b3eee89e7d0 — Celeste Wouters 1 year, 8 months ago 079afdb feature/instanced-faces
WIP WILL BE REBASED Render block faces using instancing
3 files changed, 72 insertions(+), 72 deletions(-)

M client/src/shader/blockShaderVS.glsl
M client/src/voxel/chunk.c
M client/src/voxel/chunkvertbuf.c
M client/src/shader/blockShaderVS.glsl => client/src/shader/blockShaderVS.glsl +37 -5
@@ 7,13 7,45 @@ in uint packedData;
out vec3 texCoord;
out vec3 lightness;

uniform ivec3 aa[6*4] = ivec3[6*4](
  ivec3(0, 0, 0),
  ivec3(1, 0, 0),
  ivec3(1, 1, 0),
  ivec3(0, 1, 0),

  ivec3(0, 0, 0),
  ivec3(0, 1, 0),
  ivec3(1, 1, 0),
  ivec3(1, 0, 0),

  ivec3(0, 0, 0),
  ivec3(0, 0, 1),
  ivec3(1, 0, 1),
  ivec3(1, 0, 0),

  ivec3(0, 0, 0),
  ivec3(1, 0, 0),
  ivec3(1, 0, 1),
  ivec3(0, 0, 1),

  ivec3(0, 0, 0),
  ivec3(0, 0, 1),
  ivec3(0, 1, 1),
  ivec3(0, 1, 0),

  ivec3(0, 0, 0),
  ivec3(0, 1, 0),
  ivec3(0, 1, 1),
  ivec3(0, 0, 1)
);

void main(){
  uvec4 pos = uvec4(packedData & 0x1Fu, (packedData >> 5) & 0x1Fu, (packedData >> 10) & 0x1Fu, 1);
  uvec2 taxis[3] = uvec2[3](pos.xy, pos.xz, pos.zy);
  uint flag = (packedData >> 24) & 0x7u;
  vec3 tex = vec3(uvec3(taxis[flag >> 1], (packedData >> 16) & 0xFFu));

  ivec3 a = aa[int(flag) * 4 + gl_VertexID];
  ivec4 pos = ivec4(int(packedData & 0x1Fu) + a.x, int((packedData >> 5) & 0x1Fu) + a.y, int((packedData >> 10) & 0x1Fu) + a.z, 1);
  ivec2 taxis[3] = ivec2[3](ivec2(pos.x, -pos.y), pos.xz, ivec2(pos.z, -pos.y));
  ivec3 tex = ivec3(taxis[flag >> 1], (packedData >> 16) & 0xFFu);
  gl_Position = matMVP * (vec4(pos) + vec4(transPos,0.0));
  texCoord    = tex;
  texCoord    = vec3(tex) * vec3(0.5, 0.5, 1);
  lightness   = sideTints[flag];
}

M client/src/voxel/chunk.c => client/src/voxel/chunk.c +14 -26
@@ 43,8 43,7 @@
#define EDGE (CHUNK_SIZE-1)

#define CUBE_FACES 6
#define VERTICES_PER_FACE 4
vertexPacked blockMeshBuffer[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE * CUBE_FACES * VERTICES_PER_FACE / 2];
vertexPacked blockMeshBuffer[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE * CUBE_FACES / 2];
u16 blockMeshSideEnd[sideMAX];
int chunksGeneratedThisFrame = 0;



@@ 94,64 93,53 @@ static void chunkAddFront(blockId b,u8 x,u8 y,u8 z, u8 w, u8 h, u8 d) {
	const u8 bt = blocks[b].tex[sideFront];
	vertexPacked *vp = &blockMeshBuffer[blockMeshSideEnd[sideFront]];
	*vp++ = mkVertex(x  ,y  ,z+d,0,h,bt,sideFront);
	*vp++ = mkVertex(x+w,y  ,z+d,w,h,bt,sideFront);
	*vp++ = mkVertex(x+w,y+h,z+d,w,0,bt,sideFront);
	*vp++ = mkVertex(x  ,y+h,z+d,0,0,bt,sideFront);
	blockMeshSideEnd[sideFront] += VERTICES_PER_FACE;
	(void) w; (void) h; (void) d;
	blockMeshSideEnd[sideFront] += 1;
}
static void chunkAddBack(blockId b,u8 x,u8 y,u8 z, u8 w, u8 h, u8 d) {
	(void)d;
	const u8 bt = blocks[b].tex[sideBack];
	vertexPacked *vp = &blockMeshBuffer[blockMeshSideEnd[sideBack]];
	*vp++ = mkVertex(x  ,y  ,z  ,0,h,bt,sideBack);
	*vp++ = mkVertex(x  ,y+h,z  ,0,0,bt,sideBack);
	*vp++ = mkVertex(x+w,y+h,z  ,w,0,bt,sideBack);
	*vp++ = mkVertex(x+w,y  ,z  ,w,h,bt,sideBack);
	blockMeshSideEnd[sideBack] += VERTICES_PER_FACE;
	(void) w; (void) h; (void) d;
	blockMeshSideEnd[sideBack] += 1;
}
static void chunkAddTop(blockId b,u8 x,u8 y,u8 z, u8 w, u8 h, u8 d) {
	const u8 bt = blocks[b].tex[sideTop];
	vertexPacked *vp = &blockMeshBuffer[blockMeshSideEnd[sideTop]];
	*vp++ = mkVertex(x  ,y+h,z  ,0,0,bt,sideTop);
	*vp++ = mkVertex(x  ,y+h,z+d,0,d,bt,sideTop);
	*vp++ = mkVertex(x+w,y+h,z+d,w,d,bt,sideTop);
	*vp++ = mkVertex(x+w,y+h,z  ,w,0,bt,sideTop);
	blockMeshSideEnd[sideTop] += VERTICES_PER_FACE;
	(void) w; (void) h; (void) d;
	blockMeshSideEnd[sideTop] += 1;
}
static void chunkAddBottom(blockId b,u8 x,u8 y,u8 z, u8 w, u8 h, u8 d) {
	(void)h;
	const u8 bt = blocks[b].tex[sideBottom];
	vertexPacked *vp = &blockMeshBuffer[blockMeshSideEnd[sideBottom]];
	*vp++ = mkVertex(x  ,y  ,z  ,0,0,bt,sideBottom);
	*vp++ = mkVertex(x+w,y  ,z  ,w,0,bt,sideBottom);
	*vp++ = mkVertex(x+w,y  ,z+d,w,d,bt,sideBottom);
	*vp++ = mkVertex(x  ,y  ,z+d,0,d,bt,sideBottom);
	blockMeshSideEnd[sideBottom] += VERTICES_PER_FACE;
	(void) w; (void) h; (void) d;
	blockMeshSideEnd[sideBottom] += 1;
}
static void chunkAddLeft(blockId b,u8 x,u8 y,u8 z, u8 w, u8 h, u8 d) {
	(void)w;
	const u8 bt = blocks[b].tex[sideLeft];
	vertexPacked *vp = &blockMeshBuffer[blockMeshSideEnd[sideLeft]];
	*vp++ = mkVertex(x  ,y  ,z  ,0,h,bt,sideLeft);
	*vp++ = mkVertex(x  ,y  ,z+d,d,h,bt,sideLeft);
	*vp++ = mkVertex(x  ,y+h,z+d,d,0,bt,sideLeft);
	*vp++ = mkVertex(x  ,y+h,z  ,0,0,bt,sideLeft);
	blockMeshSideEnd[sideLeft] += VERTICES_PER_FACE;
	(void) w; (void) h; (void) d;
	blockMeshSideEnd[sideLeft] += 1;
}
static void chunkAddRight(blockId b,u8 x,u8 y,u8 z, u8 w, u8 h, u8 d) {
	const u8 bt = blocks[b].tex[sideRight];
	vertexPacked *vp = &blockMeshBuffer[blockMeshSideEnd[sideRight]];
	*vp++ = mkVertex(x+w,y  ,z  ,0,h,bt,sideRight);
	*vp++ = mkVertex(x+w,y+h,z  ,0,0,bt,sideRight);
	*vp++ = mkVertex(x+w,y+h,z+d,d,0,bt,sideRight);
	*vp++ = mkVertex(x+w,y  ,z+d,d,h,bt,sideRight);
	blockMeshSideEnd[sideRight] += VERTICES_PER_FACE;
	(void) w; (void) h; (void) d;
	blockMeshSideEnd[sideRight] += 1;
}

// genmesh avg. 0.677ms
// chunkVert: 4246K

static void chunkOptimizePlane(u32 plane[CHUNK_SIZE][CHUNK_SIZE]){
	return;
	for(int y=CHUNK_SIZE-1;y>=0;y--){
	for(int x=CHUNK_SIZE-1;x>=0;x--){
		if((x < CHUNK_SIZE-1) && (plane[x][y]) && ((plane[x][y] & 0xFF00FF) == (plane[x+1][y] & 0xFF00FF))){

M client/src/voxel/chunkvertbuf.c => client/src/voxel/chunkvertbuf.c +21 -41
@@ 37,39 37,22 @@ struct chunkvertbuf {
	};
	u16 vboSize; // size of vbo in vertices
	u8 flags;
	u16 sideIdxStart[sideMAX],sideIdxCount[sideMAX]; // offset and count of side indices within the (sub)buffer
	u16 idxCount; // total number of indices, used when all sides are drawn
	u16 sideFaceStart[sideMAX],sideFaceCount[sideMAX]; // offset and count of side faces within the (sub)buffer
	u16 faceCount; // total number of faces, used when all sides are drawn
};

static u32 allocatedGlBufferBytes;
static GLuint indexBuffer;

static void setVAOFormatPacked(){
	glVertexAttribIPointer(SHADER_ATTRIDX_PACKED, 1, GL_UNSIGNED_INT, sizeof(vertexPacked), NULL);
	glVertexAttribDivisor(SHADER_ATTRIDX_PACKED, 1);
	glEnableVertexAttribArray(SHADER_ATTRIDX_PACKED);
}

#define CUBE_FACES 6
#define VERTICES_PER_FACE 4
#define INDICES_PER_FACE 5
void chunkvertbufInit(){
	allocatedGlBufferBytes = 0;
	glGenBuffers(1, &indexBuffer);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
	gfxObjectLabel(GL_BUFFER, indexBuffer, "Chunk vertex IBO");
	const GLsizei indexCount = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE * CUBE_FACES * INDICES_PER_FACE / 2;
	u16 *indicesRaw = malloc(indexCount * sizeof(u16));
	u16 *indices = indicesRaw;
	const GLsizei indexMax = indexCount/INDICES_PER_FACE - 1;
	for(GLsizei i=0;i<indexMax;++i){
		*indices++ = i*4 + 0;
		*indices++ = i*4 + 1;
		*indices++ = i*4 + 2;
		*indices++ = i*4 + 3;
		*indices++ = 0xFFFF;
	}
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(u16), indicesRaw, GL_STATIC_DRAW);
	free(indicesRaw);
}

u32 chunkvertbufUsedBytes(){


@@ 115,9 98,7 @@ void chunkvertbufFree(struct chunk *c){
	c->vertbuf = NULL;
}


#define VTX_TO_IDX_COUNT(x) (x*INDICES_PER_FACE/VERTICES_PER_FACE)
void chunkvertbufUpdate(chunk *c, vertexPacked *vertices, u16 sideVtxCounts[sideMAX]) {
void chunkvertbufUpdate(chunk *c, vertexPacked *vertices, u16 sideFaceCounts[sideMAX]) {
	struct chunkvertbuf *v = c->vertbuf;
	if(v == NULL) {
		c->vertbuf = v = chunkvertbufAlloc();


@@ 126,15 107,15 @@ void chunkvertbufUpdate(chunk *c, vertexPacked *vertices, u16 sideVtxCounts[side

	// Compute where the geometry for each side starts and how long it is
	// in the chunk's packed vertex buffer.
	u16 vtxCount = 0;
	u16 faceCount = 0;
	for(side sideIndex=0;sideIndex<sideMAX;sideIndex++){
		v->sideIdxStart[sideIndex] = VTX_TO_IDX_COUNT(vtxCount);
		v->sideIdxCount[sideIndex] = VTX_TO_IDX_COUNT(sideVtxCounts[sideIndex]);
		vtxCount += sideVtxCounts[sideIndex];
		v->sideFaceStart[sideIndex] = faceCount;
		v->sideFaceCount[sideIndex] = sideFaceCounts[sideIndex];
		faceCount += sideFaceCounts[sideIndex];
	}
	v->idxCount = VTX_TO_IDX_COUNT(vtxCount);
	v->faceCount = faceCount;

	if(vtxCount == 0){
	if(faceCount == 0){
		// Empty chunk, don't allocate or update anything (except the counts themselves)
		return;
	}


@@ 144,7 125,6 @@ void chunkvertbufUpdate(chunk *c, vertexPacked *vertices, u16 sideVtxCounts[side
		gfxObjectLabel(GL_VERTEX_ARRAY, v->vao, "Chunk %d,%d,%d VAO", c->x, c->y, c->z);
	}
	glBindVertexArray(v->vao);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);

	if(!v->vbo){
		glGenBuffers(1, &v->vbo);


@@ 154,28 134,28 @@ void chunkvertbufUpdate(chunk *c, vertexPacked *vertices, u16 sideVtxCounts[side

	// Upload to the GPU, doing partial updates if possible.
	const u32 vertexSize = sizeof(vertexPacked);
	if(gfxUseSubData && (vtxCount <= v->vboSize)){
		glBufferSubData(GL_ARRAY_BUFFER,0,vertexSize * vtxCount,vertices); // Todo Measure performance impact of this!
	if(gfxUseSubData && (faceCount <= v->vboSize)){
		glBufferSubData(GL_ARRAY_BUFFER,0,vertexSize * faceCount,vertices); // Todo Measure performance impact of this!
	}else{
		allocatedGlBufferBytes -= vertexSize * v->vboSize;
		glBufferData(GL_ARRAY_BUFFER,vertexSize * vtxCount,vertices,GL_STATIC_DRAW);
		allocatedGlBufferBytes += vertexSize * vtxCount;
		v->vboSize = vtxCount;
		glBufferData(GL_ARRAY_BUFFER,vertexSize * faceCount,vertices,GL_STATIC_DRAW);
		allocatedGlBufferBytes += vertexSize * faceCount;
		v->vboSize = faceCount;
		setVAOFormatPacked();
	}
}

void chunkvertbufDrawOne(struct chunk *c, sideMask mask){
	struct chunkvertbuf *v = c->vertbuf;
	if(v->vao == 0 || v->idxCount == 0){return;}
	if(v->vao == 0 || v->faceCount == 0){return;}
	uint bufOffset = 0;

	shaderTransform(sBlockMesh,c->x-subBlockViewOffset.x,c->y-subBlockViewOffset.y,c->z-subBlockViewOffset.z);

	glBindVertexArray(v->vao);
	if(mask == sideMaskALL || !glIsMultiDrawAvailable){
		glDrawElements(GL_TRIANGLE_FAN,v->idxCount,GL_UNSIGNED_SHORT,NULL);
		vboTrisCount += v->idxCount / 3;
	if(true || mask == sideMaskALL || !glIsMultiDrawAvailable){
		glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, VERTICES_PER_FACE, v->faceCount);
		vboTrisCount += v->faceCount * 2;
		drawCallCount++;
	}else{
		// We need one face less max, otherwise it would mean mask == sideMaskALL


@@ 185,8 165,8 @@ void chunkvertbufDrawOne(struct chunk *c, sideMask mask){
		bool reuseLastSide = false;
		for(side sideIndex = 0; sideIndex < sideMAX; sideIndex++){
			if(mask & (1 << sideIndex)){
				const uint cFirst = bufOffset + c->vertbuf->sideIdxStart[sideIndex];
				const uint cCount = c->vertbuf->sideIdxCount[sideIndex];
				const uint cFirst = bufOffset + c->vertbuf->sideFaceStart[sideIndex];
				const uint cCount = c->vertbuf->sideFaceCount[sideIndex];
				if(cCount == 0){continue;}
				vboTrisCount += cCount / 3;
				if(reuseLastSide){