学习python编程,在新东方少儿编程官网的自由创作平台做的一些作品。
可以在线运行,效果如下(在新页面中打开链接):
代码如下(用到平台自定义的xdf库):
from xdf import *
import time
import math
class Fps:
def __init__(self, x = 0, y = 50, size = 50, color="black"):
self.fps = 0
self.t = time.time()
self.x = x
self.y = y
self.tf = text("", x, y, size, color)
def update(self):
self.fps += 1
t0 = time.time()
if t0 - self.t > 1:
self.tf.change("fps:" + str(int(self.fps/(t0-self.t))))
self.t = t0
self.fps = 0
pass
pass
class Color:
def __init__(self, r = 255, g = 255, b = 255, a = 1.0):
self.r =r
self.g = g
self.b = b
self.a = a
pass
def copy(self):
return Color(self.r, self.g, self.b, self.a)
def __str__(self):
return "rgb({},{},{},{})".format(self.r, self.g, self.b, self.a)
@staticmethod
def fromValue(v, a = 1.0):
return Color(v>>16&0xff, v>>8&0xff, v&0xff, a)
pass
class Vector2:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
pass
pass
class PixelScreen:
def __init__(self, x, y, CW, CH, m, n, color = "white"):
self.x = x
self.y = y
self.CW = CW
self.CH = CH
self.m = m
self.n = n
self.cubes = []
self.pixels = []
for i in range(m):
self.cubes.append([])
self.pixels.append([])
for j in range(n):
xy = self.ij2xy(i, j)
self.cubes[i].append(line(xy.x, xy.y, xy.x + CW, xy.y, CH, color))
self.pixels[i].append([color, color])
pass
def ij2xy(self, i, j):
return Vector2(self.x + i * self.CW, self.y + j * self.CH)
def xy2ij(self, x, y):
return Vector2(int((x - self.x)/self.CW), int((y - self.y)/self.CH))
def update(self):
for i in range(self.m):
for j in range(self.n):
pixel = self.pixels[i][j]
if pixel[0] != pixel[1]:
pixel[0] = pixel[1]
self.cubes[i][j].change(pixel[0])
pass
pass
class Vector3:
def __init__(self, x = 0, y = 0, z = 0):
self.x = x
self.y = y
self.z = z
pass
def copy(self):
return Vector3(self.x, self.y, self.z)
def length(self):
return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
def sqrLength(self):
return self.x * self.x + self.y * self.y + self.z * self.z
def normalize(self):
inv = 1 / self.length()
return Vector3(self.x * inv, self.y * inv, self.z * inv)
def cross(self, v):
return Vector3(-self.z * v.y + self.y * v.z, self.z * v.x - self.x * v.z, -self.y * v.x + self.x * v.y)
def __pow__(self, v):
return Vector3(-self.z * v.y + self.y * v.z, self.z * v.x - self.x * v.z, -self.y * v.x + self.x * v.y)
def __neg__(self): #重载-(负)
return Vector3(-self.x, -self.y, -self.z)
def __pos__(self): #重载+(正)
return Vector3(self.x, self.y, self.z)
def __abs__(self): #重载abs()
return Vector3(abs(self.x), abs(self.y), abs(self.z))
def __add__(self, v): #重载+
return Vector3(self.x + v.x, self.y + v.y, self.z + v.z)
def __sub__(self, v): #重载-
return Vector3(self.x - v.x, self.y - v.y, self.z - v.z)
def __mul__(self, v): #重载*
if type(v)==type(self):
return self.x * v.x + self.y * v.y + self.z * v.z
return Vector3(self.x * v, self.y * v, self.z * v)
def __div__(self, v): # 重载/
if type(v)==type(self):
pass
invf = 1 / v
return Vector3(self.x * invf, self.y * invf, self.z * invf)
def __iadd__(self, v): #重载+=
self.x += v.x
self.y += v.y
self.z += v.z
return self
def __isub__(self, v): #重载-=
self.x -= v.x
self.y -= v.y
self.z -= v.z
return self
def __imul__(self, v): #重载*=
if type(v)==type(self):
return self.x * v.x + self.y * v.y + self.z * v.z
self.x *= v
self.y *= v
self.z *= v
return self
def __idiv__(self, v): # 重载/
if type(v)==type(self):
pass
invf = 1 / v
self.x *= invf
self.y *= invf
self.z *= invf
return self
def __str__(self):
return "({},{},{})".format(self.x, self.y, self.z)
pass
Vector3.zero = Vector3()
class Ray3:
def __init__(self, origin, direction):
self.origin = origin
self.direction = direction
pass
def getPoint(self, t):
return self.origin + self.direction * t
pass
class IntersectResult:
def __init__(self):
self.geometry = None
self.distance = 0
self.position = Vector3.zero
self.normal = Vector3.zero
pass
pass
IntersectResult.noHit = IntersectResult()
class PerspectiveCamera:
def __init__(self, eye, front, up, fov):
self.eye = eye
self.front = front
self.refUp = up
self.fov = fov
self.right = Vector3.zero
self.up = Vector3.zero
self.fovScale = 0
pass
def initialize(self):
self.right = self.front ** self.refUp
self.up = self.right ** self.front
self.fovScale = math.tan(self.fov * 0.5 * math.pi / 180) * 2
pass
def generateRay(self, x, y):
r = self.right * ((x - 0.5) * self.fovScale)
u = self.up * ((y - 0.5) * self.fovScale)
return Ray3(self.eye, (self.front + r + u).normalize())
pass
class Plane:
def __init__(self, normal, d):
self.normal = normal
self.d = d
self.position = Vector3.zero
self.material = None
pass
def copy(self):
return Plane(self.normal.copy(), self.d)
def initialize(self):
self.position = self.normal * self.d
pass
def intersect(self, ray):
a = ray.direction * self.normal
if a >= 0:
return IntersectResult.noHit
b = self.normal * (ray.origin - self.position)
result = IntersectResult()
result.geometry = self
result.distance = -b / a
result.position = ray.getPoint(result.distance)
result.normal = self.normal
return result
pass
class Sphere:
def __init__(self, center, radius):
self.center = center
self.radius = radius
self.sqrRadius = radius * radius
self.material = None
pass
def copy(self):
return Sphere(self.center.copy(), self.radius)
def initialize(self):
self.sqrRadius = self.radius * self.radius
pass
def intersect(self, ray):
v = ray.origin - self.center
dotV = ray.direction * v
if dotV <= 0:
a0 = v * v - self.sqrRadius
discr = dotV * dotV - a0
if discr >= 0:
result = IntersectResult()
result.geometry = self
result.distance = -dotV - math.sqrt(discr)
result.position = ray.getPoint(result.distance)
result.normal = (result.position - self.center).normalize()
return result
return IntersectResult.noHit
pass
class Union:
def __init__(self, geometries):
self.geometries = geometries
pass
def initialize(self):
for geom in self.geometries:
geom.initialize()
pass
def intersect(self, ray):
minDistance = 1e20
minResult = IntersectResult.noHit
for geom in self.geometries:
result = geom.intersect(ray)
if result.geometry and result.distance < minDistance:
minDistance = result.distance
minResult = result
return minResult
pass
class CheckerMaterial:
def __init__(self, scale, reflectiveness):
self.scale = scale
self.reflectiveness = reflectiveness
def sample(self, ray, position, normal):
if abs((math.floor(position.x*self.scale) + math.floor(position.z*self.scale))%2)<1:
return "black"
else:
return "white";
pass
sphere = Sphere(Vector3(0, 10, -10), 10)
plane = Plane(Vector3(0, 1, 0), 0)
plane.material = CheckerMaterial(0.1, 0.0)
scene = Union([
plane,
sphere
])
camera = PerspectiveCamera(Vector3(0, 10, 10), Vector3(0, 0, -1), Vector3(0, 1, 0), 90)
scene.initialize()
camera.initialize()
W = 768
H = 1024
CW = 12 // 4
m = int(W/CW)
n = int(W/CW)
screen = PixelScreen(0, 0, CW, CW, m, n, "red")
fps = Fps(color="red")
def update3d():
#scene.initialize()
#camera.initialize()
for i in range(m):
for j in range(n):
screen.pixels[i][j][1] = "black"
ray = camera.generateRay(i / m, 1 - j / n)
result = scene.intersect(ray)
if result.geometry:
if result.geometry.material:
color = result.geometry.material.sample(ray, result.position, result.normal)
screen.pixels[i][j][1] = str(color)
else:
color = Color(
(result.normal.x + 1)*128//1,
(result.normal.y + 1)*128//1,
(result.normal.z + 1)*128//1
)
screen.pixels[i][j][1] = str(color)
pass
def updateColors():
for i in range(m):
for j in range(n):
v = random(255)
screen.pixels[i][j][1] = str(Color(v, v, v, 1.0))
update3d()
screen.update()
def loop():
#updateColors()
#update3d()
#screen.update()
fps.update()
也可以下载代码,本地python环境运行(用pygame封装了xdf库)。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。