texture can't repeat properly?

Discussion in 'Programming' started by kaito, Oct 5, 2018.

  1. kaito

    kaito Member

    Joined:
    Aug 29, 2017
    Posts:
    21
    i have Hrepeat and Vrepeat set to 3 but it draws texture page?
    d3d_draw_floor(0,0,0,100,100,0,sprite_get_texture(s_wall,0),3,3)
    i.PNG
    why it is not repeating 1 image 3 times?
     
  2. flyingsaucerinvasion

    flyingsaucerinvasion Member

    Joined:
    Jun 20, 2016
    Posts:
    1,706
    you'll need to put the image on its own texture page. There is an option to do so in the sprite editor. Check "used for 3d".
     
  3. kaito

    kaito Member

    Joined:
    Aug 29, 2017
    Posts:
    21
    @flyingsaucerinvasion the thing is that i have like 30 images in one sprite (s_wall) and i need to draw all of them.
    if am gonna check (used for 3d) then it's gonna create new texture page for each of them right?
    is it ok to have that many texture pages?
     
  4. flyingsaucerinvasion

    flyingsaucerinvasion Member

    Joined:
    Jun 20, 2016
    Posts:
    1,706
    the problem is that d3d_draw_floor isn't going to be compatible with any other way of repeating the textures.

    What you could do instead is put the floor geometry into a vertex buffer, and then you could supply extra vertex data that informs a custom shader on how to repeat parts of a texture atlas.

    See spoiler for an example:
    setup:
    Code:
    //======================================================
        //vertex format
        vertex_format_begin();
        vertex_format_add_position_3d();
        vertex_format_add_textcoord();
        vertex_format_add_custom( vertex_type_float4, vertex_usage_textcoord );  //vec4 that will be put into a second texture coordinates attribute
        vf_world = vertex_format_end();
    //----------------------------------------
        //note: texture atlas doesn't have to be a background, can be sprite or surface just as well
        tex_world = background_get_texture( bck_world );
        //width and height of texture measured in pixels
        var _tex_w = background_get_width( background_bricks );
        var _tex_h = background_get_height( background_bricks );
    //----------------------------------------
        vb_world = vertex_create_buffer();
        vertex_begin( vb_world, vf_world );
    //----------------------------------------
        //top-left corner of rectangular section of texture to repeat, measured in pixels
        var _image_x = 1;
        var _image_y = 1;
        //width and height of section, measured in pixels
        var _image_w = 32;
        var _image_h = 32;
        //-----------------
        //location of sides of section, measured in texture coordinates
        var _l = _image_x / _tex_w;
        var _t = _image_y / _tex_h;
        var _r = _l + _image_w / _tex_w;
        var _b = _t + _image_h / _tex_h;
        //width of section, measured in texture coordinates
        var _w = _r - _l;
        var _h = _b - _t;
        //used to scale position of vertex to get texture coordinates
        //can invert sign of _p and or _q to flip the texture along an one or both axes
        var _p = _w / _image_w;
        var _q = _h / _image_h;
        //-----------------
        var _x0, _y0, _x1, _y1;
        var _vb = vb_world; //copy pointer to vertex buffer into temporary variable (so don't need to use other.vb_world)
        //note: don't need to use objects to define location of floors.
        with (obj_floor) {
            //-x,-y corner of floor
            _x0 = x;
            _y0 = y;
            //+x,+y corner of floor
            _x1 = x + sprite_width;
            _y1 = y + sprite_height;
            //-----------------
                //+x,+y triangle
                vertex_position_3d( _vb, _x0, _y0, 0 );
                vertex_texcoord( _vb, _x0 * _p, _y0 * _q ); //texture coordinates
                vertex_float4( _vb, _w, _h, _l, _t ); //used in shader to wrap texture
                //-----------------
                vertex_position_3d( _vb, _x1, _y0, 0 );
                vertex_texcoord( _vb, _x1 * _p, _y0 * _q ); //texture coordinates
                vertex_float4( _vb, _w, _h, _l, _t ); //used in shader to wrap texture
                //-----------------
                vertex_position_3d( _vb, _x1, _y1, 0 );
                vertex_texcoord( _vb, _x1 * _p, _y1 * _q ); //texture coordinates
                vertex_float4( _vb, _w, _h, _l, _t ); //used in shader to wrap texture
            //-----------------
                //-x,-y triangle
                vertex_position_3d( _vb, _x0, _y0, 0 );
                vertex_texcoord( _vb, _x0 * _p, _y0 * _q ); //texture coordinates
                vertex_float4( _vb, _w, _h, _l, _t ); //used in shader to wrap texture
                //-----------------
                vertex_position_3d( _vb, _x1, _y1, 0 );
                vertex_texcoord( _vb, _x1 * _p, _y1 * _q ); //texture coordinates
                vertex_float4( _vb, _w, _h, _l, _t ); //used in shader to wrap texture 
                //-----------------
                vertex_position_3d( _vb, _x0, _y1, 0 );
                vertex_texcoord( _vb, _x0 * _p, _y1 * _q ); //texture coordinates
                vertex_float4( _vb, _w, _h, _l, _t ); //used in shader to wrap texture             
        }
    //----------------------------------------
        vertex_end( vb_world );
        vertex_freeze( vb_world );
    //======================================================
    
    draw event:
    Code:
    //======================================================
        shader_set(sh_repeat_textures);
        vertex_submit( vb_wall, pr_trianglelist, tex_bricks );
        shader_reset();
    //======================================================
    
    vertex shader:
    Code:
    //======================================================
        attribute vec3 in_Position;
        attribute vec2 in_Textcoord0;
        attribute vec4 in_Textcoord1;
        varying vec2 v_vTexcoord;
        varying vec4 v_vRepeat;
        void main(){
            gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * vec4( in_Position, 1.0 );
            v_vTexcoord = in_Textcoord0;
            v_vRepeat = in_Textcoord1;
        }
    //======================================================
    
    fragment shader:
    Code:
    //======================================================
        varying vec2 v_vTexcoord;
        varying vec4 v_vRepeat;
        void main(){
            gl_FragColor = texture2D( gm_BaseTexture, v_vTexcoord - floor( v_vTexcoord / v_vRepeat.xy ) * v_vRepeat.xy + v_vRepeat.zw );
        }
    //======================================================
    

    When designing your textures, you don't want colors from adjacent parts of the atlas to bleed through at the seams. So, you'll need to put a buffer around each section. The border contains the colors on the opposite side of the section. It's a bit hard to explain, so here's a picture that illustrates what I'm talking about. There is a 32x32 section, with a 1 pixel wide border surrounding it. The colors in the picture represent the coordinates of the section.
    upload_2018-10-5_15-26-5.png
     
    Last edited: Oct 5, 2018
    kaito likes this.
  5. kaito

    kaito Member

    Joined:
    Aug 29, 2017
    Posts:
    21
    @flyingsaucerinvasion Thanks, I know nothing about the vertex buffer or shaders, so I will try to figure it out.
    and just so you know, i am using 1.4
     
  6. flyingsaucerinvasion

    flyingsaucerinvasion Member

    Joined:
    Jun 20, 2016
    Posts:
    1,706
    I can't think of any other way of doing this without using a vertex buffer and shader. If what I outlined above doesn't make complete sense, just reply below, and I'll try to clarify.
     
  7. kaito

    kaito Member

    Joined:
    Aug 29, 2017
    Posts:
    21
  8. flyingsaucerinvasion

    flyingsaucerinvasion Member

    Joined:
    Jun 20, 2016
    Posts:
    1,706
    As long as it works for you, it's ok, except if you happen to run into performance problems, which seems unlikely unless you're drawing a ton of different floor parts.

    A few points that could help you later on, they won't necessarily make a difference here, but in the future they could help. In general you want to break the current vertex batch as few times as possible. Setting uniforms or matrices (which are also uniforms), will break the batch. Also, in most cases, you'll probably want to avoid using loops in your shader if you can accomplish the same thing with fewer instructions. And finally, submitting an already written vertex buffer is going to be a whole lot faster than drawing new primitives. (i actually totally forgot the d3d_vertex_ functions existed) . Again,these things might not make much of a difference in this particular case, but keeping them in mind could save your bacon in the future.

    EDIT: By the way, after reviewing the implementation of "mod" in glsles, I realized that mod(x,y) does exactly the same as x - y * floor( x/y ). I had originally thought mod would not work with negative numbers here, but I was wrong. So, the one line in my fragment shader can be reduced, for ease of readability, to: gl_FragColor = texture2D( gm_BaseTexture, mod(v_vTexcoord, v_vRepeat.xy ) + v_vRepeat.zw );
     
    Last edited: Oct 9, 2018
  9. kaito

    kaito Member

    Joined:
    Aug 29, 2017
    Posts:
    21
    @flyingsaucerinvasion thanks. i did not get some of the things in your method, because i am new to this, but eventually i will try to do it.
    I'm going to copy and paste modified code of 3d model, that i created in blender, into draw event, and see what up with the performance.
     
  10. flyingsaucerinvasion

    flyingsaucerinvasion Member

    Joined:
    Jun 20, 2016
    Posts:
    1,706
    eh? hat's that about a blender model? You'll need some kind of a script to import it. Unless you're talking about translating blender python code into gml.
     
  11. kaito

    kaito Member

    Joined:
    Aug 29, 2017
    Posts:
    21
    @flyingsaucerinvasion i just made a little program in game maker that translates model.obj code like vertex positions into game maker.
    c2.PNG
    pol is a script for rotation. just image insted of pol d3d_vertex(x,y,z)
    c3.PNG
    it's just a little spaceship.
    now i want to upgrade it, to translate textures as well.
     
  12. flyingsaucerinvasion

    flyingsaucerinvasion Member

    Joined:
    Jun 20, 2016
    Posts:
    1,706
    you should consider switching to using vertex buffers. They're going to be way faster for something like that. They're not difficult to use.
     
  13. kaito

    kaito Member

    Joined:
    Aug 29, 2017
    Posts:
    21
    @flyingsaucerinvasion in your code you don't have background_get_uvs()
    so that means that i need to check (used for 3d)
    and it's not gonna create another texture page unless i use something like d3d_draw_floor or d3d_vertex_texture is that right?
    guess i can't have textures in one sprite, because my textures don't have same size, so i need to use a bunch of backgrounds.
    this is what i have so far.
    c1.png
    c2.png
    so i need to create new vertex buffer for every texture that i have right?
     
  14. flyingsaucerinvasion

    flyingsaucerinvasion Member

    Joined:
    Jun 20, 2016
    Posts:
    1,706
    whoa... hold on there. You definitely can put your different images in the same texture, and you can use the same vertex buffer for all of them (as long as they are using the same texture). That was the whole point of this topic.

    You may use sprite_get_uvs or background_get_uvs to get the values of the left, top, right, and bottom sides:

    var _uvs = sprite_get_uvs(some_sprite,some_sub_image);
    var _l = _uvs[0];
    var _t = _uvs[1];
    var _r = _uvs[2];
    var _b = _uvs[3];

    Make sure all your sprites and or backgrounds are located on the same texture page though!

    Also, make sure you check "tile: horizontally" and "tile: vertically" in the sprite or background editor. Otherwise there will be visible seams.

    ---------

    The vertex format I designed carries both the texture coordinates of each vertex as well as information the shader can use to wrap the texture coordinates within a rectangular area

    vertex_position_3d( _vb, _x0, _y0, 0 );
    vertex_texcoord( _vb, _x0 * _p, _y0 * _q ); //texture coordinates
    vertex_float4( _vb, _w, _h, _l, _t ); //used in shader to wrap texture

    Since you're making floor pieces, it makes sense for the texture coordinates to be some multiple of the x and y position coordinats. The values of _p and _q are here calculated so that the texture will be scaled to be 1 texel (pixel in the texture) = 1 unit of area in the room. However, you can scale by any amount that you want.

    -------------

    If this isn't making sense yet, I could throw together a demo project. It might make it easier to see everything put altogether in working order.
     
  15. kaito

    kaito Member

    Joined:
    Aug 29, 2017
    Posts:
    21
    @flyingsaucerinvasion a demo would be great.
    put all my images that are in one sprite to a texture? i didn't even know that was a thing.
     
  16. flyingsaucerinvasion

    flyingsaucerinvasion Member

    Joined:
    Jun 20, 2016
    Posts:
    1,706
    This is for GMS1.4 pro... if you don't have the pro version, what you'll need to do is compile your own texture atlas in an image editor, and then manually measure uvs of sections of that atlas. Otherwise you couldn't be sure that different sprites and or backgrounds will necessarily end up on the same texture page.

    https://www.dropbox.com/s/rt1303d4k3v8yto/repeat_texture_demo.gmz?dl=0
     
  17. kaito

    kaito Member

    Joined:
    Aug 29, 2017
    Posts:
    21

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice