The shape below is single-surface. It was constructed by addmesh()ing together four meshes. Note the two black pixels along a junction between two quads. There are actually a lot of parallel quads which are joined together without artifacts in this mesh, but that junction is the only one that causes any artifacts. How can I fix this?


;--------------------------------------------------------------------------------------------------- ;= TYPES ;--------------------------------------------------------------------------------------------------- type point field x#, y#, z# end type type shape field rotation_pivot field origin_pivot field entity field shape_info.shape_info end type type shape_info field r, g, b field block.shape_block_info[4-1] field collision_map[4*4*4-1] end type type shape_block_info field block_id field x, y, ang end type ;--------------------------------------------------------------------------------------------------- ;= CONSTANTS ;--------------------------------------------------------------------------------------------------- const BLOCK_SIZE# = 1.0 const BLOCK_BEVEL_WIDTH# = 0.2 ; block enum const BLOCK_end = 0 const BLOCK_corner = 1 const BLOCK_straight = 2 const BLOCK_three_way = 3 const BLOCK_filled_corner = 4 const BLOCK_TOTAL = 5 ; shape enum const SHAPE_I = 0 const SHAPE_T = 1 const SHAPE_O = 2 const SHAPE_L = 3 const SHAPE_J = 4 const SHAPE_S = 5 const SHAPE_Z = 6 const SHAPE_TOTAL = 7 ;--------------------------------------------------------------------------------------------------- ;= GLOBALS ;--------------------------------------------------------------------------------------------------- dim block_blueprint_outsideonly(BLOCK_TOTAL-1) dim block_blueprint_complete(BLOCK_TOTAL-1) dim shape_colours(SHAPE_TOTAL-1, 3-1) dim shape_info.shape_info(SHAPE_TOTAL-1) global block_texture ; used in Calculate_Normals() Dim Face_NX#(32768) Dim Face_NY#(32768) Dim Face_NZ#(32768) Dim Vertex_ConnectedTris(32768) Dim Vertex_TriList(32768, 32) ;--------------------------------------------------------------------------------------------------- ;= PROGRAM FLOW ;--------------------------------------------------------------------------------------------------- game_init() game_main() ;--------------------------------------------------------------------------------------------------- function game_init() graphics3d 800, 600, 32, 0 setbuffer backbuffer() init_block_blueprint_outsideonly() init_shape_data() camera = createcamera() positionentity(camera, 0, 0, -6) light = createlight() rotateentity(light, 45, 45, 0) ambientlight(200, 200, 200) block_texture = loadtexture("block_texture.jpg", 1) ; 64=spheremap, but that doesn't work well on tris with "flat" normals. flare them? scaletexture(block_texture, 3, 3) end function ;--------------------------------------------------------------------------------------------------- function game_main() current_shape.shape = create_shape(SHAPE_T) entityalpha(current_shape\entity, .5) ;entityblend(current_shape\entity, 3) mousexspeed() : mouseyspeed() while not keyhit(1) turnentity(current_shape\rotation_pivot, -mouseyspeed(), mousexspeed(), 0) renderworld flip wend end end function ;--------------------------------------------------------------------------------------------------- ;= POINTS ;--------------------------------------------------------------------------------------------------- function point_new.point(x#, y#, z#) this.point = new point this\x = x : this\y = y : this\z = z return this end function ;--------------------------------------------------------------------------------------------------- ;= SHAPES ;--------------------------------------------------------------------------------------------------- function create_shape.shape(id) s.shape = new shape s\shape_info = shape_info(id) s\origin_pivot = createpivot() s\rotation_pivot = createpivot(s\origin_pivot) s\entity = createmesh(s\rotation_pivot) entitycolor(s\entity, s\shape_info\r, s\shape_info\g, s\shape_info\b) entityshininess(s\entity, .3) ;entitytexture(s\entity, block_texture) for b = 0 to 4-1 block_info.shape_block_info = s\shape_info\block[b] bp = block_blueprint_outsideonly(block_info\block_id) rotatemesh(bp, 0, 0, -block_info\ang) positionmesh(bp, -block_info\x, -block_info\y, 0) addmesh(bp, s\entity) positionmesh(bp, block_info\x, block_info\y, 0) rotatemesh(bp, 0, 0, block_info\ang) next surface_id = getsurface(s\entity, 1) for v = 0 to countvertices(surface_id)-1 x# = vertexx(surface_id, v) y# = vertexy(surface_id, v) z# = vertexz(surface_id, v) vertextexcoords(surface_id, v, x+z/2, y+z/2) next return s end function ;--------------------------------------------------------------------------------------------------- function init_shape_data() restore shape_data for id = 0 to SHAPE_TOTAL-1 shape_info(id) = new shape_info read shape_info(id)\r, shape_info(id)\g, shape_info(id)\b for b = 0 to 4-1 shape_info(id)\block[b] = new shape_block_info read shape_info(id)\block[b]\block_id read shape_info(id)\block[b]\x read shape_info(id)\block[b]\y read shape_info(id)\block[b]\ang next for r = 0 to 3 for y = 0 to 3 for x = 0 to 3 read shape_info(id)\collision_map[r*16 + y*4 + x] next next next next end function ;--------------------------------------------------------------------------------------------------- function init_block_blueprint_outsideonly() local xy_lookup#[3] xy_lookup[0] = -BLOCK_SIZE / 2 xy_lookup[1] = -BLOCK_SIZE / 2 + BLOCK_BEVEL_WIDTH xy_lookup[2] = BLOCK_SIZE / 2 - BLOCK_BEVEL_WIDTH xy_lookup[3] = BLOCK_SIZE / 2 local z_lookup#[3] z_lookup[0] = BLOCK_SIZE / 2 z_lookup[1] = BLOCK_SIZE / 2 - BLOCK_BEVEL_WIDTH z_lookup[2] = -BLOCK_SIZE / 2 + BLOCK_BEVEL_WIDTH z_lookup[3] = -BLOCK_SIZE / 2 restore block_blueprints while true read id if id = -1 then exit block_blueprint_outsideonly(id) = createmesh() hideentity(block_blueprint_outsideonly(id)) surface_id = createsurface(block_blueprint_outsideonly(id)) while true while true read x# if x = -1 then exit read y#, z# x = xy_lookup[x] y = xy_lookup[y] z = z_lookup[z] point_new(x, y, z) wend if first point = null then exit ; if no points were created, then we're done with this block_mesh draw_polygon_with_all_points(surface_id) wend Calculate_Normals(block_blueprint_outsideonly(id)) block_blueprint_complete(id) = copymesh(block_blueprint_outsideonly(id)) hideentity(block_blueprint_complete(id)) surface_id = getsurface(block_blueprint_complete(id), 1) while true while true read x# if x = -1 then exit read y#, z# x = xy_lookup[x] y = xy_lookup[y] z = z_lookup[z] point_new(x, y, z) wend if first point = null then exit ; if no points were created, then we're done with this block_mesh draw_polygon_with_all_points(surface_id) wend Calculate_Normals(block_blueprint_complete(id)) wend end function ;--------------------------------------------------------------------------------------------------- function draw_polygon_with_all_points(surface_id) point.point = first point first_vertex = addvertex(surface_id, point\x, point\y, point\z) delete point point.point = first point previous_vertex = addvertex(surface_id, point\x, point\y, point\z) delete point while first point <> null point = first point this_vertex = addvertex(surface_id, point\x, point\y, point\z) delete point addtriangle(surface_id, first_vertex, previous_vertex, this_vertex) previous_vertex = this_vertex wend end function ;--------------------------------------------------------------------------------------------------- ;= DATA ;--------------------------------------------------------------------------------------------------- ;= block_blueprints .block_blueprints ; a list of vertices for drawing polygons. triangles will be drawn between the first, previous, and current point. ; the second set of polygons for each block are for "inside" polygons, which will not be visible in unadulterated shapes. data BLOCK_end data 1,1,3, 1,3,3, 2,3,3, 2,1,3, -1 ; surface data 1,3,3, 1,1,3, 0,0,2, 0,3,2, -1 ; bevel data 1,1,3, 2,1,3, 3,0,2, 0,0,2, -1 ; bevel data 2,1,3, 2,3,3, 3,3,2, 3,0,2, -1 ; bevel data 0,0,0, 0,0,2, 3,0,2, 3,0,0, -1 ; south edge data 3,0,0, 3,0,2, 3,3,2, 3,3,0, -1 ; east edge data 0,3,0, 0,3,2, 0,0,2, 0,0,0, -1 ; west edge data 0,0,0, 3,0,0, 3,3,0, 0,3,0, -1 ; bottom data -1 data 3,3,0, 3,3,2, 2,3,3, 1,3,3, 0,3,2, 0,3,0, -1 ; north edge data -1 data BLOCK_corner data 1,1,3, 1,3,3, 2,3,3, 2,2,3, 3,2,3, 3,1,3, -1 ; surface data 1,3,3, 1,1,3, 0,0,2, 0,3,2, -1 ; bevel data 1,1,3, 3,1,3, 3,0,2, 0,0,2, -1 ; bevel data 2,2,3, 2,3,3, 3,3,2, -1 ; bevel data 3,2,3, 2,2,3, 3,3,2, -1 ; bevel data 0,0,0, 0,0,2, 3,0,2, 3,0,0, -1 ; south edge data 0,3,0, 0,3,2, 0,0,2, 0,0,0, -1 ; west edge data 0,0,0, 3,0,0, 3,3,0, 0,3,0, -1 ; bottom data -1 data 3,0,0, 3,0,2, 3,1,3, 3,2,3, 3,3,2, 3,3,0, -1 ; east edge data 3,3,0, 3,3,2, 2,3,3, 1,3,3, 0,3,2, 0,3,0, -1 ; north edge data -1 data BLOCK_straight data 1,0,3, 1,3,3, 2,3,3, 2,0,3, -1 ; surface data 1,3,3, 1,0,3, 0,0,2, 0,3,2, -1 ; bevel data 2,0,3, 2,3,3, 3,3,2, 3,0,2, -1 ; bevel data 3,0,0, 3,0,2, 3,3,2, 3,3,0, -1 ; east edge data 0,3,0, 0,3,2, 0,0,2, 0,0,0, -1 ; west edge data 0,0,0, 3,0,0, 3,3,0, 0,3,0, -1 ; bottom data -1 data 0,0,0, 0,0,2, 1,0,3, 2,0,3, 3,0,2, 3,0,0, -1 ; south edge data 3,3,0, 3,3,2, 2,3,3, 1,3,3, 0,3,2, 0,3,0, -1 ; north edge data -1 data BLOCK_three_way data 1,0,3, 1,3,3, 2,3,3, 2,0,3, -1 ; surface data 2,2,3, 3,2,3, 3,1,3, 2,1,3, -1 ; surface data 1,3,3, 1,0,3, 0,0,2, 0,3,2, -1 ; bevel data 2,2,3, 2,3,3, 3,3,2, -1 ; bevel data 3,2,3, 2,2,3, 3,3,2, -1 ; bevel data 2,1,3, 3,1,3, 3,0,2, -1 ; bevel data 2,0,3, 2,1,3, 3,0,2, -1 ; bevel data 0,3,0, 0,3,2, 0,0,2, 0,0,0, -1 ; west edge data 0,0,0, 3,0,0, 3,3,0, 0,3,0, -1 ; bottom data -1 data 0,0,0, 0,0,2, 1,0,3, 2,0,3, 3,0,2, 3,0,0, -1 ; south edge data 3,0,0, 3,0,2, 3,1,3, 3,2,3, 3,3,2, 3,3,0, -1 ; east edge data 3,3,0, 3,3,2, 2,3,3, 1,3,3, 0,3,2, 0,3,0, -1 ; north edge data -1 data BLOCK_filled_corner data 1,1,3, 1,3,3, 3,3,3, 3,1,3, -1 ; surface data 1,3,3, 1,1,3, 0,0,2, 0,3,2, -1 ; bevel data 1,1,3, 3,1,3, 3,0,2, 0,0,2, -1 ; bevel data 0,0,0, 0,0,2, 3,0,2, 3,0,0, -1 ; south edge data 0,3,0, 0,3,2, 0,0,2, 0,0,0, -1 ; west edge data 0,0,0, 3,0,0, 3,3,0, 0,3,0, -1 ; bottom data -1 data 3,0,0, 3,0,2, 3,1,3, 3,3,3, 3,3,0, -1 ; east edge data 3,3,0, 3,3,3, 1,3,3, 0,3,2, 0,3,0, -1 ; north edge data -1 data -1 ;--------------------------------------------------------------------------------------------------- ;= shape_data .shape_data ; SHAPE_I data 0, 0, 127 data BLOCK_end, 0, -2, 180 data BLOCK_straight, 0, -1, 0 data BLOCK_straight, 0, 0, 0 data BLOCK_end, 0, 1, 0 data 0,0,1,0 data 0,0,1,0 data 0,0,1,0 data 0,0,1,0 data 0,0,0,0 data 1,1,1,1 data 0,0,0,0 data 0,0,0,0 data 0,0,1,0 data 0,0,1,0 data 0,0,1,0 data 0,0,1,0 data 0,0,0,0 data 1,1,1,1 data 0,0,0,0 data 0,0,0,0 ; SHAPE_T data 127, 127, 0 data BLOCK_end, 0, 1, 0 data BLOCK_three_way, 0, 0, 90 data BLOCK_end, -1, 0, -90 data BLOCK_end, 1, 0, 90 data 0,0,1,0 data 0,1,1,1 data 0,0,0,0 data 0,0,0,0 data 0,0,1,0 data 0,0,1,1 data 0,0,1,0 data 0,0,0,0 data 0,0,0,0 data 0,1,1,1 data 0,0,1,0 data 0,0,0,0 data 0,0,1,0 data 0,1,1,0 data 0,0,1,0 data 0,0,0,0 ; SHAPE_O data 127, 127, 127 data BLOCK_filled_corner, 0, 0, 0 data BLOCK_filled_corner, -1, 0, -90 data BLOCK_filled_corner, 0, -1, 90 data BLOCK_filled_corner, -1, -1, 180 data 0,0,0,0 data 0,1,1,0 data 0,1,1,0 data 0,0,0,0 data 0,0,0,0 data 0,1,1,0 data 0,1,1,0 data 0,0,0,0 data 0,0,0,0 data 0,1,1,0 data 0,1,1,0 data 0,0,0,0 data 0,0,0,0 data 0,1,1,0 data 0,1,1,0 data 0,0,0,0 ; SHAPE_L data 127, 0, 127 data BLOCK_end, 0, 1, 0 data BLOCK_straight, 0, 0, 0 data BLOCK_corner, 0, -1, 180 data BLOCK_end, 1, -1, 90 data 0,0,1,0 data 0,0,1,0 data 0,0,1,1 data 0,0,0,0 data 0,0,0,0 data 0,1,1,1 data 0,1,0,0 data 0,0,0,0 data 0,1,1,0 data 0,0,1,0 data 0,0,1,0 data 0,0,0,0 data 0,0,0,1 data 0,1,1,1 data 0,0,0,0 data 0,0,0,0 ; SHAPE_J data 0, 127, 127 data BLOCK_end, 0, 1, 0 data BLOCK_straight, 0, 0, 0 data BLOCK_corner, 0, -1, 90 data BLOCK_end, -1, -1, -90 data 0,0,1,0 data 0,0,1,0 data 0,1,1,0 data 0,0,0,0 data 0,1,0,0 data 0,1,1,1 data 0,0,0,0 data 0,0,0,0 data 0,0,1,1 data 0,0,1,0 data 0,0,1,0 data 0,0,0,0 data 0,0,0,0 data 0,1,1,1 data 0,0,0,1 data 0,0,0,0 ; SHAPE_S data 127, 0, 0 data BLOCK_end, 0, 1, 0 data BLOCK_corner, 0, 0, 180 data BLOCK_corner, 1, 0, 0 data BLOCK_end, 1, -1, 180 data 0,0,1,0 data 0,0,1,1 data 0,0,0,1 data 0,0,0,0 data 0,0,1,1 data 0,1,1,0 data 0,0,0,0 data 0,0,0,0 data 0,0,1,0 data 0,0,1,1 data 0,0,0,1 data 0,0,0,0 data 0,0,1,1 data 0,1,1,0 data 0,0,0,0 data 0,0,0,0 ; SHAPE_Z data 0, 127, 0 data BLOCK_end, 1, 1, 0 data BLOCK_corner, 1, 0, 90 data BLOCK_corner, 0, 0, -90 data BLOCK_end, 0, -1, 180 data 0,0,0,1 data 0,0,1,1 data 0,0,1,0 data 0,0,0,0 data 0,1,1,0 data 0,0,1,1 data 0,0,0,0 data 0,0,0,0 data 0,0,0,1 data 0,0,1,1 data 0,0,1,0 data 0,0,0,0 data 0,1,1,0 data 0,0,1,1 data 0,0,0,0 data 0,0,0,0 ;--------------------------------------------------------------------------------------------------- ;= MISC ;--------------------------------------------------------------------------------------------------- Function Calculate_Normals(ThisMesh) ; Author: sswift ; Date: 2004-03-25 09:17:35 ; Loop through all surfaces of the mesh. Surfaces = CountSurfaces(ThisMesh) For LOOP_Surface = 1 To Surfaces Surface_Handle = GetSurface(ThisMesh, LOOP_Surface) ; Reset the number of connected polygons for each vertex. For LoopV = 0 To 32767 Vertex_ConnectedTris(LoopV) = 0 Next ; Loop through all triangles in this surface of the mesh. Tris = CountTriangles(Surface_Handle) For LOOP_Tris = 0 To Tris-1 ; Get the vertices that make up this triangle. Vertex_0 = TriangleVertex(Surface_Handle, LOOP_Tris, 0) Vertex_1 = TriangleVertex(Surface_Handle, LOOP_Tris, 1) Vertex_2 = TriangleVertex(Surface_Handle, LOOP_Tris, 2) ; Adjust the number of triangles each vertex is connected to and ; store this triangle in each vertex's list of triangles it is connected to. ConnectedTris = Vertex_ConnectedTris(Vertex_0) Vertex_TriList(Vertex_0, ConnectedTris) = LOOP_Tris Vertex_ConnectedTris(Vertex_0) = ConnectedTris + 1 ConnectedTris = Vertex_ConnectedTris(Vertex_1) Vertex_TriList(Vertex_1, ConnectedTris) = LOOP_Tris Vertex_ConnectedTris(Vertex_1) = ConnectedTris + 1 ConnectedTris = Vertex_ConnectedTris(Vertex_2) Vertex_TriList(Vertex_2, ConnectedTris) = LOOP_Tris Vertex_ConnectedTris(Vertex_2) = ConnectedTris + 1 ; Calculate the normal for this face. ; Get the corners of this face: Ax# = VertexX#(Surface_Handle, Vertex_0) Ay# = VertexY#(Surface_Handle, Vertex_0) Az# = VertexZ#(Surface_Handle, Vertex_0) Bx# = VertexX#(Surface_Handle, Vertex_1) By# = VertexY#(Surface_Handle, Vertex_1) Bz# = VertexZ#(Surface_Handle, Vertex_1) Cx# = VertexX#(Surface_Handle, Vertex_2) Cy# = VertexY#(Surface_Handle, Vertex_2) Cz# = VertexZ#(Surface_Handle, Vertex_2) ; Triangle 1 ; Get the vectors for two edges of the triangle. Px# = Ax#-Bx# Py# = Ay#-By# Pz# = Az#-Bz# Qx# = Bx#-Cx# Qy# = By#-Cy# Qz# = Bz#-Cz# ; Compute their cross product. Nx# = Py#*Qz# - Pz#*Qy# Ny# = Pz#*Qx# - Px#*Qz# Nz# = Px#*Qy# - Py#*Qx# ; Store the face normal. Face_NX#(LOOP_Tris) = Nx# Face_NY#(LOOP_Tris) = Ny# Face_NZ#(LOOP_Tris) = Nz# Next ; Now that all the face normals for this surface have been calculated, calculate the vertex normals. Vertices = CountVertices(Surface_Handle) For LOOP_Vertices = 0 To Vertices-1 ; Reset this normal. Nx# = 0 Ny# = 0 Nz# = 0 ; Add the normals of all polygons which are connected to this vertex. Polys = Vertex_ConnectedTris(LOOP_Vertices) For LOOP_Polys = 0 To Polys-1 ThisPoly = Vertex_TriList(LOOP_Vertices, LOOP_Polys) Nx# = Nx# + Face_NX#(ThisPoly) Ny# = Ny# + Face_NY#(ThisPoly) Nz# = Nz# + Face_NZ#(ThisPoly) Next ; Normalize the new vertex normal. ; (Normalizing is scaling the vertex normal down so that it's length = 1) Nl# = Sqr(Nx#^2 + Ny#^2 + Nz#^2) ; Avoid a divide by zero error if by some freak accident, the vectors add up to 0. ; If Nl# = 0 Then Nl# = 0.1 Nx# = Nx# / Nl# Ny# = Ny# / Nl# Nz# = Nz# / Nl# ; Set the vertex normal. VertexNormal Surface_Handle, LOOP_Vertices, Nx#, Ny#, Nz# ;VertexColor Surface_Handle, LOOP_Vertices, polys*127, polys*127, polys*127 Next Next End Function