Cascaded shadow mapping support
This commit is contained in:
		
							parent
							
								
									68264fcf87
								
							
						
					
					
						commit
						f20d32eb3a
					
				
							
								
								
									
										227
									
								
								src/k3.c
									
									
									
									
									
								
							
							
						
						
									
										227
									
								
								src/k3.c
									
									
									
									
									
								
							| @ -584,6 +584,16 @@ static struct k3Light *Lights; | |||||||
| void k3SetLights(size_t count, struct k3Light *lightsNew) { | void k3SetLights(size_t count, struct k3Light *lightsNew) { | ||||||
| 	LightCount = count; | 	LightCount = count; | ||||||
| 	Lights = lightsNew; | 	Lights = lightsNew; | ||||||
|  | 	 | ||||||
|  | 	for(int i = 0; i < count; i++) { | ||||||
|  | 		if(Lights[i].type == k3_DIRECTIONAL) { | ||||||
|  | 			if(Lights[i].dir.cascadeCount == 0) { | ||||||
|  | 				Lights[i].dir.cascadeCount = 1; | ||||||
|  | 			} else if(Lights[i].dir.cascadeCount > 3) { | ||||||
|  | 				Lights[i].dir.cascadeCount = 3; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct k3Light *k3GetLights(size_t *a) { | struct k3Light *k3GetLights(size_t *a) { | ||||||
| @ -617,15 +627,18 @@ static mat4 CamMat; | |||||||
| static mat4 ProjMat; | static mat4 ProjMat; | ||||||
| 
 | 
 | ||||||
| struct LightShadow { | struct LightShadow { | ||||||
| 	mat4 vp; | 	uint8_t vpCount; | ||||||
|  | 	mat4 vp[6]; | ||||||
|  | 	 | ||||||
| 	vec4 atlasSegment; | 	vec4 atlasSegment; | ||||||
|  | 	 | ||||||
| #ifdef k3_IRREGULAR_SHADOWS | #ifdef k3_IRREGULAR_SHADOWS | ||||||
| 	GLuint multimapEls; // buffer
 | 	GLuint multimapEls; // buffer
 | ||||||
| 	GLuint multimapHeads; // image
 | 	GLuint multimapHeads; // image
 | ||||||
| #endif | #endif | ||||||
| } __attribute__((aligned(16))); | } __attribute__((aligned(16))); | ||||||
| static size_t LightShadowsCount, LightShadowsCapacity; |  | ||||||
| static struct LightShadow *LightShadows; | static struct LightShadow *LightShadows; | ||||||
|  | static size_t LightShadowsCount = 0, LightShadowsCapacity = 0; | ||||||
| static struct k3Offscreen *ShadowAtlas; | static struct k3Offscreen *ShadowAtlas; | ||||||
| 
 | 
 | ||||||
| static bool LightShadowIrregularMode = false; | static bool LightShadowIrregularMode = false; | ||||||
| @ -818,17 +831,22 @@ static void setup_glsl_lighting_uniforms(GLuint bound, int lightsStart, int ligh | |||||||
| 		lightsCount = LightCount - lightsStart; | 		lightsCount = LightCount - lightsStart; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	vec4 settings1[4]; | 	if(lightsCount) { | ||||||
| 	vec4 settings2[4]; | 	//	raise(SIGINT);
 | ||||||
|  | 	} | ||||||
| 	 | 	 | ||||||
| 	vec4 colors[4]; | 	vec4 settings1[4] = {}; | ||||||
| 	memset(colors, 0, sizeof(colors)); | 	vec4 settings2[4] = {}; | ||||||
|  | 	 | ||||||
|  | 	vec4 colors[4] = {}; | ||||||
| 	 | 	 | ||||||
| 	for(int i = 0; i < lightsCount; i++) { | 	for(int i = 0; i < lightsCount; i++) { | ||||||
| 		struct k3Light *l = &Lights[i + lightsStart]; | 		struct k3Light *l = &Lights[i + lightsStart]; | ||||||
| 		 | 		 | ||||||
| 		if(l->type == k3_DIRECTIONAL) { | 		if(l->type == k3_DIRECTIONAL) { | ||||||
| 			glm_vec4_copy(l->dir.direction, settings1[i]); | 			glm_vec4_copy(l->dir.direction, settings1[i]); | ||||||
|  | 			 | ||||||
|  | 			settings2[i][0] = l->dir.cascadeCount; | ||||||
| 		} else if(l->type == k3_SPOT) { | 		} else if(l->type == k3_SPOT) { | ||||||
| 			glm_vec4_copy(l->spot.position, settings1[i]); | 			glm_vec4_copy(l->spot.position, settings1[i]); | ||||||
| 			 | 			 | ||||||
| @ -879,20 +897,26 @@ static void setup_glsl_shadow_uniforms(GLuint bound, int atlasUnit, int lightsSt | |||||||
| 		k3Log(k3_ERR, "Max 4 lights per pass"); | 		k3Log(k3_ERR, "Max 4 lights per pass"); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	if(!LightShadows) return; | 	if(!ShadowAtlas) return; | ||||||
| 	 | 	 | ||||||
| 	if(LightShadowIrregularMode) { | 	if(LightShadowIrregularMode) { | ||||||
| 		assert(k3IsCore); | 		assert(k3IsCore); | ||||||
| 		 | 		 | ||||||
| 		glUniform1i(glGetUniformLocation(bound, "u_pixelsinshadow"), 0); | 		glUniform1i(glGetUniformLocation(bound, "u_pixelsinshadow"), 0); | ||||||
| 	} else { | 	} else { | ||||||
| 		mat4 m[4]; | 		size_t vpi = 0; | ||||||
|  | 		mat4 m[6]; | ||||||
| 		memset(m, 0, sizeof(m)); | 		memset(m, 0, sizeof(m)); | ||||||
| 		 | 		 | ||||||
| 		vec4 seg[4]; | 		vec4 seg[4]; | ||||||
| 		 | 		 | ||||||
| 		for(int i = 0; i < lightsCount; i++) { | 		for(int i = 0; i < lightsCount; i++) { | ||||||
| 			glm_mat4_copy(LightShadows[i + lightsStart].vp, m[i]); | 			for(int z = 0; z < LightShadows[i + lightsStart].vpCount; z++) { | ||||||
|  | 				glm_mat4_copy(LightShadows[i + lightsStart].vp[z], m[vpi]); | ||||||
|  | 				 | ||||||
|  | 				vpi++; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
| 			glm_vec4_copy(LightShadows[i + lightsStart].atlasSegment, seg[i]); | 			glm_vec4_copy(LightShadows[i + lightsStart].atlasSegment, seg[i]); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| @ -905,12 +929,12 @@ static void setup_glsl_shadow_uniforms(GLuint bound, int atlasUnit, int lightsSt | |||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		if(!k3IsCore) { | 		if(!k3IsCore) { | ||||||
| 			glUniformMatrix4fvARB(glGetUniformLocationARB(bound, "u_shadows0vp"), 4, GL_FALSE, (float*) m); | 			glUniformMatrix4fvARB(glGetUniformLocationARB(bound, "u_shadows0vp"), vpi, GL_FALSE, (float*) m); | ||||||
| 			glUniform4fvARB(glGetUniformLocationARB(bound, "u_shadows0seg"), 4, (float*) seg); | 			glUniform4fvARB(glGetUniformLocationARB(bound, "u_shadows0seg"), 4, (float*) seg); | ||||||
| 			 | 			 | ||||||
| 			glUniform1iARB(glGetUniformLocationARB(bound, "u_shadows0atlas"), atlasUnit); | 			glUniform1iARB(glGetUniformLocationARB(bound, "u_shadows0atlas"), atlasUnit); | ||||||
| 		} else { | 		} else { | ||||||
| 			glUniformMatrix4fv(glGetUniformLocationARB(bound, "u_shadows0vp"), 4, GL_FALSE, (float*) m); | 			glUniformMatrix4fv(glGetUniformLocationARB(bound, "u_shadows0vp"), vpi, GL_FALSE, (float*) m); | ||||||
| 			glUniform4fv(glGetUniformLocationARB(bound, "u_shadows0seg"), 4, (float*) seg); | 			glUniform4fv(glGetUniformLocationARB(bound, "u_shadows0seg"), 4, (float*) seg); | ||||||
| 			 | 			 | ||||||
| 			glUniform1i(glGetUniformLocationARB(bound, "u_shadows0atlas"), atlasUnit); | 			glUniform1i(glGetUniformLocationARB(bound, "u_shadows0atlas"), atlasUnit); | ||||||
| @ -1659,76 +1683,109 @@ void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull) { | |||||||
| 	glFrontFace(GL_CCW); | 	glFrontFace(GL_CCW); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static size_t compute_light_views(mat4 **_projs, mat4 **_cams, char **_isCube) { | static void split_frustum(mat4 proj, int cascades, mat4 croppeds[]) { | ||||||
| 	mat4 *projs = _mm_malloc(sizeof(*projs) * LightCount * 6, 16); | 	float fovy = glm_persp_fovy(proj); | ||||||
| 	mat4 *cams = _mm_malloc(sizeof(*cams) * LightCount * 6, 16); | 	float aspect = glm_persp_aspect(proj); | ||||||
| 	char *isCube = _mm_malloc(sizeof(*isCube) * LightCount * 6, 1); |  | ||||||
| 	 | 	 | ||||||
| 	size_t s = 0; | 	float near, far; | ||||||
|  | 	glm_persp_decomp_near(proj, &near); | ||||||
|  | 	glm_persp_decomp_far(proj, &far); | ||||||
|  | 	 | ||||||
|  | 	float depthChunk = (far - near) / cascades; | ||||||
|  | 	 | ||||||
|  | 	for(int c = 0; c < cascades; c++) { | ||||||
|  | 		glm_perspective(fovy, aspect, near + c * depthChunk, near + (c + 1) * depthChunk, croppeds[c]); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct LightView { | ||||||
|  | 	uint8_t cams; | ||||||
|  | 	uint8_t projs; | ||||||
|  | 	mat4 c[6]; | ||||||
|  | 	mat4 p[3]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static size_t compute_light_views(struct LightView lv[]) { | ||||||
|  | 	size_t totalTilesUsed = 0; | ||||||
| 	 | 	 | ||||||
| 	for(int i = 0; i < LightCount; i++) { | 	for(int i = 0; i < LightCount; i++) { | ||||||
| 		isCube[s] = 0; |  | ||||||
| 		 |  | ||||||
| 		struct k3Light *l = &Lights[i]; | 		struct k3Light *l = &Lights[i]; | ||||||
| 		 | 		 | ||||||
| 		/*if(!l->castShadow) {
 |  | ||||||
| 			continue; |  | ||||||
| 		}*/ |  | ||||||
| 		 |  | ||||||
| 		if(l->type == k3_DIRECTIONAL) { | 		if(l->type == k3_DIRECTIONAL) { | ||||||
| 			glm_ortho(-60, 60, -60, 60, -60, 60, projs[s]); | 			size_t CASCADE_COUNT = l->dir.cascadeCount; | ||||||
| 			 | 			 | ||||||
| 			mat4 invmainproj; | 			lv[i].projs = CASCADE_COUNT; | ||||||
| 			glm_mat4_inv_fast(ProjMat, invmainproj); | 			lv[i].cams = CASCADE_COUNT; | ||||||
| 			 | 			 | ||||||
| 			mat4 frustummat; | 			mat4 croppeds[CASCADE_COUNT]; | ||||||
| 			glm_mat4_mul(CamMat, invmainproj, frustummat); | 			split_frustum(ProjMat, CASCADE_COUNT, croppeds); | ||||||
| 			 | 			 | ||||||
| 			vec4 corners[8]; | 			for(int cascade = 0; cascade < CASCADE_COUNT; cascade++) { | ||||||
| 			glm_frustum_corners(frustummat, corners); | 				mat4 invmainproj; | ||||||
|  | 				glm_mat4_inv_fast(croppeds[cascade], invmainproj); | ||||||
| 				 | 				 | ||||||
| 			vec4 viewcenter; | 				mat4 frustummat; | ||||||
| 			glm_frustum_center(corners, viewcenter); | 				glm_mat4_mul(CamMat, invmainproj, frustummat); | ||||||
| 				 | 				 | ||||||
| 			mat4 view; | 				vec4 corners[8]; | ||||||
| 			glm_look_anyup(viewcenter, l->dir.direction, view); | 				glm_frustum_corners(frustummat, corners); | ||||||
| 				 | 				 | ||||||
| 			glm_mat4_inv_fast(view, cams[s]); | 				vec4 viewcenter; | ||||||
|  | 				glm_frustum_center(corners, viewcenter); | ||||||
| 				 | 				 | ||||||
| 			s++; | 				mat4 lightview; | ||||||
|  | 				glm_look_anyup(viewcenter, l->dir.direction, lightview); | ||||||
|  | 				 | ||||||
|  | 				vec4 minaabb = {+HUGE_VALF, +HUGE_VALF, +HUGE_VALF}; | ||||||
|  | 				vec4 maxaabb = {-HUGE_VALF, -HUGE_VALF, -HUGE_VALF}; | ||||||
|  | 				 | ||||||
|  | 				for(int c = 0; c < 8; c++) { | ||||||
|  | 					vec4 lightspaceCorner; | ||||||
|  | 					glm_mat4_mulv(lightview, corners[c], lightspaceCorner); | ||||||
|  | 					 | ||||||
|  | 					glm_vec4_minv(minaabb, lightspaceCorner, minaabb); | ||||||
|  | 					glm_vec4_maxv(maxaabb, lightspaceCorner, maxaabb); | ||||||
|  | 				} | ||||||
|  | 				 | ||||||
|  | 				glm_ortho(minaabb[0], maxaabb[0], minaabb[1], maxaabb[1], minaabb[2] - 50, maxaabb[2], lv[i].p[cascade]); | ||||||
|  | 				glm_mat4_inv_fast(lightview, lv[i].c[cascade]); | ||||||
|  | 			} | ||||||
| 		} else if(l->type == k3_SPOT || l->type == k3_HALF_OMNI) { | 		} else if(l->type == k3_SPOT || l->type == k3_HALF_OMNI) { | ||||||
| 			glm_perspective(l->spot.angle, 1, 0.1, l->radius, projs[s]); | 			lv[i].projs = 1; | ||||||
|  | 			lv[i].cams = 1; | ||||||
|  | 			 | ||||||
|  | 			glm_perspective(l->spot.angle, 1, 0.1, l->radius, lv[i].p[0]); | ||||||
| 			 | 			 | ||||||
| 			mat4 view; | 			mat4 view; | ||||||
| 			glm_look_anyup(l->spot.position, l->spot.direction, view); | 			glm_look_anyup(l->spot.position, l->spot.direction, view); | ||||||
| 			 | 			 | ||||||
| 			glm_mat4_inv_fast(view, cams[s]); | 			glm_mat4_inv_fast(view, lv[i].c[0]); | ||||||
| 			 |  | ||||||
| 			s++; |  | ||||||
| 		} else if(l->type == k3_OMNI) { | 		} else if(l->type == k3_OMNI) { | ||||||
| 			static const vec3 dirs[] = {{0, 0, -1}, {0, 0, 1}, {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}}; | 			static const vec3 dirs[] = {{0, 0, -1}, {0, 0, 1}, {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}}; | ||||||
| 			static const vec3 ups[] = {{0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 0, 1}, {0, 0, -1}}; | 			static const vec3 ups[] = {{0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 0, 1}, {0, 0, -1}}; | ||||||
| 			 | 			 | ||||||
|  | 			lv[i].projs = 1; | ||||||
|  | 			lv[i].cams = 6; | ||||||
|  | 			 | ||||||
|  | 			mat4 proj; | ||||||
|  | 			glm_perspective(glm_rad(120), 1, 0.1, l->radius, proj); | ||||||
|  | 			 | ||||||
|  | 			glm_mat4_copy(proj, lv[i].p[0]); | ||||||
|  | 			 | ||||||
| 			for(int d = 0; d < 6; d++) { | 			for(int d = 0; d < 6; d++) { | ||||||
| 				glm_perspective(glm_rad(120), 1, 0.1, l->radius, projs[s]); |  | ||||||
| 				 | 				 | ||||||
| 				mat4 view; | 				mat4 view; | ||||||
| 				glm_look(l->omni.position, dirs[d], ups[d], view); | 				glm_look(l->omni.position, dirs[d], ups[d], view); | ||||||
| 				 | 				 | ||||||
| 				glm_mat4_inv_fast(view, cams[s]); | 				glm_mat4_inv_fast(view, lv[i].c[d]); | ||||||
| 				 | 				 | ||||||
| 				isCube[s] = d != 0; |  | ||||||
| 				 |  | ||||||
| 				s++; |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		 | ||||||
|  | 		totalTilesUsed += lv[i].cams; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	*_projs = projs; | 	return totalTilesUsed; | ||||||
| 	*_cams = cams; |  | ||||||
| 	*_isCube = isCube; |  | ||||||
| 	 |  | ||||||
| 	return s; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef k3_IRREGULAR_SHADOWS | #ifdef k3_IRREGULAR_SHADOWS | ||||||
| @ -1892,7 +1949,7 @@ void k3PassIrregular(struct k3Offscreen *mainview, mat4 mainproj, mat4 maincam) | |||||||
| 	mat4 *cams; | 	mat4 *cams; | ||||||
| 	char *isCube; | 	char *isCube; | ||||||
| 	 | 	 | ||||||
| 	size_t count = compute_light_views(&projs, &cams, &isCube); | 	count = compute_light_views(&projs, &cams, &isCube); | ||||||
| 	 | 	 | ||||||
| 	LightShadowsCount = count; | 	LightShadowsCount = count; | ||||||
| 	if(LightShadowsCount > LightShadowsCapacity) { | 	if(LightShadowsCount > LightShadowsCapacity) { | ||||||
| @ -1995,11 +2052,8 @@ void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr) { | |||||||
| 	glm_mat4_copy(projection, ProjMat); | 	glm_mat4_copy(projection, ProjMat); | ||||||
| 	glm_mat4_copy(cam, CamMat); | 	glm_mat4_copy(cam, CamMat); | ||||||
| 	 | 	 | ||||||
| 	mat4 *projs; | 	struct LightView *views = alloca(sizeof(*views) * LightCount); | ||||||
| 	mat4 *cams; | 	size_t totalTilesUsed = compute_light_views(views); | ||||||
| 	char *isCube; |  | ||||||
| 	 |  | ||||||
| 	size_t count = compute_light_views(&projs, &cams, &isCube); |  | ||||||
| 	 | 	 | ||||||
| 	ShadowAtlas = offscr; | 	ShadowAtlas = offscr; | ||||||
| 	 | 	 | ||||||
| @ -2014,7 +2068,7 @@ void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr) { | |||||||
| 		LightShadowsCapacity = LightShadowsCount; | 		LightShadowsCapacity = LightShadowsCount; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	if(count == 0) { | 	if(totalTilesUsed == 0) { | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| @ -2025,45 +2079,56 @@ void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr) { | |||||||
| 	 | 	 | ||||||
| 	int cellsPerDimension = 0; | 	int cellsPerDimension = 0; | ||||||
| 	 | 	 | ||||||
| 	if(count == 1) { | 	if(totalTilesUsed == 1) { | ||||||
| 		cellsPerDimension = 1; | 		cellsPerDimension = 1; | ||||||
| 	} else { | 	} else { | ||||||
| 		int cellsTotalLog = 1; | 		int cellsTotalSqrt = 1; | ||||||
| 		while((1 << cellsTotalLog) < count) { | 		while((cellsTotalSqrt * cellsTotalSqrt) < totalTilesUsed) { | ||||||
| 			cellsTotalLog++; | 			cellsTotalSqrt++; | ||||||
| 		} | 		} | ||||||
| 		cellsPerDimension = 1 << ((cellsTotalLog + 1) / 2); | 		cellsPerDimension = cellsTotalSqrt; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	uint16_t sz = k3TexSzX(offscr->depth); | 	uint16_t sz = k3TexSzX(offscr->depth); | ||||||
| 	uint16_t cellSz = sz / cellsPerDimension; | 	float cellSz = (float) sz / cellsPerDimension; | ||||||
| 	 |  | ||||||
| 	size_t s = 0; |  | ||||||
| 	 | 	 | ||||||
| 	k3BeginOffscreen(offscr); | 	k3BeginOffscreen(offscr); | ||||||
| 		for(size_t i = 0; i < count; i++) { | 		size_t i = 0; | ||||||
| 			int cellX = i % cellsPerDimension; | 		for(size_t li = 0; li < LightCount; li++) { | ||||||
| 			int cellY = i / cellsPerDimension; | 			struct LightView *lv = &views[li]; | ||||||
| 			 | 			 | ||||||
| 			int vp[] = {cellX * cellSz, cellY * cellSz, cellSz, cellSz}; | 			for(int camIdx = 0; camIdx < lv->cams; camIdx++) { | ||||||
|  | 				int cellX = i % cellsPerDimension; | ||||||
|  | 				int cellY = i / cellsPerDimension; | ||||||
| 				 | 				 | ||||||
| 			mat4 view = GLM_MAT4_IDENTITY_INIT; | 				int vp[] = { | ||||||
| 			glm_mat4_inv(cams[i], view); | 					(int) roundf(cellX * cellSz), | ||||||
|  | 					(int) roundf(cellY * cellSz), | ||||||
|  | 					(int) cellSz, | ||||||
|  | 					(int) cellSz | ||||||
|  | 				}; | ||||||
| 				 | 				 | ||||||
| 			if(!isCube[i]) { | 				mat4 view = GLM_MAT4_IDENTITY_INIT; | ||||||
| 				glm_mat4_mul(projs[i], view, LightShadows[s].vp); | 				glm_mat4_inv(lv->c[camIdx], view); | ||||||
| 				glm_vec4_copy((vec4) {i, (float) cellSz / sz, 0, 0}, LightShadows[s].atlasSegment); | 				 | ||||||
| 				s++; | 				mat4 proj = GLM_MAT4_IDENTITY_INIT; | ||||||
|  | 				glm_mat4_copy(lv->projs == 1 ? lv->p[0] : lv->p[camIdx], proj); | ||||||
|  | 				 | ||||||
|  | 				LightShadows[li].vpCount = lv->projs; | ||||||
|  | 				if(lv->projs > 1 || camIdx == 0) { | ||||||
|  | 					glm_mat4_mul(proj, view, LightShadows[li].vp[camIdx]); | ||||||
|  | 				} | ||||||
|  | 				if(camIdx == 0) { | ||||||
|  | 					glm_vec4_copy((vec4) {i, (float) cellSz / sz, 0, 0}, LightShadows[li].atlasSegment); | ||||||
|  | 				} | ||||||
|  | 				 | ||||||
|  | 				glViewport(vp[0], vp[1], vp[2], vp[3]); | ||||||
|  | 				k3PassDepthOnly(proj, lv->c[camIdx], i == 0, false); | ||||||
|  | 				 | ||||||
|  | 				i++; | ||||||
| 			} | 			} | ||||||
| 			 |  | ||||||
| 			glViewport(vp[0], vp[1], vp[2], vp[3]); |  | ||||||
| 			k3PassDepthOnly(projs[i], cams[i], i == 0, false); |  | ||||||
| 		} | 		} | ||||||
| 	k3EndOffscreen(offscr); | 	k3EndOffscreen(offscr); | ||||||
| 	 |  | ||||||
| 	_mm_free(projs); |  | ||||||
| 	_mm_free(cams); |  | ||||||
| 	_mm_free(isCube); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void k3BatchClear() { | void k3BatchClear() { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 mid
						mid