【发布时间】: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