1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Various material implementations
18 intrude import depth_core
22 # Get the default blueish material
23 new do return new SmoothMaterial(
29 # Simple material with static colors
33 # Ambient color, always visible
34 var ambient_color
: Array[Float] is writable
36 # Diffuse color when covered by a light source
37 var diffuse_color
: Array[Float] is writable
39 # Specular color affecting reflections
40 var specular_color
: Array[Float] is writable
42 redef fun draw
(actor
, model
)
44 var program
= app
.versatile_program
50 program
.translation
.uniform
(actor
.center
.x
, actor
.center
.y
, actor
.center
.z
, 0.0)
51 program
.scale
.uniform actor
.scale
52 program
.rotation
.uniform
new Matrix.gamnit_euler_rotation
(actor
.pitch
, actor
.yaw
, actor
.roll
)
55 program
.coord
.array_enabled
= true
56 program
.coord
.array
(mesh
.vertices
, 3)
58 program
.normal
.array_enabled
= true
59 program
.normal
.array
(mesh
.normals
, 3)
62 program
.use_map_ambient
.uniform
false
63 program
.use_map_diffuse
.uniform
false
64 program
.use_map_specular
.uniform
false
65 program
.tex_coord
.array_enabled
= false
68 program
.light_center
.uniform
(app
.light
.position
.x
, app
.light
.position
.y
, app
.light
.position
.z
)
71 program
.camera
.uniform
(app
.world_camera
.position
.x
, app
.world_camera
.position
.y
, app
.world_camera
.position
.z
)
73 # Colors from the material
74 program
.ambient_color
.uniform
(ambient_color
[0], ambient_color
[1], ambient_color
[2], ambient_color
[3]*actor
.alpha
)
75 program
.diffuse_color
.uniform
(diffuse_color
[0], diffuse_color
[1], diffuse_color
[2], diffuse_color
[3]*actor
.alpha
)
76 program
.specular_color
.uniform
(specular_color
[0], specular_color
[1], specular_color
[2], specular_color
[3]*actor
.alpha
)
79 if mesh
.indices
.is_empty
then
80 glDrawArrays
(mesh
.draw_mode
, 0, mesh
.vertices
.length
/3)
82 glDrawElements
(mesh
.draw_mode
, mesh
.indices
.length
, gl_UNSIGNED_SHORT
, mesh
.indices_c
.native_array
)
87 # Material with potential `diffuse_texture` and `specular_texture`
88 class TexturedMaterial
91 # Texture applied to the ambient_color
92 var ambient_texture
: nullable Texture = null is writable
94 # Texture applied to the diffuse color
95 var diffuse_texture
: nullable Texture = null is writable
97 # Texture applied to the specular color
98 var specular_texture
: nullable Texture = null is writable
100 redef fun draw
(actor
, model
)
102 var mesh
= model
.mesh
104 var program
= app
.versatile_program
107 # One of the textures used, if any
108 var sample_used_texture
= null
110 var texture
= ambient_texture
111 if texture
!= null then
112 glActiveTexture gl_TEXTURE0
113 glBindTexture
(gl_TEXTURE_2D
, texture
.gl_texture
)
114 program
.use_map_ambient
.uniform
true
115 program
.map_ambient
.uniform
0
116 sample_used_texture
= texture
118 program
.use_map_ambient
.uniform
false
121 texture
= diffuse_texture
122 if texture
!= null then
123 glActiveTexture gl_TEXTURE1
124 glBindTexture
(gl_TEXTURE_2D
, texture
.gl_texture
)
125 program
.use_map_diffuse
.uniform
true
126 program
.map_diffuse
.uniform
1
127 sample_used_texture
= texture
129 program
.use_map_diffuse
.uniform
false
132 texture
= specular_texture
133 if texture
!= null then
134 glActiveTexture gl_TEXTURE2
135 glBindTexture
(gl_TEXTURE_2D
, texture
.gl_texture
)
136 program
.use_map_specular
.uniform
true
137 program
.map_specular
.uniform
2
138 sample_used_texture
= texture
140 program
.use_map_specular
.uniform
false
143 program
.translation
.uniform
(actor
.center
.x
, actor
.center
.y
, actor
.center
.z
, 0.0)
144 program
.scale
.uniform actor
.scale
146 # If using a texture, set `texture_coords`
147 program
.tex_coord
.array_enabled
= sample_used_texture
!= null
148 if sample_used_texture
!= null then
149 if sample_used_texture
isa RootTexture then
150 # Coordinates are directly valid
151 program
.tex_coord
.array
(mesh
.texture_coords
, 2)
153 # Correlate texture coordinates from the substexture and the mesh.
154 # This is slow, but should be cached on the GPU.
155 var xa
= sample_used_texture
.offset_left
156 var xd
= sample_used_texture
.offset_right
- xa
157 var ya
= sample_used_texture
.offset_top
158 var yd
= sample_used_texture
.offset_bottom
- ya
162 var tex_coords
= new Array[Float].with_capacity
(mesh
.texture_coords
.length
)
163 for i
in [0..mesh
.texture_coords
.length
/2[ do
164 tex_coords
[i
*2] = xa
+ xd
* mesh
.texture_coords
[i
*2]
165 tex_coords
[i
*2+1] = 1.0 - (ya
+ yd
* mesh
.texture_coords
[i
*2+1])
168 program
.tex_coord
.array
(tex_coords
, 2)
172 program
.coord
.array_enabled
= true
173 program
.coord
.array
(mesh
.vertices
, 3)
175 program
.rotation
.uniform
new Matrix.gamnit_euler_rotation
(actor
.pitch
, actor
.yaw
, actor
.roll
)
177 program
.ambient_color
.uniform
(ambient_color
[0], ambient_color
[1], ambient_color
[2], ambient_color
[3]*actor
.alpha
)
178 program
.diffuse_color
.uniform
(diffuse_color
[0], diffuse_color
[1], diffuse_color
[2], diffuse_color
[3]*actor
.alpha
)
179 program
.specular_color
.uniform
(specular_color
[0], specular_color
[1], specular_color
[2], specular_color
[3]*actor
.alpha
)
181 program
.normal
.array_enabled
= true
182 program
.normal
.array
(mesh
.normals
, 3)
184 program
.light_center
.uniform
(app
.light
.position
.x
, app
.light
.position
.y
, app
.light
.position
.z
)
185 program
.camera
.uniform
(app
.world_camera
.position
.x
, app
.world_camera
.position
.y
, app
.world_camera
.position
.z
)
187 if mesh
.indices
.is_empty
then
188 glDrawArrays
(mesh
.draw_mode
, 0, mesh
.vertices
.length
/3)
190 glDrawElements
(mesh
.draw_mode
, mesh
.indices
.length
, gl_UNSIGNED_SHORT
, mesh
.indices_c
.native_array
)
195 # Simple material using the normals of the surface as color
197 # Each axis composing the normals are translated to color values.
198 # This material is useful for debugging normals or display models in a colorful way.
199 class NormalsMaterial
202 redef fun draw
(actor
, model
)
204 var program
= app
.normals_program
206 program
.mvp
.uniform app
.world_camera
.mvp_matrix
208 var mesh
= model
.mesh
210 # TODO apply normal map
212 program
.translation
.uniform
(actor
.center
.x
, actor
.center
.y
, actor
.center
.z
, 0.0)
213 program
.scale
.uniform actor
.scale
215 program
.tex_coord
.array_enabled
= true
216 program
.tex_coord
.array
(mesh
.texture_coords
, 2)
218 program
.coord
.array_enabled
= true
219 program
.coord
.array
(mesh
.vertices
, 3)
221 program
.rotation
.uniform
new Matrix.gamnit_euler_rotation
(actor
.pitch
, actor
.yaw
, actor
.roll
)
223 program
.normal
.array_enabled
= true
224 program
.normal
.array
(mesh
.normals
, 3)
226 if mesh
.indices
.is_empty
then
227 glDrawArrays
(mesh
.draw_mode
, 0, mesh
.vertices
.length
/3)
229 glDrawElements
(mesh
.draw_mode
, mesh
.indices
.length
, gl_UNSIGNED_SHORT
, mesh
.indices_c
.native_array
)
234 # Graphic program to display 3D models with Lamber diffuse lighting
236 super GamnitProgramFromSource
238 redef var vertex_shader_source
= """
239 // Vertex coordinates
240 attribute vec4 coord;
242 // Vertex translation
243 uniform vec4 translation;
248 // Vertex coordinates on textures
249 attribute vec2 tex_coord;
252 attribute vec3 normal;
254 // Model view projection matrix
257 uniform mat4 rotation;
260 uniform vec3 light_center;
262 // Coordinates of the camera
265 // Output for the fragment shader
266 varying vec2 v_tex_coord;
267 varying vec3 v_normal;
268 varying vec4 v_light_center;
269 varying vec4 v_camera;
273 // Pass varyings to the fragment shader
274 v_tex_coord = vec2(tex_coord.x, 1.0 - tex_coord.y);
275 v_normal = normalize(vec4(normal, 0.0) * rotation * mvp).xyz;
277 gl_Position = (vec4(coord.xyz * scale, 1.0) * rotation + translation) * mvp;
279 // TODO compute v_light_center and v_camera on the CPU side and pass as uniforms
280 v_light_center = vec4(light_center, 0.0) * mvp;
281 v_camera = vec4(camera, 0.0) * mvp;
283 """ @ glsl_vertex_shader
285 redef var fragment_shader_source
= """
286 precision mediump float;
288 // Input from the vertex shader
289 varying vec2 v_tex_coord;
290 varying vec3 v_normal;
291 varying vec4 v_light_center;
292 varying vec4 v_camera;
295 uniform vec4 ambient_color;
296 uniform vec4 diffuse_color;
297 uniform vec4 specular_color;
300 uniform bool use_map_ambient;
301 uniform sampler2D map_ambient;
304 uniform bool use_map_diffuse;
305 uniform sampler2D map_diffuse;
308 uniform bool use_map_specular;
309 uniform sampler2D map_specular;
312 uniform bool use_map_bump;
313 uniform sampler2D map_bump;
316 uniform bool use_map_normal;
317 uniform sampler2D map_normal;
322 vec3 light_dir = normalize(v_light_center.xyz);
323 float lambert = max(dot(light_dir, v_normal), 0.0);
326 gl_FragColor = ambient_color * texture2D(map_ambient, v_tex_coord);
328 gl_FragColor = ambient_color;
331 gl_FragColor += lambert * diffuse_color * texture2D(map_diffuse, v_tex_coord);
333 gl_FragColor += lambert * diffuse_color;
335 if (gl_FragColor.a < 0.01) discard;
337 """ @ glsl_fragment_shader
339 # Vertices coordinates
340 var coord
= attributes
["coord"].as(AttributeVec4) is lazy
342 # Should this program use the texture `map_ambient`?
343 var use_map_ambient
= uniforms
["use_map_ambient"].as(UniformBool) is lazy
345 # Ambient texture unit
346 var map_ambient
= uniforms
["map_ambient"].as(UniformSampler2D) is lazy
348 # Should this program use the texture `map_diffuse`?
349 var use_map_diffuse
= uniforms
["use_map_diffuse"].as(UniformBool) is lazy
351 # Diffuser texture unit
352 var map_diffuse
= uniforms
["map_diffuse"].as(UniformSampler2D) is lazy
354 # Should this program use the texture `map_specular`?
355 var use_map_specular
= uniforms
["use_map_specular"].as(UniformBool) is lazy
357 # Specularity texture unit
358 var map_specular
= uniforms
["map_specular"].as(UniformSampler2D) is lazy
361 var normal
= attributes
["normal"].as(AttributeVec3) is lazy
363 # Coordinates on the textures, per vertex
364 var tex_coord
= attributes
["tex_coord"].as(AttributeVec2) is lazy
367 var ambient_color
= uniforms
["ambient_color"].as(UniformVec4) is lazy
370 var diffuse_color
= uniforms
["diffuse_color"].as(UniformVec4) is lazy
373 var specular_color
= uniforms
["specular_color"].as(UniformVec4) is lazy
375 # Center position of the light
376 var light_center
= uniforms
["light_center"].as(UniformVec3) is lazy
379 var camera
= uniforms
["camera"].as(UniformVec3) is lazy
381 # Translation applied to each vertex
382 var translation
= uniforms
["translation"].as(UniformVec4) is lazy
385 var rotation
= uniforms
["rotation"].as(UniformMat4) is lazy
388 var scale
= uniforms
["scale"].as(UniformFloat) is lazy
390 # Model view projection matrix
391 var mvp
= uniforms
["mvp"].as(UniformMat4) is lazy
394 # Program to color objects from their normal vectors
398 redef var fragment_shader_source
= """
399 precision mediump float;
401 // Input from the vertex shader
402 varying vec3 v_normal;
406 gl_FragColor = vec4(v_normal*0.5 + 0.5, 1.0);
408 """ @ glsl_fragment_shader
412 private var versatile_program
= new LambertProgram is lazy
414 private var normals_program
= new NormalProgram is lazy