gpt4 book ai didi

python - 如何在 Kivy 中将纹理绑定(bind)到 3D 网格?

转载 作者:行者123 更新时间:2023-12-01 06:22:32 24 4
gpt4 key购买 nike

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

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

看来我已经成功地将纹理坐标传递给着色器了,因为当我仅使用纹理坐标作为颜色值进行渲染时(使用着色器代码末尾附近的注释行),我得到了一个多色对象。但是,当我将这些纹理坐标放置在texture2D() 调用中时,该对象将被渲染为根本没有纹理。

根据BindTexture文档:

The BindTexture Instruction will bind a texture and enable GL_TEXTURE_2D for subsequent drawing.

所以看起来这应该非常简单,但我显然错过了一些东西。

我是 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);
}

最佳答案

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

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

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;
}

关于python - 如何在 Kivy 中将纹理绑定(bind)到 3D 网格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60293436/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com