给定两个向量 A 和 B ,它们形成线段 L = A-B。 此外,假设视锥体 F 由其左,右,底,顶,近和远平面定义。
如何对 F 剪辑 L ?
也就是说,测试一个交叉点和哪里出现交叉点? (请记住,如果一条线段与一个平截头体相交,如果它与一个角落的两边相交,则该线段可以更多。)
如果可能,请提供一个代码示例(C ++或Python首选)。
答案 0 :(得分:4)
我现在不想为此编写代码,但如果我正确理解“frustum”,则以下内容应该有效。
但我可能完全被误解了。在这种情况下,请详细说明:)
答案 1 :(得分:1)
除了上面提到的Corporal Touchy,你还需要know how to intersect a line segment with a plane。在该页面的描述中,u表示行的参数化定义中的参数。首先,使用所描述的两种方法之一计算u。如果u的值落在0.0到1.0的范围内,则平面会将线段剪切到线段的某个位置。将你回到你的线方程中可以得到交点出现的点。
另一种方法是找到每个点到飞机的directed distance。如果一个点的距离是正的而另一个是负的,则它们位于平面的相对侧。然后你知道哪个点在你的平截头体之外(根据你的飞机法线指向哪个方向)。使用这种方法,通过基于有向距离的比率进行线性插值,可以更快地找到交点。例如。如果一个点的距离是+12而另一个是-12,你知道平面将这个段切成两半,你的u参数是0.5。
希望这有帮助。
答案 2 :(得分:1)
首先extract the planes from your view matrix。
然后使用你的点来定义一个向量,将min / max定义为(0,1),然后在平面上迭代并将它们与段相交,更新最小值/最大值,如果func parseWithIndexes(p *parser) (map[*Node][2]int, error) {
// Iterate until EOF. Any other error will cause an early return.
var err error
var globalBufDif int
var prevEndBuf int
var tokenIndex [2]int
tokenMap := make(map[*Node][2]int)
for err != io.EOF {
// CDATA sections are allowed only in foreign content.
n := p.oe.top()
p.tokenizer.AllowCDATA(n != nil && n.Namespace != "")
t := p.top().FirstChild
for {
if t != nil && t.NextSibling != nil {
t = t.NextSibling
} else {
break
}
}
tokenMap[t] = tokenIndex
if prevEndBuf > p.tokenizer.data.end {
globalBufDif += prevEndBuf
}
prevEndBuf = p.tokenizer.data.end
// Read and parse the next token.
p.tokenizer.Next()
tokenIndex = [2]int{p.tokenizer.data.start + globalBufDif, p.tokenizer.data.end + globalBufDif}
p.tok = p.tokenizer.Token()
if p.tok.Type == ErrorToken {
err = p.tokenizer.Err()
if err != nil && err != io.EOF {
return tokenMap, err
}
}
p.parseCurrentToken()
}
return tokenMap, nil
}
// ParseFragmentWithIndexes parses a fragment of HTML and returns the nodes
// that were found. If the fragment is the InnerHTML for an existing element,
// pass that element in context.
func ParseFragmentWithIndexes(r io.Reader, context *Node) ([]*Node, map[*Node][2]int, error) {
contextTag := ""
if context != nil {
if context.Type != ElementNode {
return nil, nil, errors.New("html: ParseFragment of non-element Node")
}
// The next check isn't just context.DataAtom.String() == context.Data because
// it is valid to pass an element whose tag isn't a known atom. For example,
// DataAtom == 0 and Data = "tagfromthefuture" is perfectly consistent.
if context.DataAtom != a.Lookup([]byte(context.Data)) {
return nil, nil, fmt.Errorf("html: inconsistent Node: DataAtom=%q, Data=%q", context.DataAtom, context.Data)
}
contextTag = context.DataAtom.String()
}
p := &parser{
tokenizer: NewTokenizerFragment(r, contextTag),
doc: &Node{
Type: DocumentNode,
},
scripting: true,
fragment: true,
context: context,
}
root := &Node{
Type: ElementNode,
DataAtom: a.Html,
Data: a.Html.String(),
}
p.doc.AppendChild(root)
p.oe = nodeStack{root}
p.resetInsertionMode()
for n := context; n != nil; n = n.Parent {
if n.Type == ElementNode && n.DataAtom == a.Form {
p.form = n
break
}
}
tokenMap, err := parseWithIndexes(p)
if err != nil {
return nil, nil, err
}
parent := p.doc
if context != nil {
parent = root
}
var result []*Node
for c := parent.FirstChild; c != nil; {
next := c.NextSibling
parent.RemoveChild(c)
result = append(result, c)
c = next
}
return result, tokenMap, nil
}
则提前退出
这是一个纯Python函数的例子,没有外部代码。
min > max