4

I’m testing the current status of Qt3D. I’m very fond of the MetalRoughMaterial, but I can’t seem to handle this simple use case in Qt3D: I would like to use textures that repeat to fill the face they are on.

Desired result:

desired result desired result2

What I get is this (see code below):

longcube

In case you’re wondering, I made 2 cubes next to one another to make the 2nd image, but I don’t consider this a real solution…)

I have been experimenting with WrapMode, Qtexture, textureScale but can’t find a solution in Qt3D yet.

I noticed that when I change textureScale, this repeats the texture on all faces. But on the small faces we get the same amount of images as in the longer ones. Is there a way to change this for x, y and z differently?

code:

import Qt3D.Core 2.12
import Qt3D.Render 2.12
import Qt3D.Input 2.12
import Qt3D.Extras 2.12

Entity {
    id: sceneRoot

    components: [
        RenderSettings {
            activeFrameGraph: ForwardRenderer{ 
                camera: camera
            }
        },
        InputSettings { },

        DirectionalLight {
            worldDirection: Qt.vector3d(-1, -1, -1);
            color: "white"
            intensity: 2.0
        }
   ]

    Camera {
        id: camera
        projectionType: CameraLens.PerspectiveProjection
        fieldOfView: 45
        aspectRatio: 800/600
        nearPlane : 0.1
        farPlane : 1000.0
        position: Qt.vector3d( 2.0, 2.0, 2.0 )
        upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
        viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
    }

    OrbitCameraController { camera: camera }

    CuboidMesh {
        id: cuboidMesh
        xExtent:  2
        yExtent:  1
        zExtent:  1
    }

    Transform {
        id: cuboidTranslation
        translation: Qt.vector3d(0, 0, 0)
    }

    Entity {
        id: cuboidEntity
        components: [ cuboidMesh, testMaterial, cuboidTranslation ]
    }

    MetalRoughMaterial {
        id: testMaterial
        baseColor: TextureLoader {
            source: "qrc:/assets/textures/checkers.png"
        }

        metalness:0.0
        roughness: 1.0
        textureScale :1
    }
}

I know how to do it in pure opengl(without Qt3D) by altering texturecoordinates of vertex data. If that is the direction to go I suspect I will have to make my own custom Mesh. Can somebody confirm this is the way to go? Or are there other solutions for this use case?

Thanks for your time reading this. Every help, suggestion is welcome, even the pure opengl solutions.

Eddy Alleman
  • 1,096
  • 2
  • 10
  • 21

2 Answers2

5

Yes, you can change texture coordinates in geometry, but I think it's easier to write custom shader, which gets proper texture coordinates from computations. For example, you can start with SimpleMaterial shader, modify it to display grid like you want. I had similar code for fragment shader:

#version 150 core

uniform vec3 boxSize;//all model
uniform vec2 wallSectionSize;//x y - size of cell inside this model
varying highp vec3 pos;

void main() {
    vec3 pt = pos.xyz;
    float x = pt.x;
    float y = pt.y;
    float z = pt.z;
    bool side = false;
    if(x==0 || x==boxSize.x) {
        x = z;
        side = true;
    } else if(y==0 || y==boxSize.y) {
        y = z;
    }
    //b == block number
    const int nbx = int(x/wallSectionSize.x);
    const int nby = int(y/wallSectionSize.y);//floor number from 0
    //coordinates in this block umber
    float bx = x - nbx * wallSectionSize.x;
    float by = y - nby * wallSectionSize.y;
    if(nbx % 2)
        //fragColor = texture2D(...);
        fragColor = vec4(1,1,0,0);
    else
        fragColor = vec4(1,0,1,0);
}
  • 1
    Thank you very much! Do you have a small compilable example on how to use it in Qt3D with a cuboid? or any link to an example that uses custom shaders? This looks very promising and I'd like to play with it. – Eddy Alleman Aug 03 '19 at 18:31
  • 1
    no bother... I think I found what I need: Techniques and renderpasses.Thanks again Konstantine. – Eddy Alleman Aug 03 '19 at 19:13
2

Also you can use textureScale property if your cube grows equally in all directions. In your example, where cube is not equally scaled, you can use textureTransform matrix. Also I created example which uses both approaches and a shader: https://github.com/neurocod/StackOverflow/tree/master/texture-sapect-ratio

  • Thank you for your effort, Konstantine ! It's a pity that textureTransform cannot be used with MetalRoughMaterial the same way as with TextureMaterial (looking dull). There is no texture property there. Maybe there is a workaround... – Eddy Alleman Aug 04 '19 at 14:40
  • 1
    I beleive the easiest way is to clone `MetalRoughMaterial` shader and reimplement `textureTransform` as it's done in `TextureMaterial`. – Konstantine Kozachuck Aug 04 '19 at 15:26
  • 1
    I was afraid you gonna say that. Thanks again – Eddy Alleman Aug 04 '19 at 15:54
  • 1
    That's not a hard task - just add one more parameter to shader and multiply it inside. If you see https://code.woboq.org/qt5/qt3d/src/extras/defaults/qtexturematerial.cpp.html , there is `m_textureTransformParameter(new QParameter(QStringLiteral("texCoordTransform"), qVariantFromValue(QMatrix3x3())))` and then https://github.com/qt/qt3d/blob/5.12/src/extras/shaders/gl3/unlittexture.vert -> you'll see how that `texCoordTransform` is used. – Konstantine Kozachuck Aug 04 '19 at 20:59