14
2024
11

python编程学习-3d

学习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库)。



« 上一篇下一篇 »

相关文章:

python编程学习-华容道  (2024-11-14 16:43:25)

python编程学习-动画  (2024-11-14 16:39:37)

python编程学习-别踩白块  (2024-11-14 16:38:59)

python编程学习-俄罗斯方块  (2024-11-14 16:38:19)

python编程学习-井字棋  (2024-11-14 16:34:9)

python编程学习-五子棋  (2024-11-14 16:33:23)

python编程学习-乒乓  (2024-11-14 16:32:46)

python编程学习-一笔画关卡生成  (2024-11-14 16:32:6)

python编程学习-一笔画  (2024-11-14 16:31:27)

python编程学习-woblox  (2024-11-14 16:30:47)

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。