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


...