код C ++ из примера
vmath::mat4 plane_matrix = vmath::rotate(f * 6.0f, 1.0f, 0.0f, 0.0f) *
vmath::rotate(f * 7.3f, 0.0f, 1.0f, 0.0f);
соответствует следующему коду Python
RX = (GLfloat * 16)(*identityMatrix)
m3dRotationMatrix44(RX, f * 6.0, 1.0, 0.0, 0.0)
RY = (GLfloat * 16)(*identityMatrix)
m3dRotationMatrix44(RY, f * 7.3, 0.0, 1.0, 0.0)
plane_matrix = (GLfloat * 16)(*identityMatrix)
plane_matrix = m3dMultiply(RX , RY)
Обратите внимание, вы должны поменять местами RX
и RY
в умножении матриц.
Ваши функции length
и normalize
могут работать только с векторами, которые имеют 3 компонента (x, y, z) . Для сравнения функция C ++ vmath::normalize
из примера может обрабатывать векторы с 4 компонентами (x, y, z, w) .
Кроме того, обработка "деление на ноль" отсутствует в normalize
.
Адаптируйте функции normalize
и length
для работы с любым векторным размером.
Если длина вектора равна 0, то все его компоненты равны 0. Для этого нет правильного решения, поэтому просто верните копию самого вектора.
def length(v):
sum_sq = sum([s*s for s in v])
return math.sqrt(sum_sq)
def normalize(v):
l = length(v)
if l == 0.0:
return v[:]
return [s/l for s in v]
Теперь вы можете портировать код C ++ из примера
vmath::vec4 plane = plane_matrix[0];
plane[3] = 0.0f;
plane = vmath::normalize(plane);
очень прямо к питону:
plane = plane_matrix[0:4]
plane[3] = 0
plane = normalize(plane)
Далее, есть проблема в модуле sbmloader
.
Указан только массив координат вершин и текстурных координат. Нормальные векторы пропускаются.
Просто пропустите строку
if attrib.name=='position' or attrib.name=='map1':
чтобы исправить проблему:
for attrib_i, attrib in enumerate(vertex_attrib_chunk.attrib_data):
#if attrib.name=='position' or attrib.name=='map1':
glVertexAttribPointer(attrib_i,
attrib.size, attrib.type,
GL_TRUE if (attrib.flags & SB6M_VERTEX_ATTRIB_FLAG_NORMALIZED) != 0 else GL_FALSE,
attrib.stride, ctypes.c_void_p(int(attrib.data_offset)))
glEnableVertexAttribArray(attrib_i)
Если вы хотите дополнительно обернуть текстуру в модель, вам нужно добавить атрибут координат текстуры в вершинный шейдер:
layout (location = 2) in vec2 tc;
И передать его выводом на следующий этап шейдера
out VS_OUT
{
vec3 N;
vec3 L;
vec3 V;
vec2 T;
} vs_out;
void main()
{
// ...
vs_out.T = tc;
// ...
}
В фрагментный шейдер вы должны добавить равномерный сэмплер текстуры
layout (binding = 0) uniform sampler2D tex;
Прочитайте цвет формы текстуры
vec4 texColor = texture(tex, fs_in.T);
Умножить выходной цвет на цвет текстуры
color = vec4(diffuse + specular + rim, 1.0) * texColor;
Фрагмент шейдера (заметьте, я изменил diffuse_albedo
):
#version 420 core
// Output
layout (location = 0) out vec4 color;
// Input from vertex shader
in VS_OUT
{
vec3 N;
vec3 L;
vec3 V;
vec2 T;
} fs_in;
// Material properties
uniform vec3 diffuse_albedo = vec3(0.5);
uniform vec3 specular_albedo = vec3(0.7);
uniform float specular_power = 128.0;
uniform vec3 rim_color = vec3(0.1, 0.2, 0.2);
uniform float rim_power = 5.0;
layout (binding = 0) uniform sampler2D tex;
vec3 calculate_rim(vec3 N, vec3 V)
{
float f = 1.0 - dot(N, V);
f = smoothstep(0.0, 1.0, f);
f = pow(f, rim_power);
return f * rim_color;
}
void main(void)
{
// Normalize the incoming N, L and V vectors
vec3 N = normalize(fs_in.N);
vec3 L = normalize(fs_in.L);
vec3 V = normalize(fs_in.V);
// Calculate R locally
vec3 R = reflect(-L, N);
// Compute the diffuse and specular components for each fragment
vec3 diffuse = max(dot(N, L), 0.0) * diffuse_albedo;
vec3 specular = pow(max(dot(R, V), 0.0), specular_power) * specular_albedo;
vec3 rim = calculate_rim(N, V);
// read color from the texture
vec4 texColor = texture(tex, fs_in.T);
// Write final color to the framebuffer
color = vec4(diffuse + specular + rim, 1.0) * texColor;
}
Я рекомендую добавить шейдерную компиляцию и регистрацию ошибок ссылок:
glCompileShader(result)
if not glGetShaderiv(result, GL_COMPILE_STATUS):
print( 'compile error:' )
print( glGetShaderInfoLog(result) )
glLinkProgram(program)
if not glGetProgramiv(program, GL_LINK_STATUS):
print( 'link error:' )
print( glGetProgramInfoLog(program) )
Чтение текстуры при инициализации приложения
class Scene:
def __init__(self, width, height):
global myobject, tex_dragon
myobject.load("dragon.sbm")
load_shaders()
ktxobj = KTXObject()
tex_dragon = ktxobj.ktx_load("texture_file_name.ktx")
Привязать текстуру перед рисованием модели
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, tex_dragon)
myobject.render()