From 5b89a0fab0a46764c92979797681bf170125a7da Mon Sep 17 00:00:00 2001 From: chai Date: Sun, 19 Jul 2020 17:01:00 +0800 Subject: *early back face culling --- Release/SoftShadeRoom.exe | Bin 130560 -> 132096 bytes src/core/device.c | 99 +++++++++++++++++++++--------- src/core/device.h | 5 +- src/core/rasterizer.c | 24 ++------ src/core/rasterizer.h | 2 +- src/example/03_texture/03_texture.c | 23 +++++-- src/extend/mesh.c | 118 +++++++++++++++++++++++++++++------- src/extend/mesh.h | 20 +++--- src/gizmo/gizmo.c | 9 ++- src/main.c | 5 +- src/shaders/pbr.c | 1 + 11 files changed, 212 insertions(+), 94 deletions(-) diff --git a/Release/SoftShadeRoom.exe b/Release/SoftShadeRoom.exe index 280d7e2..310b16e 100644 Binary files a/Release/SoftShadeRoom.exe and b/Release/SoftShadeRoom.exe differ diff --git a/src/core/device.c b/src/core/device.c index ce13c72..5ff39ef 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -459,14 +459,28 @@ void ssrU_blend( out->a = src->a + dst->a; } -void ssr_bindvertices(Vertex* verts, int vert_count, uint* indices, int prim_count) { - ssr_assert(verts && indices); +void ssr_bindvertices(Vertex* verts, int vert_count) { + ssr_assert(verts); state.verts = verts; state.vert_count = vert_count; +} + +void ssr_unbindvertices() { + state.verts = NULL; + state.vert_count = 0; +} + +void ssr_bindindices(uint* indices, int prim_count) { + ssr_assert(indices); state.indices = indices; state.prim_count = prim_count; } +void ssr_unbindindices() { + state.indices = NULL; + state.prim_count = 0; +} + void ssr_useprogram(Program* program) { ssr_assert(program); state.program = program; @@ -485,11 +499,45 @@ static struct { extern ClippedBuffer clip_buffer; /*clipping result*/ +static bool is_back_face(Vec4* c0, Vec4* c1, Vec4*c2) { + /*cull in ndc*/ + float w0 = 1 / c0->w, w1 = 1 / c1->w, w2 = 1 / c2->w; + bool all_front = w0 > 0 && w1 > 0 && w2 > 0; + if (all_front) + { + Vec2 ab, ac; + ab.x = c1->x * w1 - c0->x * w0; + ab.y = c1->y * w1 - c0->y * w0; + ac.x = c2->x * w2 - c0->x * w0; + ac.y = c2->y * w2 - c0->y * w0; + if (ab.x * ac.y - ab.y * ac.x <= 0) { + return TRUE; + } + } + return FALSE; + /*OpenGL algrithm*/ + /* + float w0 = max(1 / c0->w, 0), w1 = 1 / c1->w, w2 = 1 / c2->w; + Vec2 a = { c0->x * w0, c0->y * w0 }; + Vec2 b = { c1->x * w1, c1->y * w1 }; + Vec2 c = { c2->x * w2, c2->y * w2 }; + float signed_area = 0; + signed_area += a.x * b.y - a.y * b.x; + signed_area += b.x * c.y - b.y * c.x; + signed_area += c.x * a.y - c.y * a.x; + if (signed_area <= 0) { + return TRUE; + } + return FALSE; + */ +} + static void render_prims_triangle(uint varying_flag) { uint i0, i1, i2; Vec4 *c0, *c1, *c2; bool reset_active_reg = FALSE; bool clipped = FALSE; + bool is_enable_backface_cull = ssr_isenable(ENABLE_BACKFACECULL); for (int i = 0; i < state.prim_count; ++i) { i0 = state.indices[i * 3]; i1 = state.indices[i * 3 + 1]; @@ -501,34 +549,17 @@ static void render_prims_triangle(uint varying_flag) { /*early back face culling*/ bool early_culled = FALSE; - if (ssr_isenable(ENABLE_BACKFACECULL)) { - /*cull in ndc*/ + if (is_enable_backface_cull) { float w0 = 1 / c0->w, w1 = 1 / c1->w, w2 = 1 / c2->w; - bool all_front = w0 > 0 && w1 > 0 && w2 > 0; - if (all_front) - { + if (w0 <= 0 && w1 <= 0 && w2 <= 0) { + early_culled = TRUE; + continue; + } + else if (w0 > 0 && w1 > 0 && w2 > 0) { early_culled = TRUE; - Vec2 ab, ac; - ab.x = c1->x * w1 - c0->x * w0; - ab.y = c1->y * w1 - c0->y * w0; - ac.x = c2->x * w2 - c0->x * w0; - ac.y = c2->y * w2 - c0->y * w0; - if (ab.x * ac.y - ab.y * ac.x <= 0) { - continue; /*cull*/ - } + if (is_back_face(c0, c1, c2)) + continue; } - //OpenGL algrithm: - //float w0 = max(1 / c0->w, 0), w1 = 1 / c1->w, w2 = 1 / c2->w; - //Vec2 a = { c0->x * w0, c0->y * w0 }; - //Vec2 b = { c1->x * w1, c1->y * w1 }; - //Vec2 c = { c2->x * w2, c2->y * w2 }; - //float signed_area = 0; - //signed_area += a.x * b.y - a.y * b.x; - //signed_area += b.x * c.y - b.y * c.x; - //signed_area += c.x * a.y - c.y * a.x; - //if (signed_area <= 0) { - // continue; /*cull*/ - //} } /*clipping*/ @@ -540,7 +571,12 @@ static void render_prims_triangle(uint varying_flag) { reset_active_reg = FALSE; ssrS_setactiveregr(); } - ssrR_triangle(c0, c1, c2, i0, i1, i2, state.program, early_culled); + /*late back face culling*/ + if (!early_culled && is_enable_backface_cull) { + if(is_back_face(c0, c1, c2)) + continue; + } + ssrR_triangle(c0, c1, c2, i0, i1, i2, state.program); } else { if (!reset_active_reg) { @@ -554,7 +590,12 @@ static void render_prims_triangle(uint varying_flag) { vt2 = &clip_buffer.vertices[i + 1]; c0 = &vt0->clip_coord; c1 = &vt1->clip_coord; c2 = &vt2->clip_coord; i0 = vt0->index; i1 = vt1->index; i2 = vt2->index; - ssrR_triangle(c0, c1, c2, i0, i1, i2, state.program, early_culled); + /*late back face culling*/ + if (!early_culled && is_enable_backface_cull) { + if (is_back_face(c0, c1, c2)) + continue; + } + ssrR_triangle(c0, c1, c2, i0, i1, i2, state.program); } } } diff --git a/src/core/device.h b/src/core/device.h index 79ffd4b..6d0b61d 100644 --- a/src/core/device.h +++ b/src/core/device.h @@ -118,9 +118,12 @@ void ssr_disable(uint mask); bool ssr_isenable(uint mask); /* 绑定顶点数据 */ -void ssr_bindvertices(Vertex* verts, int vert_count, uint* indices, int prim_count); +void ssr_bindvertices(Vertex* verts, int vert_count); void ssr_unbindvertices(); +void ssr_bindindices(uint* indices, int prim_count); +void ssr_unbindindices(); + void ssr_useprogram(Program* program); void ssr_unuseprogram(); diff --git a/src/core/rasterizer.c b/src/core/rasterizer.c index 55d4ad3..9276cbd 100644 --- a/src/core/rasterizer.c +++ b/src/core/rasterizer.c @@ -44,7 +44,7 @@ float ssrR_area(Vec2* v1, Vec2* v2, Vec2* v3) { return area; } -/*from https://github.com/ssloy/tinyrenderer */ +/*https://github.com/ssloy/tinyrenderer */ bool ssrR_barycentric(Vec2* A, Vec2* B, Vec2* C, Vec2* p, Vec3* out) { ssr_assert(A && B && C && p && out); Vec3 s[2], u; @@ -87,24 +87,10 @@ extern UniformCollection* g_uniforms ; void ssrR_triangle( Vec4* CA, Vec4* CB, Vec4* CC, uint IA, uint IB, uint IC, - Program* program, - bool early_culled + Program* program ) { ssr_assert(CA && CB && CC && program); - /*late back face culling*/ - if (!early_culled && ssr_isenable(ENABLE_BACKFACECULL)) { - float w0 = 1 / CA->w, w1 = 1 / CB->w, w2 = 1 / CC->w; - Vec2 ab, ac; - ab.x = CB->x * w1 - CA->x * w0; - ab.y = CB->y * w1 - CA->y * w0; - ac.x = CC->x * w2 - CA->x * w0; - ac.y = CC->y * w2 - CA->y * w0; - if (ab.x * ac.y - ab.y * ac.x <= 0) { - return; - } - } - UniformCollection* uniforms = g_uniforms; Vec4 SA, SB, SC; @@ -164,7 +150,7 @@ void ssrR_triangle( for (p.x = from; order * (p.x - to) <= 0; p.x += order) { \ /*calculate barycentric coordinate*/ \ s[0].z = sa->x - p.x; \ - internal_vec3_cross(&s[0], &s[1], &u); \ + internal_vec3_cross(&s[0], &s[1], &u); \ discardif(compare(u.z, 0)); \ u.z = 1.f / u.z; \ bc.x = 1.f - (u.x + u.y) * u.z; \ @@ -173,7 +159,7 @@ void ssrR_triangle( discardif(bc.x < 0 || bc.y < 0 || bc.z < 0); \ /*perspective correction*/ \ bc.x *= CAw; bc.y *= CBw; bc.z *= CCw; \ - internal_vec3_scale(&bc, 1.f / (bc.x + bc.y + bc.z), &bc); \ + internal_vec3_scale(&bc, 1.f / (bc.x + bc.y + bc.z), &bc); \ /*early depth testing*/ \ if(depth_test){ \ depth = bc.x*sa->z + bc.y*sb->z + bc.z*sc->z; \ @@ -189,7 +175,7 @@ void ssrR_triangle( /*interpolate varying variables*/ \ ssrS_solveregsbcp(&bc, IA, IB, IC); \ /*enter fragment shader*/ \ - discard = !frag_shader(out_color[0]); \ + discard = !frag_shader(out_color[0]); \ discardif(discard); \ /*put point*/ \ ssr_blendandputpoint(p.x, p.y, blend); \ diff --git a/src/core/rasterizer.h b/src/core/rasterizer.h index fce8376..c7ccc3c 100644 --- a/src/core/rasterizer.h +++ b/src/core/rasterizer.h @@ -13,7 +13,7 @@ bool ssrR_barycentric(Vec2* A, Vec2* B, Vec2* C, Vec2* p, Vec3* out); /* void ssrR_center(Vec2* A, Vec2* B, Vec2* C, Vec2* out); /*获得重心*/ bool ssrR_ispointintriangle(Vec2* A, Vec2* B, Vec2* C, Vec2* p); -void ssrR_triangle(Vec4* CA, Vec4* CB, Vec4* CC, uint IA, uint IB, uint IC, Program* program, bool early_called); +void ssrR_triangle(Vec4* CA, Vec4* CB, Vec4* CC, uint IA, uint IB, uint IC, Program* program); void ssrR_line(Vec4* CA, Vec4* CB, uint IA, uint IB, Program* program); void ssrR_point(Vec4* CA, uint IA, Program* program); diff --git a/src/example/03_texture/03_texture.c b/src/example/03_texture/03_texture.c index 2e9d6f1..23597c9 100644 --- a/src/example/03_texture/03_texture.c +++ b/src/example/03_texture/03_texture.c @@ -43,16 +43,20 @@ static Mesh* cyborg_mesh; static Texture* ball_albedo; static Mesh* ball_mesh; +Texture* base_color_texs[]; + EXAMPLE void onload_texture(void* data) { - CameraConfig* conf = (CameraConfig*)data; + CameraConfig* conf = (CameraConfig*)data; //mech_albedo = texture_loadfromfile("res/dieselpunk/mech_basecolor.tga"); - mech_albedo = texture_loadfromfile("res/gun/gun.png"); + //mech_albedo = texture_loadfromfile("res/station/textures/projekt_Gas_BaseColor.png"); + mech_albedo = texture_loadfromfile("res/townscaper/town_diffuse.jpg"); mech_normal = texture_loadfromfile("res/dieselpunk/mech_normal.tga"); mech_roughness = texture_loadfromfile("res/dieselpunk/mech_roughness.tga"); mech_metalness = texture_loadfromfile("res/dieselpunk/mech_metalness.tga"); - //mech_mesh = mesh_loadfromobj("res/dieselpunk/mech.obj"); - mech_mesh = mesh_loadfromobj("res/gun/gun.obj"); + mech_mesh = mesh_loadfromobj("res/townscaper/town.obj"); + //mech_mesh = mesh_loadfromobj("res/gun/gun.obj"); + //mech_mesh = mesh_loadfromobj("res/station/station.obj"); //mech_mesh = mesh_loadfromobj("res/gun/triangle.obj"); ground_albedo = texture_loadfromfile("res/dieselpunk/ground_basecolor.tga"); ground_mesh = mesh_loadfromobj("res/dieselpunk/ground.obj"); @@ -70,6 +74,7 @@ EXAMPLE void onevent_texture(void* data) { EXAMPLE void onupdate_texture(void*data) { ssr_matrixmode(MATRIX_MODEL); ssr_loadidentity(); + ssr_scale(100,100,100); Vec3 light = {1, 0, 0}; ssr_setuniformvec3(0, &light); @@ -101,8 +106,14 @@ EXAMPLE void ondraw_texture(void*data) { ssr_setuniformtex(1, mech_normal); ssr_setuniformtex(2, mech_roughness); ssr_setuniformtex(3, mech_metalness); - ssr_bindvertices(mech_mesh->vertices, mech_mesh->vert_count, mech_mesh->triangles, mech_mesh->tris_count); - ssr_draw(PRIMITIVE_TRIANGLE); + ssr_bindvertices(mech_mesh->vertices, mech_mesh->vert_count); + for (int i = 0; i < mech_mesh->submesh_count; ++i) { + ssr_bindindices(mech_mesh->submesh[i].triangles, mech_mesh->submesh[i].tris_count); + ssr_draw(PRIMITIVE_TRIANGLE); + } + + ssr_unbindvertices(); + ssr_unbindindices(); /* ssr_setstencilfunc(STENCILFUNC_EQUAL, 1, 0xff); diff --git a/src/extend/mesh.c b/src/extend/mesh.c index 56b1afe..45a5736 100644 --- a/src/extend/mesh.c +++ b/src/extend/mesh.c @@ -206,17 +206,24 @@ typedef struct { int* related_triangles; } MeshVertexInfo; +typedef struct { + char name[32]; + int start, end; +} SubmeshInfo; + typedef struct { MeshVertexInfo* vertices; // vertices list Triangle* triangles; // triangles list + SubmeshInfo* submeshs; } MeshInfo; -void free_mesh_info(MeshInfo* mesh) { - for (int i = 0; i < darray_size(mesh->vertices); ++i) { - darray_free(mesh->vertices[i].related_triangles); +void free_mesh_info(MeshInfo* mesh_info) { + for (int i = 0; i < darray_size(mesh_info->vertices); ++i) { + darray_free(mesh_info->vertices[i].related_triangles); } - darray_free(mesh->vertices); - darray_free(mesh->triangles); + darray_free(mesh_info->vertices); + darray_free(mesh_info->triangles); + darray_free(mesh_info->submeshs); } void calc_face_tanget(MeshInfo* mesh); @@ -234,6 +241,10 @@ Mesh* mesh_loadfromobj(const char* path) { file = fopen(path, "rb"); assert(file != NULL); + SubmeshInfo* submeshs = NULL; + SubmeshInfo submesh_info = {0}; + int submesh_start = 0, submesh_end = -1; + char line[LINE_SIZE]; while (1) { @@ -242,7 +253,14 @@ Mesh* mesh_loadfromobj(const char* path) { break; } else if (strncmp(line, "o ", 2) == 0) { /* submesh name */ - // ignore + if(submesh_end >= submesh_start){ + submesh_info.start = submesh_start; + submesh_info.end = submesh_end; + darray_push(submeshs, submesh_info); + submesh_start = submesh_end + 1; + } + items = sscanf(line, "o %s", submesh_info.name); + assert(items == 1); } else if (strncmp(line, "v ", 2) == 0) { /* position */ Vec3 position; @@ -292,13 +310,15 @@ Mesh* mesh_loadfromobj(const char* path) { } else ++p; } - assert(face_verts && darray_size(face_verts) > 0); - FaceVertex* v0 = &face_verts[0]; - for (int i = 1; i < darray_size(face_verts) - 1; ++i) { - FaceVertex* v1 = &face_verts[i]; - FaceVertex* v2 = &face_verts[i + 1]; - FaceInfo face = { *v0, *v1, *v2}; - darray_push(face_list, face); + if (face_verts && darray_size(face_verts) > 0) { + FaceVertex* v0 = &face_verts[0]; + for (int i = 1; i < darray_size(face_verts) - 1; ++i) { + FaceVertex* v1 = &face_verts[i]; + FaceVertex* v2 = &face_verts[i + 1]; + FaceInfo face = { *v0, *v1, *v2 }; + darray_push(face_list, face); + ++submesh_end; + } } darray_free(face_verts); #else @@ -315,7 +335,13 @@ Mesh* mesh_loadfromobj(const char* path) { { // ignore } - memset(&line, 0, LINE_SIZE); + //memset(&line, 0, LINE_SIZE); + } + + if (submesh_end >= submesh_start) { + submesh_info.start = submesh_start; + submesh_info.end = submesh_end; + darray_push(submeshs, submesh_info); } int vert_counts = darray_size(vertex_list); @@ -326,6 +352,7 @@ Mesh* mesh_loadfromobj(const char* path) { int vert_count = 0; MeshInfo mesh_info = {0}; + mesh_info.submeshs = submeshs; for (int i = 0; i < darray_size(face_list); ++i) { @@ -404,19 +431,49 @@ Mesh* mesh_loadfromobj(const char* path) { Mesh* build_mesh(MeshInfo* mesh_info) { Mesh* mesh = malloc(sizeof(Mesh)); - int num_of_face = darray_size(mesh_info->triangles); - mesh->triangles = malloc(num_of_face * 3 * sizeof(uint)); - for (int i = 0; i < darray_size(mesh_info->triangles); ++i) { - mesh->triangles[3 * i] = mesh_info->triangles[i].vertices[0]; - mesh->triangles[3 * i + 1] = mesh_info->triangles[i].vertices[1]; - mesh->triangles[3 * i + 2] = mesh_info->triangles[i].vertices[2]; - } - mesh->tris_count = num_of_face; + // vertices mesh->vertices = malloc(sizeof(Vertex) * darray_size(mesh_info->vertices)); for (int i = 0; i < darray_size(mesh_info->vertices); ++i) { mesh->vertices[i] = mesh_info->vertices[i].props; } mesh->vert_count = darray_size(mesh_info->vertices); + + if(mesh_info->submeshs) { + int num_of_submeshs = darray_size(mesh_info->submeshs); + mesh->submesh = malloc(num_of_submeshs * sizeof(SubMesh)); + mesh->submesh_count = num_of_submeshs; + for (int i = 0; i < darray_size(mesh_info->submeshs); ++i) { + SubmeshInfo* submesh_info = &mesh_info->submeshs[i]; + SubMesh* submesh = &mesh->submesh[i]; + strcpy(submesh->name, submesh_info->name); + int start = submesh_info->start, end = submesh_info->end; + int num_of_face = end - start + 1; + submesh->tris_count = num_of_face; + submesh->triangles = malloc(num_of_face * 3 * sizeof(uint)); + int k = 0; + for(int j = start; j <= end; ++j) { + Triangle* triangle = &mesh_info->triangles[j]; + submesh->triangles[k++] = triangle->vertices[0]; + submesh->triangles[k++] = triangle->vertices[1]; + submesh->triangles[k++] = triangle->vertices[2]; + } + } + // map to first submesh + mesh->triangles = mesh->submesh[0].triangles; + mesh->tris_count = mesh->submesh[0].tris_count; + } else { + mesh->submesh = NULL; + mesh->submesh_count = 0; + int num_of_face = darray_size(mesh_info->triangles); + mesh->triangles = malloc(num_of_face * 3 * sizeof(uint)); + for (int i = 0; i < darray_size(mesh_info->triangles); ++i) { + mesh->triangles[3 * i] = mesh_info->triangles[i].vertices[0]; + mesh->triangles[3 * i + 1] = mesh_info->triangles[i].vertices[1]; + mesh->triangles[3 * i + 2] = mesh_info->triangles[i].vertices[2]; + } + mesh->tris_count = num_of_face; + } + return mesh; } @@ -516,4 +573,19 @@ void calc_vertex_tangnet(MeshInfo* mesh) { } } -#endif // SIMPLE_OBJ_LOADER \ No newline at end of file +#endif // SIMPLE_OBJ_LOADER + +void free_mesh(Mesh* mesh) { + if(!mesh) return; + + free(mesh->vertices); + if (!mesh->submesh) + { + for (int i = 0; i < mesh->submesh_count; ++i) + free(mesh->submesh[i].triangles); + } + else + { + free(mesh->triangles); + } +} diff --git a/src/extend/mesh.h b/src/extend/mesh.h index d7a519e..6e58a9d 100644 --- a/src/extend/mesh.h +++ b/src/extend/mesh.h @@ -2,27 +2,27 @@ #define _SOFTSHADEROOM_MESH_H_ #include "../core/vert.h" -/* + typedef struct { - Vertex* vertices; - uint vert_count; - uint* triangles; + uint* triangles; // indices of vertex uint tris_count; - const char* name; + char name[32]; } SubMesh; -*/ + typedef struct { Vertex* vertices; uint vert_count; - uint* triangles; + // map to first submesh + uint* triangles; uint tris_count; - //const char* name; - /* + char name[32]; + // submeshs SubMesh* submesh; uint submesh_count; - */ } Mesh; Mesh* mesh_loadfromobj(const char* path); +void free_mesh(Mesh* mesh); + #endif \ No newline at end of file diff --git a/src/gizmo/gizmo.c b/src/gizmo/gizmo.c index 30638ee..5706e60 100644 --- a/src/gizmo/gizmo.c +++ b/src/gizmo/gizmo.c @@ -111,7 +111,8 @@ void gizmo_grid() { verts[i].color = color; grid[i] = i++; } - ssr_bindvertices(&verts, vCount, &grid, vCount/2); + ssr_bindvertices(&verts, vCount); + ssr_bindindices(&grid, vCount / 2); ssr_matrixmode(MATRIX_MODEL); ssr_loadidentity(); ssr_useprogram(&line_shader); @@ -130,7 +131,8 @@ void gizmo_axis() { {5, {0, 0, 10000}, vec3zero, vec4zero, vec2zero, 0xff0000ff}, }; int grid[] = { 0, 1, 2, 3, 4, 5 }; - ssr_bindvertices(&verts, 6, &grid, 3); + ssr_bindvertices(&verts, 6); + ssr_bindindices(&grid, 3); ssr_matrixmode(MATRIX_MODEL); ssr_loadidentity(); ssr_useprogram(&line_shader); @@ -145,7 +147,8 @@ void gizmo_line(Vec3 start, Vec3 end, Color32 color) { {1, end, vec3zero, vec4zero, vec2zero, color32_tocolor(&color)}, }; int line[] = { 0, 1}; - ssr_bindvertices(&verts, 2, &line, 1); + ssr_bindvertices(&verts, 2); + ssr_bindindices(&line, 1); ssr_matrixmode(MATRIX_MODEL); ssr_loadidentity(); ssr_useprogram(&line_shader); diff --git a/src/main.c b/src/main.c index 2b6e853..19dd7ab 100644 --- a/src/main.c +++ b/src/main.c @@ -18,6 +18,7 @@ #define SCREEN_HEIGHT 480.f static char* instruction = + "/***********************************************/\n" "/* SoftShadeRoom */\n" "/* */\n" @@ -38,8 +39,7 @@ static char* instruction = " texture \n" " bloom \n" " fog \n" -" shadow \n" -" \n"; +" shadow \n"; typedef void(*Callback)(void*); @@ -86,6 +86,7 @@ int main(int argc, char* argv[]) { {5, 5}, {150, 150}, 4000, }; + printf("Loading...\n"); onload(&cam_config); scene.main_camera = camera_create(wnd, &cam_config); gizmo_init(); diff --git a/src/shaders/pbr.c b/src/shaders/pbr.c index 8a47051..a917f95 100644 --- a/src/shaders/pbr.c +++ b/src/shaders/pbr.c @@ -48,6 +48,7 @@ static bool frag( Vec4* color) { //Color32 nc = tex2d(noramltex, in->texcoord); //internal_vec3_scale(&c, roughness, &c); *color = vec4_saturate(c); + //*color = vec4(1,1,1,1); //*color = vec4(depth, depth, depth, 1); //internal_vec3_scale(color, 1 - depth, color); return 1; -- cgit v1.1-26-g67d0