学习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库)。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。