import { Vector4 } from "../core/math/vector4" ; import { Color } from "../core/shading/color" ; import Texture from "../core/shading/texture" ; import { Vertex } from "../core/shading/vertex" ; import Raster from "../core/raster" ; import { IExample } from "../app" ; import Shader , { VertexInput , FragmentInput , ShaderVarying } from "../core/shading/shader" ; import { Vector2 } from "../core/math/vector2" ; import { Matrix } from "../core/math/matrix" ; import MathUtils from "../core/math/math-utils" ; import Model from "../core/shading/model" ; import InputHandler from "../web/input-handler" ; export default class DrawMesh implements IExample { protected renderer : Raster ; protected model : Model ; protected diffuseTexture : Texture ; protected normalTexture : Texture ; protected specTexture : Texture ; protected inputHandler : InputHandler ; protected fovy : number = Math . PI / 4 ; protected eye : Vector4 = new Vector4 ( 1 , 1 , 3 , 1 ) ; protected modelMatrix = new Matrix ( ) ; public constructor ( renderer ) { this . renderer = renderer ; this . inputHandler = new InputHandler ( this ) ; this . init ( ) ; } protected setCamera ( ) { let at = new Vector4 ( 0 , 0 , 0 , 1 ) ; let up = new Vector4 ( 0 , 1 , 0 , 1 ) ; let aspect = this . renderer . width / this . renderer . height ; let near = 1 ; let far = 500 ; this . renderer . setCamera ( this . eye , at , up , this . fovy , aspect , near , far ) ; } protected init ( ) { this . setCamera ( ) ; this . renderer . setBackgroundColor ( Color . GRAY ) ; this . loadObj ( ) ; this . loadTextures ( ) ; let lightDir = ( new Vector4 ( 1 , 1 , 1 ) ) . normalize ( ) ; let diffuseTexture = this . diffuseTexture ; let normalTexture = this . normalTexture ; let specTexture = this . specTexture ; let fragColor = new Color ( ) ; let eye = this . eye ; let modelMatrix = this . modelMatrix ; let shader = new Shader ( { vertexShading : function ( vertex , input ) : Vector4 { let posWorld = vertex . posModel . transform ( modelMatrix ) ; vertex . context . posProject = posWorld . transform ( input . viewProject ) ; vertex . context . varyingVec2Dict [ ShaderVarying . UV ] = vertex . uv ; vertex . context . varyingVec4Dict [ ShaderVarying . WORLD_POS ] = posWorld ; return vertex . context . posProject ; } , fragmentShading : function ( input ) : Color { let uv = input . varyingVec2Dict [ ShaderVarying . UV ] ; let diffuseColor = diffuseTexture . sample ( uv ) ; let normal = normalTexture . sampleAsVector ( uv ) ; let specFactor = specTexture . sample ( uv ) . b ; let n = normal . normalize ( ) ; let worldPos = input . varyingVec4Dict [ ShaderVarying . WORLD_POS ] ; let diffuseIntense = MathUtils . saturate ( n . dot ( lightDir ) ) ; let viewDir = eye . sub ( worldPos ) . normalize ( ) ; let halfDir = lightDir . add ( viewDir ) . normalize ( ) ; let specIntense = Math . pow ( Math . max ( 0 , n . dot ( halfDir ) ) , 5 * specFactor ) ; let factor = diffuseIntense + specIntense ; let ambient = 5 ; fragColor . set ( diffuseColor ) . multiplyRGB ( factor ) . add ( ambient ) ; fragColor . a = 255 ; return fragColor ; } } ) ; this . renderer . setShader ( shader ) ; } protected loadTextures ( ) { this . diffuseTexture = Texture . createTextureFromFile ( "african_head_diffuse.png" ) ; this . normalTexture = Texture . createTextureFromFile ( "african_head_nm.png" ) ; this . specTexture = Texture . createTextureFromFile ( "african_head_spec.png" ) ; } protected loadObj ( ) { this . model = new Model ( ) ; this . model . createFromFile ( "african_head.obj" ) ; } public draw ( ) { let triangles = this . model . triangles ; for ( let triangle of triangles ) { this . renderer . drawTriangle ( triangle ) ; } } public onWheel ( delta ) { this . fovy = MathUtils . clamp ( this . fovy + ( delta > 0 ? 0.05 : - 0.05 ) , Math . PI / 6 , Math . PI * 2 / 3 ) ; this . setCamera ( ) ; } public onMove ( dx , dy ) { let angleX = - dx / 30 * Math . PI / 180 * 10 ; let angleY = - dy / 30 * Math . PI / 180 * 10 ; let mat1 = new Matrix ( ) ; mat1 . setRotateY ( angleX ) ; let mat2 = new Matrix ( ) ; mat2 . setRotateX ( angleY ) ; this . eye . transform ( mat1 . multiply ( mat2 ) , this . eye ) ; this . setCamera ( ) ; } }