Skip to content

Instantly share code, notes, and snippets.

@sugarflower
Last active July 9, 2019 10:23
Show Gist options
  • Save sugarflower/5fa03f67244be445b87dcfbc8bee56de to your computer and use it in GitHub Desktop.
Save sugarflower/5fa03f67244be445b87dcfbc8bee56de to your computer and use it in GitHub Desktop.

平面窮屈だなと思った。

ボクセルみたいなの出来たらなー。などともくもく、そのためにはいろいろ乗り越えないとイケないことがある。

ひとまずポリゴンを自前でやってみようと思ったのでPyGameをpyg経由で使って実装してみました。

#!/usr/bin/python3
import pyg
import math

class main:

	def faceVect(self,p):
		v1 = (p[1][0] - p[0][0], p[1][1] - p[0][1], p[1][2] - p[0][2])
		v2 = (p[2][0] - p[0][0], p[2][1] - p[0][1], p[2][2] - p[0][2])
		n0 = v1[1] * v2[2] - v1[2] * v2[1]
		n1 = v1[2] * v2[0] - v1[0] * v2[2]
		n2 = v1[0] * v2[1] - v1[1] * v2[0]
		ln = math.sqrt(n0**2 + n1**2 + n2**2)
		if ln != 0:
			n0 = n0 / ln
			n1 = n1 / ln
			n2 = n2 / ln
		return (n0,n1,n2)

	def cl(self,p):
		a = (p[1][0] - p[0][0]) * (p[2][1] - p[0][1])
		b = (p[1][1] - p[0][1]) * (p[2][0] - p[0][0])
		return a > b

	def rotate(self, points, rx, ry, rz):
		b = math.radians(ry)
		a = math.radians(rx)
		g = math.radians(rz)
		p2 = [0]*len(points)
		lc = int(len(points)/3)
		for i in range(lc):
			idx = i * 3
			x0 = points[idx]
			y0 = points[idx+1]
			z0 = points[idx+2]
			x1 = x0 * math.cos(b) + z0 * math.sin(b)
			z1 =-x0 * math.sin(b) + z0 * math.cos(b)
			y2 = y0 * math.cos(a) - z1 * math.sin(a)
			z2 = y0 * math.sin(a) + z1 * math.cos(a)
			x3 = x1 * math.cos(g) - y2 * math.sin(g)
			y3 = x1 * math.sin(g) + y2 * math.cos(g)
			p2[idx] = x3
			p2[idx+1] = y3
			p2[idx+2] = z2
		return p2

	def trans(self, points, rx, ry, rz):
		p2 = [[0,0,0]] * 3
		c = 0	
		for p in points:
			x = p[0] / ( 10 + p[2] ) * 500
			y = p[1] / ( 10 + p[2] ) * 500
			z = p[2]
			p2[c] = (x+160,y+160,z)
			c += 1
		return p2

	def light(self,vec):
		light = (0,0,-1) 
		a = vec[0] * light[0]
		b = vec[1] * light[1]
		c = vec[2] * light[2]
		return abs(a+b+c)

	def getTri(self, data, link):
		idx = link[0] * 3
		a = (data[idx],data[idx+1],data[idx+2])
		idx = link[1] * 3
		b = (data[idx],data[idx+1],data[idx+2])
		idx = link[2] * 3
		c = (data[idx],data[idx+1],data[idx+2])
		return (a,b,c)

	def setup(self):
		pyg.setSize((320,320))
		pyg.setTitle("polygon")
		self.rx = 0
		self.ry = 0
		self.rz = 0
		self.p = (-1,1,1, 1,1,1, 1,-1,1, -1,-1,1, -1,1,-1, 1,1,-1, 1,-1,-1, -1,-1,-1)
		self.link = (
			(0,1,2),(0,2,3), (1,5,6),(1,6,2),
			(5,4,7),(5,7,6), (4,0,3),(4,3,7),
			(4,1,0),(4,5,1), (3,2,6),(3,6,7))

	def loop(self):
		pyg.clear()

		p1 = self.rotate(self.p, self.rx, self.ry, self.rz)
		for l in self.link:
			t = self.getTri(p1,l)
			v = self.faceVect(t)
			p2=self.trans(t,self.rx,self.ry,self.rz)
			if self.cl(p2):
				lv = self.light(v)
				cl = math.floor(64 * lv + 190)
				color = pyg.Color(cl,cl,cl)
				pyg.getGfx().filled_polygon(pyg.getSurface(), p2, color)

		if pyg.isKeyDownCode(273):
			self.rx = (self.rx - 5) % 360
		if pyg.isKeyDownCode(274):
			self.rx = (self.rx + 5) % 360
		if pyg.isKeyDownCode(275):
			self.ry = (self.ry - 5) % 360
		if pyg.isKeyDownCode(276):
			self.ry = (self.ry + 5) % 360

m = main()
pyg.run(m)

動作状況

polygon3d

カーソルでぐりぐり動きます。

ファンクションの説明。

faceVect

法線ベクトルを求めるためのもの。

cl

カリング用です。

rotate

回転式。すべてのポイントを一気に計算します。

trans

2次元透視変換

light

照明効果、今の所真正面から光を当てているだけです。

getTri

点群データからリンクデータを元に3点取り出す。


処理内容

今回は単純なCube一つを描画しています。点群数は8。リンクデータが12。とても小さなデータですが想像以上に計算が多い。 Pythonの場合大真面目に計算するよりも処理の速いネイティブにデータを投げてしまって手を抜いたほうが速かったりするので ひょっとするとカリングの処理なんかはやらずZソートだけやってあげたほうがより速度が出るかもしれません。

これでいくつかの計算とifの処理がなくなるので、ひょっとしなくてもそのほうが良いのかも。

理屈は分かるけどしっくり来てないというのが全体的な話でライトの処理など、ライトの持つベクトルの扱いなど釈然とせずに悶々としているといった部分が多々あります。

lightファンクションはオブジェクトの法線ベクトルとライトのベクトルを計算して 0 ~ 1のデータを返すようになっています。 これがそのオブジェクトに与えられる明るさです。ライトのベクトルをいじれば光のあたる方向がかわるはずです。 現状ライトオブジェクトを扱うような処理は入っていませんのでそういうものを作ればすぐどうにかなるのかもしれませんが。

faceVectとclは本来一つで済みそうな処理です。faceVectのz軸の方向を見ればclの返す値の代替えができるのです(というか内容としては全く一緒です) 現状なぜ2つに別れているのかというと2次元透視変換をかける前でなければ正しい法線ベクトルが得られない、変換後でないと正しいカリングが処理できない。 という理由です。非常に厄介です。 大した計算はしていないのでそれほど処理に影響はないのかもしれませんがチリツモです。いい処理方法があるなら知りたい。

といったところでしょうか。


現状は点群数も少ないので何のストレスもなく動いていますが点群が増えればちらちらと見え隠れする処理の無駄が大きくのしかかってくるのは間違いないでしょうし。 まだまだ考えないといけないことは多いようです。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment