shenjack
f9eeafe322
readme update 看起来更像 Dear ImGui 一些(looks more like Dear ImGui and some intersting feature to the button remove debug 确认一下action 404 修改 writing theme looks good better? a ? alpha=255 not 256 looks better try new pyglet first 看起来好一些 sync pyglet 水一手 这波必须得水一手了,要不然commit太少了(确信 丢点正经东西上去 顺手继承一下Options 补充docs 坏了,忘记水commit了( 至少我能早睡了( 这里还能水一点来着( 试试再说 reee 保证能跑( 同步lib not dr 的修改 忘记带上 None了 还是加上一个额外的判断参数吧 刷点commit也不错 先更新一下依赖版本 水commit啦 理论可行,实践开始! 构建参数喜加一 reeeee 更新一下 pyproject 的依赖 fix typing looks better 水一个( 测试? sync pyglet to master A | Try use rust-cache looks good? what? C | sync pyglet A | 添加了一个 Button Draw Theme A | Magic Number (确信) A | 尽量不继承Options sync pyglet A | Add theme A | Add more Theme information Enhance | Theme sync pyglet Add | add unifont Enhance | use os.walk in font loading Enhance | Use i18n in font loading Enhance | doc sync pyglet Add | add 3.12 build option to build_rs Fix | Button position have a z sync pyglet A | Logger.py 启动! sync pyglet Changed | Bump pyo3 to 0.20.0 add logger.py update logger! Add | more logger! Add | lib-not-dr some lib-not-dr
322 lines
9.1 KiB
Python
322 lines
9.1 KiB
Python
"""Loading of 3D models.
|
|
|
|
A :py:class:`~pyglet.model.Model` is an instance of a 3D object.
|
|
|
|
The following example loads a ``"teapot.obj"`` model::
|
|
|
|
import pyglet
|
|
|
|
window = pyglet.window.Window()
|
|
|
|
teapot = pyglet.model.load('teapot.obj')
|
|
|
|
@window.event
|
|
def on_draw():
|
|
teapot.draw()
|
|
|
|
pyglet.app.run()
|
|
|
|
|
|
You can also load models with :py:meth:`~pyglet.resource.model`.
|
|
See :py:mod:`~pyglet.resource` for more information.
|
|
|
|
|
|
Efficient Drawing
|
|
=================
|
|
|
|
As with Sprites or Text, Models can be added to a
|
|
:py:class:`~pyglet.graphics.Batch` for efficient drawing. This is
|
|
preferred to calling their ``draw`` methods individually. To do this,
|
|
simply pass in a reference to the :py:class:`~pyglet.graphics.Batch`
|
|
instance when loading the Model::
|
|
|
|
|
|
import pyglet
|
|
|
|
window = pyglet.window.Window()
|
|
batch = pyglet.graphics.Batch()
|
|
|
|
teapot = pyglet.model.load('teapot.obj', batch=batch)
|
|
|
|
@window.event
|
|
def on_draw():
|
|
batch.draw()
|
|
|
|
pyglet.app.run()
|
|
|
|
|
|
.. versionadded:: 1.4
|
|
"""
|
|
|
|
import pyglet
|
|
|
|
from pyglet import gl
|
|
from pyglet import graphics
|
|
from pyglet.gl import current_context
|
|
from pyglet.math import Mat4, Vec3
|
|
from pyglet.graphics import shader
|
|
|
|
from .codecs import registry as _codec_registry
|
|
from .codecs import add_default_codecs as _add_default_codecs
|
|
|
|
|
|
def load(filename, file=None, decoder=None, batch=None, group=None):
|
|
"""Load a 3D model from a file.
|
|
|
|
:Parameters:
|
|
`filename` : str
|
|
Used to guess the model format, and to load the file if `file` is
|
|
unspecified.
|
|
`file` : file-like object or None
|
|
Source of model data in any supported format.
|
|
`decoder` : ModelDecoder or None
|
|
If unspecified, all decoders that are registered for the filename
|
|
extension are tried. An exception is raised if no codecs are
|
|
registered for the file extension, or if decoding fails.
|
|
`batch` : Batch or None
|
|
An optional Batch instance to add this model to.
|
|
`group` : Group or None
|
|
An optional top level Group.
|
|
|
|
:rtype: :py:mod:`~pyglet.model.Model`
|
|
"""
|
|
if decoder:
|
|
return decoder.decode(filename, file, batch=batch, group=group)
|
|
else:
|
|
return _codec_registry.decode(filename, file, batch=batch, group=group)
|
|
|
|
|
|
def get_default_shader():
|
|
return pyglet.gl.current_context.create_program((MaterialGroup.default_vert_src, 'vertex'),
|
|
(MaterialGroup.default_frag_src, 'fragment'))
|
|
|
|
def get_default_textured_shader():
|
|
return pyglet.gl.current_context.create_program((TexturedMaterialGroup.default_vert_src, 'vertex'),
|
|
(TexturedMaterialGroup.default_frag_src, 'fragment'))
|
|
|
|
|
|
class Model:
|
|
"""Instance of a 3D object.
|
|
|
|
See the module documentation for usage.
|
|
"""
|
|
|
|
def __init__(self, vertex_lists, groups, batch):
|
|
"""Create a model.
|
|
|
|
:Parameters:
|
|
`vertex_lists` : list
|
|
A list of `~pyglet.graphics.VertexList` or
|
|
`~pyglet.graphics.IndexedVertexList`.
|
|
`groups` : list
|
|
A list of `~pyglet.model.TexturedMaterialGroup`, or
|
|
`~pyglet.model.MaterialGroup`. Each group corresponds to
|
|
a vertex list in `vertex_lists` of the same index.
|
|
`batch` : `~pyglet.graphics.Batch`
|
|
Optional batch to add the model to. If no batch is provided,
|
|
the model will maintain its own internal batch.
|
|
"""
|
|
self.vertex_lists = vertex_lists
|
|
self.groups = groups
|
|
self._batch = batch
|
|
self._modelview_matrix = Mat4()
|
|
|
|
@property
|
|
def batch(self):
|
|
"""The graphics Batch that the Model belongs to.
|
|
|
|
The Model can be migrated from one batch to another, or removed from
|
|
a batch (for individual drawing). If not part of any batch, the Model
|
|
will keep its own internal batch. Note that batch migration can be
|
|
an expensive operation.
|
|
|
|
:type: :py:class:`pyglet.graphics.Batch`
|
|
"""
|
|
return self._batch
|
|
|
|
@batch.setter
|
|
def batch(self, batch):
|
|
if self._batch == batch:
|
|
return
|
|
|
|
if batch is None:
|
|
batch = graphics.Batch()
|
|
|
|
for group, vlist in zip(self.groups, self.vertex_lists):
|
|
self._batch.migrate(vlist, gl.GL_TRIANGLES, group, batch)
|
|
|
|
self._batch = batch
|
|
|
|
@property
|
|
def matrix(self):
|
|
return self._modelview_matrix
|
|
|
|
@matrix.setter
|
|
def matrix(self, matrix):
|
|
self._modelview_matrix = matrix
|
|
for group in self.groups:
|
|
group.matrix = matrix
|
|
|
|
def draw(self):
|
|
"""Draw the model.
|
|
|
|
This is not recommended. See the module documentation
|
|
for information on efficient drawing of multiple models.
|
|
"""
|
|
gl.current_context.window_block.bind(0)
|
|
self._batch.draw_subset(self.vertex_lists)
|
|
|
|
|
|
class Material:
|
|
__slots__ = ("name", "diffuse", "ambient", "specular", "emission", "shininess", "texture_name")
|
|
|
|
def __init__(self, name, diffuse, ambient, specular, emission, shininess, texture_name=None):
|
|
self.name = name
|
|
self.diffuse = diffuse
|
|
self.ambient = ambient
|
|
self.specular = specular
|
|
self.emission = emission
|
|
self.shininess = shininess
|
|
self.texture_name = texture_name
|
|
|
|
def __eq__(self, other):
|
|
return (self.name == other.name and
|
|
self.diffuse == other.diffuse and
|
|
self.ambient == other.ambient and
|
|
self.specular == other.specular and
|
|
self.emission == other.emission and
|
|
self.shininess == other.shininess and
|
|
self.texture_name == other.texture_name)
|
|
|
|
|
|
class BaseMaterialGroup(graphics.Group):
|
|
default_vert_src = None
|
|
default_frag_src = None
|
|
matrix = Mat4()
|
|
|
|
def __init__(self, material, program, order=0, parent=None):
|
|
super().__init__(order, parent)
|
|
self.material = material
|
|
self.program = program
|
|
|
|
|
|
class TexturedMaterialGroup(BaseMaterialGroup):
|
|
default_vert_src = """#version 330 core
|
|
in vec3 position;
|
|
in vec3 normals;
|
|
in vec2 tex_coords;
|
|
in vec4 colors;
|
|
|
|
out vec4 vertex_colors;
|
|
out vec3 vertex_normals;
|
|
out vec2 texture_coords;
|
|
out vec3 vertex_position;
|
|
|
|
uniform WindowBlock
|
|
{
|
|
mat4 projection;
|
|
mat4 view;
|
|
} window;
|
|
|
|
uniform mat4 model;
|
|
|
|
void main()
|
|
{
|
|
vec4 pos = window.view * model * vec4(position, 1.0);
|
|
gl_Position = window.projection * pos;
|
|
mat3 normal_matrix = transpose(inverse(mat3(model)));
|
|
|
|
vertex_position = pos.xyz;
|
|
vertex_colors = colors;
|
|
texture_coords = tex_coords;
|
|
vertex_normals = normal_matrix * normals;
|
|
}
|
|
"""
|
|
default_frag_src = """#version 330 core
|
|
in vec4 vertex_colors;
|
|
in vec3 vertex_normals;
|
|
in vec2 texture_coords;
|
|
in vec3 vertex_position;
|
|
out vec4 final_colors;
|
|
|
|
uniform sampler2D our_texture;
|
|
|
|
void main()
|
|
{
|
|
float l = dot(normalize(-vertex_position), normalize(vertex_normals));
|
|
final_colors = (texture(our_texture, texture_coords) * vertex_colors) * l * 1.2;
|
|
}
|
|
"""
|
|
|
|
def __init__(self, material, program, texture, order=0, parent=None):
|
|
super().__init__(material, program, order, parent)
|
|
self.texture = texture
|
|
|
|
def set_state(self):
|
|
gl.glActiveTexture(gl.GL_TEXTURE0)
|
|
gl.glBindTexture(self.texture.target, self.texture.id)
|
|
self.program.use()
|
|
self.program['model'] = self.matrix
|
|
|
|
def __hash__(self):
|
|
return hash((self.texture.target, self.texture.id, self.program, self.order, self.parent))
|
|
|
|
def __eq__(self, other):
|
|
return (self.__class__ is other.__class__ and
|
|
self.material == other.material and
|
|
self.texture.target == other.texture.target and
|
|
self.texture.id == other.texture.id and
|
|
self.program == other.program and
|
|
self.order == other.order and
|
|
self.parent == other.parent)
|
|
|
|
|
|
class MaterialGroup(BaseMaterialGroup):
|
|
default_vert_src = """#version 330 core
|
|
in vec3 position;
|
|
in vec3 normals;
|
|
in vec4 colors;
|
|
|
|
out vec4 vertex_colors;
|
|
out vec3 vertex_normals;
|
|
out vec3 vertex_position;
|
|
|
|
uniform WindowBlock
|
|
{
|
|
mat4 projection;
|
|
mat4 view;
|
|
} window;
|
|
|
|
uniform mat4 model;
|
|
|
|
void main()
|
|
{
|
|
vec4 pos = window.view * model * vec4(position, 1.0);
|
|
gl_Position = window.projection * pos;
|
|
mat3 normal_matrix = transpose(inverse(mat3(model)));
|
|
|
|
vertex_position = pos.xyz;
|
|
vertex_colors = colors;
|
|
vertex_normals = normal_matrix * normals;
|
|
}
|
|
"""
|
|
default_frag_src = """#version 330 core
|
|
in vec4 vertex_colors;
|
|
in vec3 vertex_normals;
|
|
in vec3 vertex_position;
|
|
out vec4 final_colors;
|
|
|
|
void main()
|
|
{
|
|
float l = dot(normalize(-vertex_position), normalize(vertex_normals));
|
|
final_colors = vertex_colors * l * 1.2;
|
|
}
|
|
"""
|
|
|
|
def set_state(self):
|
|
self.program.use()
|
|
self.program['model'] = self.matrix
|
|
|
|
|
|
_add_default_codecs()
|