法线

💡 法线(normal line),是指始终垂直于某平面的直线。 在几何学中,法线指平面上垂直于曲线在某点的切线的一条线。 法线也应用于光学的平面镜反射上。

Untitled

Sketch.png

Python实现的光照渲染Demo

(依赖包:numpy、opencv) 1、编写变换的矩阵包括移动、旋转、缩放、投影

import numpy as np
from math import *
def M_Move(x,y,z):
 return np.array([1,0,0,0,0,1,0,0,0,0,1,0,x,y,z,1]).reshape(4,4)
def M_Scale(x,y,z):
 return np.array([x,0,0,0,0,y,0,0,0,0,z,0,0,0,0,1]).reshape(4,4)
def M_RotateY(angle):
 return np.array([cos(angle),0,sin(angle),0,0,1,0,0,-sin(angle),0,cos(angle),0,0,0,0,1]).reshape(4,4)
def M_RotateX(angle):
 return np.array([1,0,0,0,0,cos(angle),-sin(angle),0,0,sin(angle),cos(angle),0,0,0,0,1]).reshape(4,4)
def M_Projection(distance):
 return np.array([1,0,0,0,0,1,0,0,0,0,1,1/distance,0,0,0,1]).reshape(4,4)

def GetPoint(vector4):
 offset=250
 d=1 if vector4[3]==0 else vector4[3]
 # d=-d if d<0 else d
 return (int(offset+vector4[0]/d),int(offset-vector4[1]/d))

def GetNomalizedDir(targetPos,vector4):
 Dir=targetPos-np.array([vector4[0],vector4[1],vector4[2]])
 return nomalizeVector3(Dir)

def mul(matrix4x4_1,matrix4x4_2):
 return np.matmul(matrix4x4_1,matrix4x4_2)

def nomalizeVector3(vector3):
 return vector3/np.linalg.norm(vector3)

2、实现TriangleClass,实现三角面的变换与绘制

import cv2 as cv
import numpy as np
from math import *
from matrix import *

class Trangle:
 def __init__(self,a,b,c):
 self.a=np.array(a);self.b=np.array(b);self.c=np.array(c)
 self.A=self.a;self.B=self.b;self.C=self.c
 self.cullMask=False
 self.drawLines=True
 self.thickness=1
 self.linesColor=(255,255,255)
 self.lightPos=np.array([0,0,-1])
 self.cameraPos=np.array([0,0,-1])
 def transform(self,matrix):
 self.A=mul(self.a,matrix);self.B=mul(self.b,matrix);self.C=mul(self.c,matrix)
 self.pointA=GetPoint(self.A);self.pointB=GetPoint(self.B);self.pointC=GetPoint(self.C)
 u=self.B-self.A;v=self.C-self.A
 self.U=np.array([u[0],u[1],u[2]]) ;self.V=np.array([v[0],v[1],v[2]]) 
 def drawCall(self,img):
 points=[self.pointA,self.pointB,self.pointC]
 if self.drawLines:
 cv.line(img,points[0],points[1],self.linesColor,self.thickness)
 cv.line(img,points[1],points[2],self.linesColor,self.thickness)
 cv.line(img,points[2],points[0],self.linesColor,self.thickness)

 self.normal=np.cross(self.U,self.V)
 self.normal=self.normal/np.linalg.norm(self.normal)

 eyeDir=-self.cameraPos

 self.cullMask =np.dot(eyeDir,self.normal)<0
 if not self.cullMask:
 lightDir=nomalizeVector3(-self.lightPos)
 l=np.dot(lightDir,self.normal)
 l= 0 if l<0 else l
 col=int(200*l)+55
 cv.fillPoly(img,[np.array(points)], (col,col,col))
 return img

3、实现Cube Class,根据定点构建立方体三角面,并编写绘制与变换方法

from Triangle import *

class Cube:
 def __init__(self,vertices):
 self.vertices=vertices
 self.triangles=[
 # Top
 Trangle(self.vertices[0],self.vertices[1],self.vertices[2]),
 Trangle(self.vertices[0],self.vertices[2],self.vertices[3]),
 # Down
 Trangle(self.vertices[4],self.vertices[7],self.vertices[5]),
 Trangle(self.vertices[5],self.vertices[7],self.vertices[6]),
 # Front
 Trangle(self.vertices[3],self.vertices[7],self.vertices[6]),
 Trangle(self.vertices[3],self.vertices[6],self.vertices[2]),
 # Back
 Trangle(self.vertices[0],self.vertices[1],self.vertices[4]),
 Trangle(self.vertices[1],self.vertices[5],self.vertices[4]),
 # Left
 Trangle(self.vertices[3],self.vertices[0],self.vertices[7]),
 Trangle(self.vertices[0],self.vertices[4],self.vertices[7]),

 # Right
 Trangle(self.vertices[2],self.vertices[6],self.vertices[5]),
 Trangle(self.vertices[2],self.vertices[5],self.vertices[1]),
 ]
 self.drawLines=True
 self.thickness=1
 self.linesColor=(255,255,255)
 self.lightPos=np.array([0,0,-1])
 self.cameraPos=np.array([0,0,-1])
 def transform(self,matrix):
 for t in self.triangles:
 t.transform(matrix)
 def drawCall(self,img):
 for t in self.triangles:
 t.drawLines=self.drawLines
 t.thickness=self.thickness
 t.linesColor=self.linesColor
 # t.lightPos=self.lightPos
 # t.cameraPos=self.cameraPos
 img=t.drawCall(img)
 return img

4、main脚本中,初始化顶点等相关数据,进行循环绘制,实现立方体旋转效果

from Cube import *

lightPos=np.array([10,10,-10])
cameraPos=np.array([0,0,-10])
moveSpeed=10
fov=250
rotateY=0

if __name__=='__main__':
 a=[-0.5, 0.5, 0.5, 1]
 b=[0.5, 0.5, 0.5, 1]
 c=[0.5, 0.5, -0.5, 1]
 d=[-0.5, 0.5, -0.5, 1]

 e=[-0.5, -0.5, 0.5, 1]
 f=[0.5, -0.5, 0.5, 1]
 g=[0.5, -0.5, -0.5, 1]
 h=[-0.5, -0.5, -0.5, 1]

 cube= Cube([a,b,c,d,e,f,g,h])
 done = False
 while not done:
 img=np.zeros((500,500,3),np.uint8)
 cube.lightPos=lightPos
 cube.cameraPos=cameraPos
 cube.drawLines=False
 rotateY+=0.05
 matMove=M_Move(cameraPos[0],cameraPos[1],cameraPos[2]) 
 distance=-cameraPos[2] if cameraPos[2]<0 else cameraPos[2]
 distance=0.001 if distance<=0 else distance
 matScale= M_Scale(200,200,200)
 matRotate=mul(M_RotateX(rotateY),M_RotateY(rotateY)) 
 m=matMove
 matProjection=M_Projection(fov)

 m=mul(matScale,m)
 m=mul(matRotate,m)
 m=mul(m,matProjection)

 cube.transform(m)
 graphics= cube.drawCall(img)


 cv.imshow("img",graphics)
 key=cv.waitKey(10)
 if key==27:
 done=True
 cv.destroyAllWindows()
 elif key==119:
 cameraPos[2]-=moveSpeed
 elif key==115:
 cameraPos[2]+=moveSpeed
 elif key==97:
 cameraPos[0]+=moveSpeed
 elif key==100:
 cameraPos[0]-=moveSpeed
 elif key==101:
 cameraPos[1]-=moveSpeed
 elif key==113:
 cameraPos[1]+=moveSpeed