Я использую vispy для рендеринга трехмерных параметрических поверхностей с помощью OpenGL. Похоже, по большей части это работает хорошо, но выглядит странно
в некоторых частях по краям геометриипочти как если бы нормали указывали внутрь ( пример ).
Я подозреваю, что проблема заключается либо в моем фрагментном шейдереили нормали поверхности, особенно в областях, где они находятся близко к перпендикуляру к направлению камеры. Вот как создаются вершины:
# --- Python imports ---
import numpy as np
# --- Internal imports ---
from glmesh import MeshApp3D
# -----------------------------------------------------------
# Torus parameters
radius1 = 1.0
radius2 = 0.2
# Define torus
torus = ( lambda u,v : np.cos(u)*(radius1+radius2*np.cos(v)),
lambda u,v : np.sin(u)*(radius1+radius2*np.cos(v)),
lambda u,v : radius2*np.sin(v) )
# Generate grid of points on the torus
nSamples = 100
U = np.linspace(0.0,2*np.pi,nSamples)
V = np.linspace(0.0,-2*np.pi,nSamples)
grid = np.array(
[
[ [torus[componentIndex](u,v) for u in U] for v in V ] for componentIndex in (0,1,2)
],
dtype=np.float32 )
# -----------------------------------------------------------
# Rearrange grid to a list of points
vertices = np.reshape(
np.transpose( grid,
axes=(1,2,0)),
( nSamples*nSamples ,3))
# Generate triangle indices in a positive permutation
# For example:
# 7---8---9
# | / | / |
# 4---5---6
# | / | / |
# 1---2---3
#
# (1,5,4) (1,2,5) (2,6,5) (2,3,6) (4,8,7) (4,5,8) (5,9,8) (5,6,9)
faces = np.zeros( ( 2*(nSamples-1)*(nSamples-1), 3 ), dtype=np.uint32 )
k = 0
for j in range(nSamples-1):
for i in range(nSamples-1):
jni = j*nSamples+i
faces[k] = [ jni,
jni+nSamples+1,
jni+nSamples ]
faces[k+1] = [ jni,
jni+1,
jni+1+nSamples ]
k+=2
# -----------------------------------------------------------
# -----------------------------------------------------------
meshApp = MeshApp3D( {'vertices' : vertices, 'faces' : faces},
colors=(1.0,1.0,1.0) )
meshApp.run()
Фрагментный шейдер:
varying vec3 position;
varying vec3 normal;
varying vec4 color;
void main() {
// Diffuse
vec3 lightDir = normalize( position - vec3($lightPos) );
float diffuse = dot( normal, lightDir );
//diffuse = min( max(diffuse,0.0), 1.0 );
// Specular
vec3 halfWayVector = normalize( ( lightDir+vec3($cameraDir) )/2.0 );
float specular = min( max( dot(halfWayVector,normal) ,0.0), 1.0 );
specular = specular * specular * specular * specular;
specular = specular * specular * specular * specular;
specular = specular * specular * specular * specular;
// Additive
vec3 fragColor = vec3($lightColor) * color.xyz;
fragColor = fragColor * ( $diffuseMaterialConstant * diffuse +
$specularMaterialConstant * specular)
+ $ambientMaterialConstant * vec3($ambientLight) * color.xyz;
gl_FragColor = vec4(fragColor,1.0);
}
Остальная часть кода разбита на модули, но в двух словах, вот что происходит:
- a MeshData состоит из вершин и граней
- , нормали генерируются в MeshData внутри, на основе положений вершин и порядка, в котором они определяют их соответствующиетреугольники
- холст и окно OpenGL создаются и инициализируются
- сетка рисуется в виде полос треугольника
Проблемной частью может быть определение треугольников сетки,Пример:
7---8---9
| / | / |
4---5---6
| / | / |
1---2---3
v
^
|
---> u
(1,5,4) (1,2,5) (2,6,5) (2,3,6) (4,8,7) (4,5,8) (5,9,8) (5,6,9)
Изначально он должен был генерировать треугольники для двумерных функций z = f (x, y) и хорошо с ними работал, но я столкнулся с проблемами при его применении кпараметрические поверхности r (u, v) = [x (u, v), y (u, v), z (u, v)] . Например, по этой причине параметр v изменяется от 0 до -2pi вместо + 2pi (в противном случае нормалиуказывать внутрь).
Есть какие-нибудь идеи о том, что может вызывать глюки, видимые на изображении?
(или какой-нибудь совет по улучшению генерации треугольника?)