Last active
October 29, 2024 06:50
-
-
Save GuillaumeFavelier/d12b3f9406b68b11bcae09bddfdbaf3e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file is here to name the Gist. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
""" | |
This example is a prototype demonstrating normal mapping | |
by using a subsample version of a plane with textures. | |
""" | |
import numpy as np | |
from vispy import app, gloo | |
from vispy .io import imread | |
from vispy.geometry import create_plane | |
from vispy.util.transforms import perspective, translate | |
vert = """ | |
uniform mat4 u_model; | |
uniform mat4 u_view; | |
uniform mat4 u_projection; | |
uniform vec3 u_light; | |
attribute vec3 a_position; | |
attribute vec2 a_texcoord; | |
varying vec2 v_texcoord; | |
varying vec3 v_light_vec; | |
varying vec3 v_eye_vec; | |
varying vec4 v_ambientk; | |
varying vec4 v_light_color; | |
void main() | |
{ | |
v_texcoord = a_texcoord; | |
v_ambientk = vec4(0.3, 0.3, 0.3, 1.0); | |
v_light_color = vec4(1.0, 1.0, 1.0, 1.0); | |
vec3 position = a_position; | |
v_light_vec = normalize(u_light); | |
v_eye_vec = normalize(vec3(0, 0, 5)); | |
gl_Position = u_projection * u_view * u_model * vec4(position,1.0); | |
} | |
""" | |
frag = """ | |
uniform sampler2D a_texture; | |
uniform sampler2D a_normal; | |
varying vec2 v_texcoord; | |
varying vec3 v_light_vec; | |
varying vec3 v_eye_vec; | |
varying vec4 v_ambientk; | |
varying vec4 v_light_color; | |
void main() { | |
vec4 v_base_color = texture2D(a_texture, v_texcoord); | |
vec3 v_normal_vec = texture2D(a_normal, v_texcoord).xyz * 2.0 - 1.0; | |
// disabled because of artifact | |
float shininess = 0.0; | |
//float shininess = 1. / 200.; | |
//DIFFUSE | |
float diffusek = dot(v_light_vec, v_normal_vec); | |
// clamp, because 0 < theta < pi/2 | |
diffusek = clamp(diffusek, 0.0, 1.0); | |
vec4 diffuse_color = v_light_color * diffusek; | |
//SPECULAR | |
//reflect light wrt normal for the reflected ray, then | |
//find the angle made with the eye | |
float speculark = 0.0; | |
if (shininess > 0.) { | |
speculark = dot(reflect(v_light_vec, v_normal_vec), v_eye_vec); | |
speculark = clamp(speculark, 0.0, 1.0); | |
//raise to the material's shininess, multiply with a | |
//small factor for spread | |
speculark = 20.0 * pow(speculark, 1.0 / shininess); | |
} | |
vec4 specular_color = v_light_color * speculark; | |
gl_FragColor = v_base_color * (v_ambientk + diffuse_color) + specular_color; | |
} | |
""" # noqa | |
def mesh(n_segments=5, length=3): | |
v, indices, _ = create_plane(width=length, | |
height=length, | |
width_segments=n_segments, | |
height_segments=n_segments) | |
return v['position'], v['texcoord'], indices | |
# ----------------------------------------------------------------------------- | |
class Canvas(app.Canvas): | |
def __init__(self): | |
app.Canvas.__init__(self, keys='interactive', size=(800, 600)) | |
self.theta = 0.0 | |
self.light_distance = 10.0 | |
self.filled_buf = gloo.IndexBuffer(filled) | |
self.program = gloo.Program(vert, frag) | |
self.buffer = np.array(list(zip(vertices, texcoord)), | |
dtype=[('a_position', np.float32, 3), | |
('a_texcoord', np.float32, 2)]) | |
self.program.bind(gloo.VertexBuffer(self.buffer)) | |
self.view = translate((0, 0, -5)) | |
self.model = np.eye(4, dtype=np.float32) | |
gloo.set_viewport(0, 0, self.physical_size[0], self.physical_size[1]) | |
self.projection = perspective(45.0, self.size[0] / | |
float(self.size[1]), 2.0, 10.0) | |
self.program['a_texture'] = gloo.Texture2D(texture, | |
interpolation='linear') | |
self.program['a_normal'] = gloo.Texture2D(normals, | |
interpolation='linear') | |
self.program['u_projection'] = self.projection | |
self.program['u_model'] = self.model | |
self.program['u_view'] = self.view | |
self.program['u_light'] = [self.light_distance*np.cos(self.theta), | |
self.light_distance*np.sin(self.theta), | |
self.light_distance] | |
gloo.set_clear_color('black') | |
self._timer = app.Timer('auto', connect=self.on_timer, start=True) | |
self.show() | |
# --------------------------------- | |
def on_timer(self, event): | |
self.theta += .05 | |
self.program['u_light'] = [self.light_distance*np.cos(self.theta), | |
self.light_distance*np.sin(self.theta), | |
5.0] | |
self.update() | |
# --------------------------------- | |
def on_resize(self, event): | |
gloo.set_viewport(0, 0, event.physical_size[0], event.physical_size[1]) | |
self.projection = perspective(45.0, event.size[0] / | |
float(event.size[1]), 2.0, 10.0) | |
self.program['u_projection'] = self.projection | |
# --------------------------------- | |
def on_draw(self, event): | |
gloo.clear() | |
self.program.draw('triangles', self.filled_buf) | |
if __name__ == '__main__': | |
# parameters for mesh generation | |
length = 2.5 | |
n_segments = 32 | |
# create the reference mesh | |
vertices, texcoord, filled = mesh(n_segments=n_segments, | |
length=length) | |
texture = imread("brickwall.jpg") | |
normals = imread("brickwall_normal.jpg") | |
c = Canvas() | |
app.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment