【问题标题】:How to Bind a texture to a 3D mesh in Kivy?如何在 Kivy 中将纹理绑定到 3D 网格?
【发布时间】:2020-02-19 21:39:43
【问题描述】:

我正在尝试以 Kivy 的 3D Rotating Monkey Head 为例并对其应用纹理。

似乎 Kivy 的图形上下文“BindTexture() 方法应该可以解决问题,但它似乎没有效果。我修改了示例以在 init() 方法中包含对“BindTexture()”的调用。我还更改了着色器代码包括纹理。

似乎我已经设法将纹理坐标传递给着色器就好了,因为当我只使用纹理坐标作为颜色值进行渲染时(使用着色器代码末尾附近的注释行),我得到一个多色对象.但是,当我将这些纹理坐标放置在 texture2D() 调用中时,渲染的对象根本没有纹理。

根据BindTexture 文档:

BindTexture 指令将绑定纹理并启用 GL_TEXTURE_2D 用于后续绘制。

所以看起来应该很简单,但我显然遗漏了一些东西。

我是 Kivy 和 OpenGL 的新手。我真正苦苦挣扎的一件事是如何将值传递给 GL 着色器代码中的输入变量。例如,在我的着色器代码中,变量“texture0”用于相关纹理 - 但是,我不确定它是如何映射到我的纹理的。根据我看到的一些示例,例如Kivy's multitexture 示例,似乎“BindTexture()”应该解决这个问题,但我有点不舒服,这一切对我来说似乎都是黑魔法。

main.py:

from kivy.clock import Clock
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.graphics import RenderContext, Color, Rectangle, BindTexture

class Renderer(Widget):
    def __init__(self, **kwargs):
        self.canvas = RenderContext(compute_normal_mat=True)
        # self.canvas.shader.source = resource_find('default.glsl')
        self.canvas.shader.source = resource_find('simple.glsl')
        self.scene = ObjFile(resource_find("monkey.obj"))
        BindTexture(source='mtexture2.png')


        super(Renderer, self).__init__(**kwargs)
        with self.canvas:
            self.cb = Callback(self.setup_gl_context)
            PushMatrix()
            self.setup_scene()
            PopMatrix()
            self.cb = Callback(self.reset_gl_context)
            BindTexture(source='mtexture2.png')


        self.canvas['texture0'] = 0

        Clock.schedule_interval(self.update_glsl, 1 / 60.)

    def setup_gl_context(self, *args):
        glEnable(GL_DEPTH_TEST)

    def reset_gl_context(self, *args):
        glDisable(GL_DEPTH_TEST)

    def update_glsl(self, delta):
        asp = self.width / float(self.height)
        proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1)
        # Color(1,0,0)
        self.canvas['projection_mat'] = proj
        self.canvas['diffuse_light'] = (1.0, 0.0, 0.8)
        self.canvas['ambient_light'] = (0.1, 0.1, 0.1)
        self.rot.angle += delta * 100


    def setup_scene(self):
        Color(1, 1, 1)
        PushMatrix()
        Translate(0, -2.5, -8)
        self.rot = Rotate(1, 0, 1, 0)
        UpdateNormalMatrix()
        for m in list(self.scene.objects.values()):
            self.mesh = Mesh(
                vertices=m.vertices,
                indices=m.indices,
                fmt=m.vertex_format,
                mode='triangles',
            )
        PopMatrix()


class RendererApp(App):
    def build(self):
        return Renderer()


if __name__ == "__main__":
    RendererApp().run()

着色器代码“simple.glsl”:

/* simple.glsl

simple diffuse lighting based on laberts cosine law; see e.g.:
    http://en.wikipedia.org/wiki/Lambertian_reflectance
    http://en.wikipedia.org/wiki/Lambert%27s_cosine_law
*/
---VERTEX SHADER-------------------------------------------------------
#ifdef GL_ES
    precision highp float;
#endif


/* Vertex attributes/inputs, defined in MeshData Object */
attribute vec3  v_pos;
attribute vec3  v_normal;
attribute vec2  v_tc0;

/* Outputs to the fragment shader */
varying vec2 tex_coord0;
varying vec4 normal_vec;
varying vec4 vertex_pos;

uniform mat4 modelview_mat;
uniform mat4 projection_mat;

void main (void) {
    //compute vertex position in eye_space and normalize normal vector
    vec4 pos = modelview_mat * vec4(v_pos,1.0);
    vertex_pos = pos;
    normal_vec = vec4(v_normal,0.0);
    gl_Position = projection_mat * pos;

    tex_coord0 = v_tc0;
}


---FRAGMENT SHADER-----------------------------------------------------
#ifdef GL_ES
    precision highp float;
#endif

/* Outputs from Vertex Shader */
varying vec4 normal_vec;
varying vec4 vertex_pos;
varying vec2 tex_coord0;

uniform sampler2D texture0;

uniform mat4 normal_mat;

void main (void){
    //correct normal, and compute light vector (assume light at the eye)
    vec4 v_normal = normalize( normal_mat * normal_vec ) ;
    vec4 v_light = normalize( vec4(0,0,0,1) - vertex_pos );
    //reflectance based on lamberts law of cosine
    float theta = clamp(dot(v_normal, v_light), 0.0, 1.0);
    //gl_FragColor = vec4(theta, theta, theta, 1.0)*vec4(tex_coord0, 1, 1);
    gl_FragColor = vec4(theta, theta, theta, 1.0)*texture2D(texture0, tex_coord0);
}

【问题讨论】:

  • @Rabbid76 着色器如何知道纹理索引?是名称“textureN”,其中“N”是纹理索引吗?在“BindTexture()”调用中添加“index=0”无效。

标签: python opengl kivy shader textures


【解决方案1】:

纹理对象和纹理采样器制服之间的绑定点是纹理单元。纹理对象绑定到纹理单元,纹理单元的索引设置为纹理采样器统一。我不知道使用 kivy 是如何工作的。采样器的初始值为 0。如果纹理绑定到纹理单元 0,它应该可以工作。纹理由BindTexture(source='mtexture2.png')绑定到纹理单元,纹理单元由self.canvas['texture0'] = 0分配给采样器制服。

使用纹理单元 0 时似乎存在问题。请改用纹理单元 1。
绑定setup_scene中的纹理,并将值设置为update_glsl中的采样器统一:

class Renderer(Widget):
    # [...]

    def update_glsl(self, delta):
        asp = self.width / float(self.height)
        proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1)
        self.canvas['texture0'] = 1 # <------------------------------  
        self.canvas['projection_mat'] = proj
        self.canvas['diffuse_light'] = (1.0, 0.0, 0.8)
        self.canvas['ambient_light'] = (0.1, 0.1, 0.1)
        self.rot.angle += delta * 100

    def setup_scene(self):
        BindTexture(source='mtexture2.png', index=1) # <-------------
        Color(1, 1, 1)
        PushMatrix()
        Translate(0, -2.5, -8)
        self.rot = Rotate(1, 0, 1, 0)
        UpdateNormalMatrix()
        for m in list(self.scene.objects.values()):
            self.mesh = Mesh(
                vertices=m.vertices,
                indices=m.indices,
                fmt=m.vertex_format,
                mode='triangles',
            )
        PopMatrix()

另一个问题是“monkey.obj”没有纹理坐标(vt 条目)。所以所有顶点的纹理坐标属性默认为 (0, 0)。
通过顶点着色器中的法线向量模拟纹理坐标。例如:

void main (void) {
    // [...]

    tex_coord0 = v_normal.xz * 0.5 + 0.5;
}

【讨论】:

    猜你喜欢
    • 2018-05-30
    • 1970-01-01
    • 1970-01-01
    • 2017-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-28
    • 1970-01-01
    相关资源
    最近更新 更多