mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 09:37:26 +08:00
1 parent
be5901100e
commit
c8a163a077
35 files changed
+3045
-373
No files matched your search
+191
-5
@@ -19,6 +19,168 @@ import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// drawLines 绘制作者线集,端点独立着色且不参与面的背向剔除
|
||||
// 入参: instance 场景实例, node 模型节点, mesh 属性数组, positions 世界位置, normals 世界法线, pass 绘制轮次, passIndex 轮次索引
|
||||
// 返回: error 几何、资源或取消错误
|
||||
func (r *u3dRender) drawLines(instance u3dInstance, node *U3DNode, mesh *U3DMesh, positions, normals []u3dVector, pass U3DViewPass, passIndex int) error {
|
||||
if r.depthOnly {
|
||||
return nil
|
||||
}
|
||||
shaded := r.mode.shaded()
|
||||
for index, line := range mesh.Lines {
|
||||
if index%128 == 0 {
|
||||
if err := r.ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if uint64(line.Shading) >= uint64(len(mesh.Shadings)) {
|
||||
return fmt.Errorf("invalid U3D render line shading index")
|
||||
}
|
||||
shading := mesh.Shadings[line.Shading]
|
||||
if shading.Attributes > 3 || len(shading.TextureDimensions) > 8 {
|
||||
return fmt.Errorf("invalid U3D render line shading")
|
||||
}
|
||||
var world [2]u3dVector
|
||||
var vertices [2]u3dVertex
|
||||
for i, corner := range line.Corners {
|
||||
if uint64(corner.Position) >= uint64(len(positions)) || shaded && (!mesh.ExcludeNormals && uint64(corner.Normal) >= uint64(len(normals)) || shading.Attributes&1 != 0 && uint64(corner.Diffuse) >= uint64(len(mesh.Diffuse)) || shading.Attributes&2 != 0 && uint64(corner.Specular) >= uint64(len(mesh.Specular))) {
|
||||
return fmt.Errorf("invalid U3D render line corner index")
|
||||
}
|
||||
world[i] = positions[corner.Position]
|
||||
vertices[i].point = r.toCamera.point(world[i])
|
||||
for _, value := range vertices[i].point {
|
||||
if !finite(value) {
|
||||
return fmt.Errorf("invalid U3D line camera position")
|
||||
}
|
||||
}
|
||||
}
|
||||
shaderNames := []string{""}
|
||||
if uint64(line.Shading) < uint64(len(node.LineShaders)) {
|
||||
shaderNames = node.LineShaders[line.Shading]
|
||||
}
|
||||
for _, name := range shaderNames {
|
||||
if err := r.ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
style := u3dRenderStyle{shader: U3DShader{Blend: 0x606, RenderPass: math.MaxUint32}}
|
||||
var err error
|
||||
if shaded {
|
||||
style, err = r.style(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if index, ok := r.shaders[name]; ok {
|
||||
style.shader.RenderPass = r.model.Shaders[index].RenderPass
|
||||
}
|
||||
if style.shader.RenderPass&(1<<passIndex) == 0 {
|
||||
continue
|
||||
}
|
||||
if instance.opacity >= 0 || r.opacity >= 0 {
|
||||
style.shader.Blend = 0x606
|
||||
}
|
||||
for i, corner := range line.Corners {
|
||||
vertices[i].color = [4]float64{r.auxiliaryColor[0], r.auxiliaryColor[1], r.auxiliaryColor[2], 1}
|
||||
if !shaded {
|
||||
continue
|
||||
}
|
||||
var normal u3dVector
|
||||
if !mesh.ExcludeNormals {
|
||||
normal = normals[corner.Normal]
|
||||
}
|
||||
var diffuse, specular *[4]float32
|
||||
if shading.Attributes&1 != 0 {
|
||||
diffuse = &mesh.Diffuse[corner.Diffuse]
|
||||
}
|
||||
if shading.Attributes&2 != 0 {
|
||||
specular = &mesh.Specular[corner.Specular]
|
||||
}
|
||||
vertices[i].color, err = r.shade(world[i], normal, style, diffuse, specular)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if instance.opacity >= 0 {
|
||||
vertices[i].color[3] = instance.opacity
|
||||
}
|
||||
if r.opacity >= 0 {
|
||||
vertices[i].color[3] *= r.opacity
|
||||
}
|
||||
}
|
||||
if r.mode == U3DRenderVertices || r.mode == U3DRenderShadedVertices {
|
||||
for _, vertex := range vertices {
|
||||
fresh, err := r.uniquePrimitive(vertex, vertex, style.shader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fresh {
|
||||
if err := r.modePoint(vertex, style.shader, pass); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if err := r.modeLine(vertices[0], vertices[1], u3dVector{}, u3dVector{}, style.shader, pass); err != nil {
|
||||
return err
|
||||
}
|
||||
for index, section := range r.sections {
|
||||
if index%256 == 0 {
|
||||
if err := r.ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if section.intersection != nil {
|
||||
if err := r.lineIntersection(vertices, index); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// lineIntersection 绘制作者线段与剖切面的交点,不绘制共面线段
|
||||
// 入参: line 相机空间线段, index 剖切面索引
|
||||
// 返回: error 数值、资源或取消错误
|
||||
func (r *u3dRender) lineIntersection(line [2]u3dVertex, index int) error {
|
||||
section := r.sections[index]
|
||||
a, b := u3dPlaneDistance(section.plane, line[0].point), u3dPlaneDistance(section.plane, line[1].point)
|
||||
if !finite(a) || !finite(b) {
|
||||
return fmt.Errorf("invalid U3D line intersection distance")
|
||||
}
|
||||
if a == 0 && b == 0 || a < 0 && b < 0 || a > 0 && b > 0 {
|
||||
return nil
|
||||
}
|
||||
point := u3dInterpolate(line[0], line[1], u3dClipFraction(a, b))
|
||||
for i, other := range r.sections {
|
||||
if i%256 == 0 {
|
||||
if err := r.ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if i != index {
|
||||
distance := u3dPlaneDistance(other.plane, point.point)
|
||||
if !finite(distance) {
|
||||
return fmt.Errorf("invalid U3D line intersection clip")
|
||||
}
|
||||
if distance < 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
for i, plane := range r.frustumPlanes() {
|
||||
if i == 1 && r.camera.Far == 0 && !r.camera.ClipFar {
|
||||
continue
|
||||
}
|
||||
distance := u3dPlaneDistance(plane, point.point)
|
||||
if !finite(distance) {
|
||||
return fmt.Errorf("invalid U3D projected intersection")
|
||||
}
|
||||
if distance < 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return r.rasterSectionLine(point, point, *section.intersection, u3dVector{}, u3dVector{})
|
||||
}
|
||||
|
||||
// frustumPlanes 返回保留正侧的六个相机视锥面
|
||||
// 返回: [6][4]float64 近、远、左右及上下平面
|
||||
func (r *u3dRender) frustumPlanes() [6][4]float64 {
|
||||
@@ -161,6 +323,15 @@ func u3dClipLine(a, b *u3dVertex, plane [4]float64) (bool, error) {
|
||||
// 入参: a 已裁剪起点, b 已裁剪终点, rgb 交线颜色, normal 原面法线, origin 原面上一点
|
||||
// 返回: error 数值、资源或取消错误
|
||||
func (r *u3dRender) rasterSectionLine(a, b u3dVertex, rgb [3]float64, normal, origin u3dVector) error {
|
||||
a.color = [4]float64{rgb[0], rgb[1], rgb[2], 1}
|
||||
b.color = a.color
|
||||
return r.rasterLine(a, b, normal, origin, U3DShader{Blend: 0x606}, U3DViewPass{})
|
||||
}
|
||||
|
||||
// rasterLine 绘制单像素线段,颜色与深度按透视插值,面深度偏移防止自身遮挡
|
||||
// 入参: a 已裁剪起点, b 已裁剪终点, normal 面法线, origin 面上点, shader 着色器, pass 绘制轮次
|
||||
// 返回: error 数值、资源或取消错误
|
||||
func (r *u3dRender) rasterLine(a, b u3dVertex, normal, origin u3dVector, shader U3DShader, pass U3DViewPass) error {
|
||||
cx := r.viewport[0] + r.viewport[2]/2 + r.camera.ShiftX
|
||||
cy := r.viewport[1] + r.viewport[3]/2 + r.camera.ShiftY
|
||||
planes := [4][4]float64{{r.camera.ScaleX, 0, 0, cx}, {-r.camera.ScaleX, 0, 0, float64(r.output.Rect.Dx()) - cx}, {0, -r.camera.ScaleY, 0, cy}, {0, r.camera.ScaleY, 0, float64(r.output.Rect.Dy()) - cy}}
|
||||
@@ -193,8 +364,8 @@ func (r *u3dRender) rasterSectionLine(a, b u3dVertex, rgb [3]float64, normal, or
|
||||
return fmt.Errorf("invalid U3D line span")
|
||||
}
|
||||
count := max(1, int(steps))
|
||||
color := [4]float64{rgb[0], rgb[1], rgb[2], 1}
|
||||
r.order++
|
||||
previousPixel := -1
|
||||
for i := 0; i <= count; i++ {
|
||||
if i%1024 == 0 {
|
||||
if err := r.ctx.Err(); err != nil {
|
||||
@@ -202,13 +373,21 @@ func (r *u3dRender) rasterSectionLine(a, b u3dVertex, rgb [3]float64, normal, or
|
||||
}
|
||||
}
|
||||
t := float64(i) / float64(count)
|
||||
px, py := math.Floor(x[0]*(1-t)+x[1]*t), math.Floor(y[0]*(1-t)+y[1]*t)
|
||||
px := math.Floor(x[0] + float64(i)*(x[1]-x[0])/float64(count))
|
||||
py := math.Floor(y[0] + float64(i)*(y[1]-y[0])/float64(count))
|
||||
if px < 0 || py < 0 || px >= float64(r.output.Rect.Dx()) || py >= float64(r.output.Rect.Dy()) {
|
||||
continue
|
||||
}
|
||||
depth := a.point[2]*(1-t) + b.point[2]*t
|
||||
pixel := int(py)*r.output.Rect.Dx() + int(px)
|
||||
if pixel == previousPixel {
|
||||
continue
|
||||
}
|
||||
previousPixel = pixel
|
||||
depth := a.point[2] + (b.point[2]-a.point[2])*t
|
||||
weight := t
|
||||
if r.camera.Perspective {
|
||||
depth = 1 / (q[0]*(1-t) + q[1]*t)
|
||||
weight = t * q[1] * depth
|
||||
}
|
||||
ray := u3dVector{(px + .5 - cx) / r.camera.ScaleX, (cy - py - .5) / r.camera.ScaleY, 1}
|
||||
denominator := normal[2]
|
||||
@@ -220,9 +399,16 @@ func (r *u3dRender) rasterSectionLine(a, b u3dVertex, rgb [3]float64, normal, or
|
||||
depth = sampled
|
||||
}
|
||||
depth -= 8 * math.Abs(depth-math.Nextafter(depth, math.Inf(-1)))
|
||||
pixel := int(py)*r.output.Rect.Dx() + int(px)
|
||||
if depth <= r.frame[pixel].depth {
|
||||
if err := r.fragment(pixel, depth, color, 0x606); err != nil {
|
||||
vertex := u3dInterpolate(a, b, weight)
|
||||
visible, err := u3dFragmentColor(&vertex.color, vertex.point, &shader, &pass)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !visible {
|
||||
continue
|
||||
}
|
||||
if err := r.fragment(pixel, depth, vertex.color, shader.Blend); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user