Texture not applied correctly to half a quad

What am I doing wrong here?

image

I’ve stripped down what I’m working on to the most basic bits, which revealed some other alignment and orientation issues, which was good, but this problem still persists. I’m sure it’s something fundamental, but I’m kinda learning as I go here. Any help would be most appreciated. Thank you, in advance!

I tried to put in my image, but I’m only allowed a single item, and an image of the problem seemed most prudent. Bit it’s just a 16x16 image. The text was to help me correct orientation.

Here’s my code:

from math import pi, sin, cos

from direct.showbase.ShowBase import ShowBase
from direct.task import Task

from panda3d.core import *

import sys

class FaceDirection:
    UP = 0,
    DOWN = 1,
    LEFT = 2,
    RIGHT = 3,
    FRONT = 4,
    BACK = 5

class TestApp(ShowBase):
    _BlockScale = 10 #distance on each side of center.  x2 = block width

    #unit directions for face tris.  These will be multiplied against _BlockScale to get final positions
    _Faces = {        
        FaceDirection.FRONT:    [(+1, -1, -1),(+1, +1, -1),(+1, +1, +1),(+1, -1, +1),(+1, -1, -1),(+1, +1, +1)],
        FaceDirection.BACK:     [(-1, +1, -1),(-1, -1, -1),(-1, -1, +1),(-1, +1, +1),(-1, +1, -1),(-1, -1, +1)],
        FaceDirection.DOWN:     [(+1, -1, +1),(+1, +1, +1),(-1, +1, +1),(-1, -1, +1),(+1, -1, +1),(-1, +1, +1)],
        FaceDirection.UP:       [(-1, -1, -1),(-1, +1, -1),(+1, +1, -1),(+1, -1, -1),(-1, -1, -1),(+1, +1, -1)],
        FaceDirection.LEFT:     [(-1, -1, -1),(+1, -1, -1),(+1, -1, +1),(-1, -1, +1),(-1, -1, -1),(+1, -1, +1)],
        FaceDirection.RIGHT:    [(+1, +1, -1),(-1, +1, -1),(-1, +1, +1),(+1, +1, +1),(+1, +1, -1),(-1, +1, +1)],
    }

    _UVUnits = [
        (0.0, 0.0),
        (1.0, 0.0),
        (1.0, 1.0),
        (0.0, 1.0)
    ]

    def __init__(self):

        ShowBase.__init__(self)

        self.accept("escape",sys.exit) 
        self.taskMgr.add(self.spinCameraTask, "SpinCameraTask")

        self.setFrameRateMeter(True)

        tex = self.loader.loadTexture("grass.png")
        tex.setMagfilter(SamplerState.FT_nearest)
        tex.setMinfilter(SamplerState.FT_nearest)

        node = GeomNode('chunk-0_0')
        self.createCube(node)
        nodePath = self.render.attachNewNode(node)

        ts = TextureStage('ts')
        nodePath.setTexture(ts, tex)


    def createCube(self, gNode: GeomNode):

        frontGeom = self.createFace(FaceDirection.FRONT)
        gNode.addGeom(frontGeom)
    
        backGeom = self.createFace(FaceDirection.BACK)
        gNode.addGeom(backGeom)
    
        upGeom = self.createFace(FaceDirection.UP)
        gNode.addGeom(upGeom)
    
        downGeom = self.createFace(FaceDirection.DOWN)
        gNode.addGeom(downGeom)
    
        leftGeom = self.createFace(FaceDirection.LEFT)
        gNode.addGeom(leftGeom)

        rightGeom = self.createFace(FaceDirection.RIGHT)
        gNode.addGeom(rightGeom)

    def createFace(self, faceDirection: int):

        vformat = GeomVertexFormat.getV3t2()
        vdata = GeomVertexData('cube', vformat, Geom.UHStatic)
        vdata.setNumRows(len(self._Faces[faceDirection]))

        vertex = GeomVertexWriter(vdata, 'vertex')
        texcoord = GeomVertexWriter(vdata, 'texcoord')

        for vg in self._Faces[faceDirection]: 
            v1, v2, v3 = vg
            vertex.addData3((v1 * self._BlockScale), (v2 * self._BlockScale), (v3 * self._BlockScale))

        for uv in self._UVUnits:
            texcoord.addData2f(uv)

        tri1 = GeomTriangles(Geom.UHStatic)

        tri1.addVertices(0, 1, 2)
        tri1.addVertices(3, 4, 5)
        tri1.closePrimitive()
        
        geom = Geom(vdata)
        geom.addPrimitive(tri1)
        
        return geom

    def spinCameraTask(self, task):
        angleDegrees = task.time * 6.0
        angleRadians = angleDegrees * (pi / 180.0)
        self.camera.setPos(100 * sin(angleRadians), -100 * cos(angleRadians), 10)
        self.camera.setHpr(angleDegrees, 0, 0)      
        return Task.cont


app = TestApp()
app.run()

Hello, welcome.

You have broken the order of the vertices. There are only four vertices, but you have six specified.

tri1.addVertices(0, 1, 2)
tri1.addVertices(3, 4, 5)

That’s right.

tri1.addVertices(0, 1, 2)
tri1.addVertices(2, 3, 0)
1 Like

Indeed, and it is also sufficient to add only four vertices:

    _Faces = {        
        FaceDirection.FRONT:    [(+1, -1, -1),(+1, +1, -1),(+1, +1, +1),(+1, -1, +1)],
        FaceDirection.BACK:     [(-1, +1, -1),(-1, -1, -1),(-1, -1, +1),(-1, +1, +1)],
        FaceDirection.DOWN:     [(+1, -1, +1),(+1, +1, +1),(-1, +1, +1),(-1, -1, +1)],
        FaceDirection.UP:       [(-1, -1, -1),(-1, +1, -1),(+1, +1, -1),(+1, -1, -1)],
        FaceDirection.LEFT:     [(-1, -1, -1),(+1, -1, -1),(+1, -1, +1),(-1, -1, +1)],
        FaceDirection.RIGHT:    [(+1, +1, -1),(-1, +1, -1),(-1, +1, +1),(+1, +1, +1)]
    }

I actually have 6 vertices specified. Something I was reading suggested it was better to use 6 vertices rather than share 2 of them between the tris. If you look at the _Faces dictionary, though, you’ll see that indices 1 & 2 are the same as 3 & 4. Both go clockwise (as is evident by both tri’s facing this direction. You did use a slightly different vertex order on the second tri, but that didn’t change anything when I tried it.

I have such a cheat sheet.

1 Like

Not sure how that could be better (unless you want to be able to split a face into its separate triangles at run-time for some reason), but if you really do want six vertices, you also need to add six UV coordinates instead of four.

1 Like

But that does work… so the problem is that Panda doesn’t know how to map to the 6 vertices. I’d have to UVs to map the UVs to both tris. I’ll go with 4 vertices for now… thank you both!

Basically, you need to add the same number of each vertex attribute (position, UVs, normal, etc.).