当前位置: 首页 > news >正文

一种基于体素的射线检测

效果

基于体素的射线检测

一个漏检的射线检测

从起点一直递增指定步长即可得到一个稀疏的检测

    bool Raycast(Vector3 from, Vector3 forword, float maxDistance){int loop = 6666;Vector3 pos = from;Debug.DrawLine(from, from + forword * maxDistance, Color.red);while (loop-- > 0){pos += forword;if((pos - from).magnitude > maxDistance){break;}Vector3Int blockPosition = Vector3Int.RoundToInt(pos);if (world.HasBlockCollider(blockPosition)){return true;}if(world.HasVoxelCollider(blockPosition)){return true;}Gizmos.DrawWireCube(blockPosition,Vector3.one);}return false;}

在这里插入图片描述
可以看到上图有很多地方因为迭代的步长过大导致漏检
为了补充这些空洞可以使用Bresenham重新修改算法

填补空缺

修改步长会导致迭代次数暴增,并且想要不漏检需要很小的步长。下面使用了检测相交点是否连续检测是否空缺
首先射线经过的点必然连续,那么可以我们就可以直接对比上一次离开方块时的点和当前进入方块的点

	leavePoint = GetIntersectPoint(aabb, leaveRay, leavePoint);static Vector3 GetIntersectPoint(Bounds aabb, Ray ray, Vector3 point){if (aabb.IntersectRay(ray, out var distance)){point = ray.GetPoint(distance);}else // 由于射线平行于方块的面或边导致没有相交,稍微放大方块强行相交{aabb.size *= 1.01f;if (aabb.IntersectRay(ray, out distance)){point = ray.GetPoint(distance);}}return point;}

如果2个坐标是相等的。可以认为射线并没有漏检

oldPoint = posInt;
aabb.center = posInt;
aabb.size = Vector3.one;
if (aabb.IntersectRay(enterRay, out distance))
{enterPoint = enterRay.GetPoint(distance);if (leavePoint != enterPoint){//存在漏检}
}

否则就需要补充漏检的方块,有可能射线一次漏了2个方块没有检测
在这里插入图片描述
先检测最靠近离开位置的坐标是否有方块

distance = (enterPoint - leavePoint).magnitude * 0.01f;
fillPoint = Vector3Int.RoundToInt(leavePoint + forward * distance);
if (checkCollider(fillPoint, ref hitInfo))return true;

再检测靠近进入位置的坐标是否有方块

fillPoint2 = Vector3Int.RoundToInt(enterPoint - forward * distance);
if (fillPoint2 != fillPoint)
{if (checkCollider(fillPoint2, ref hitInfo))return true;
}

手动覆盖漏检的方块,青色为补充的检测
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
多个轴向观察射线是否在绘制的方块内

细分方块

把一个方块切成 444 共计64个方块
那么它们的相对索引就是
世界坐标转为体素内部坐标

    public Vector3 PositionToVoxelPosition(Vector3 position){var pos = Vector3Int.RoundToInt(position);position -= voxelOffset;position -= pos;position *= voxelScale;position += Vector3Int.one;return Vector3Int.RoundToInt(position);}

切分时使用ulong存储体素信息。如果某一位是1,即当前位置拥有体素
方块内部坐标转索引。使用索引检测当前位是否有体素

    public int VoxelPositionToIndex(Vector3 position){return (int)Mathf.Abs(position.x * BlockWorld.planeCount + position.y * BlockWorld.voxelScale + position.z);}

体素检测,先检测当前位置是否是体素块,如果是,检测方块体内该位置是否有体素

    public bool HasVoxelCollider(Vector3 position, out Vector3 result){if (voxelDict.TryGetValue(Vector3Int.RoundToInt(position), out ulong value)){result = PositionToVoxelPosition(position);int index = VoxelPositionToIndex(result);if ((value >> index & 1) == 1){result = VoxelPositionToWorldPosition(position, result);return true;}result = Vector3.zero;return false;}result = position;return false;}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

完整代码

using System;
using System.Collections.Generic;
using UnityEngine;public class BlockWorld:IDisposable
{public const int voxelScale = 4;public const int planeCount = voxelScale * voxelScale;public static Vector3 voxelSize = Vector3.one / voxelScale;public static Vector3 voxelStartOffset = voxelSize * 0.5f;public static Vector3 voxelAABBSize = Vector3.one + BlockWorld.voxelSize * 2;public static Vector3 voxelOffset = Vector3.one * 0.5f + voxelStartOffset;private readonly Dictionary<Vector3Int, bool> blocks = new Dictionary<Vector3Int, bool>();private readonly Dictionary<Vector3Int, ulong> voxelDict = new Dictionary<Vector3Int, ulong>();public void AddBlock(Vector3Int position){blocks[position] = true;}public void AddVoxel(Vector3Int blockPosition, ulong value){voxelDict[blockPosition] = value;}public void AddVoxel( Vector3 voxelPosition){var blockPosition = Vector3Int.RoundToInt(voxelPosition);voxelDict.TryGetValue(blockPosition, out ulong value);voxelPosition = PositionToVoxelPosition(voxelPosition);int index = VoxelPositionToIndex(voxelPosition);value |= (ulong)1 << index;voxelDict[blockPosition] = value;}public Vector3 PositionToVoxelPosition(Vector3 position){var pos = Vector3Int.RoundToInt(position);position -= voxelOffset;position -= pos;position *= voxelScale;position += Vector3Int.one;return Vector3Int.RoundToInt(position);}public Vector3 VoxelPositionToWorldPosition(Vector3 position, Vector3 voxelPosition){return voxelPosition / BlockWorld.voxelScale + BlockWorld.voxelSize + BlockWorld.voxelStartOffset + Vector3Int.RoundToInt(position);}public int VoxelPositionToIndex(Vector3 position){return (int)Mathf.Abs(position.x * BlockWorld.planeCount + position.y * BlockWorld.voxelScale + position.z);}public void Clear(){blocks.Clear();voxelDict.Clear();}public bool HasBlockCollider(Vector3Int position){return blocks.ContainsKey(position);}public bool HasVoxelCollider(Vector3Int position){return voxelDict.ContainsKey(position);}public bool HasVoxelCollider(Vector3 position, out Vector3 result){if (voxelDict.TryGetValue(Vector3Int.RoundToInt(position), out ulong value)){result = PositionToVoxelPosition(position);int index = VoxelPositionToIndex(result);if( (value >> index & 1) == 1){result = VoxelPositionToWorldPosition(position, result);return true;}result = Vector3.zero;return false;}result = position;return false;}public ulong GetVoxelValue(Vector3Int position){voxelDict.TryGetValue(position, out var value);return value;}void IDisposable.Dispose(){Clear();}
}
using UnityEngine;public static class BlockPhysics
{private const int MAX_LOOP_COUNT = 6666;public static bool Raycast(BlockWorld world, Vector3 from, Vector3 forward, float maxDistance, out RaycastHit hitInfo, bool isDraw = false){
#if !UNITY_EDITORisDraw = false;
#endiffloat distance;int loop = MAX_LOOP_COUNT;Vector3 to = from + forward * maxDistance;Vector3 pos = from;Vector3 tForward = forward * 0.9f;Vector3Int posInt = Vector3Int.RoundToInt(pos);Vector3Int oldPoint = posInt;Vector3Int fillPoint;Vector3Int fillPoint2;Vector3 leavePoint = from;Vector3 enterPoint = default;Bounds aabb = default;Ray enterRay = default;Ray leaveRay = default;enterRay.origin = from;enterRay.direction = forward;leaveRay.origin = to + forward * 2;leaveRay.direction = -forward;hitInfo = default;aabb.center = posInt;aabb.size = Vector3.one;if (aabb.IntersectRay(leaveRay, out distance)){leavePoint = leaveRay.GetPoint(distance);}if (maxDistance - (int)maxDistance > 0){maxDistance += forward.magnitude * 0.9f;}#if UNITY_EDITORint index = 0;if (isDraw){Debug.DrawLine(from, to, Color.red);}
#endifwhile (loop-- > 0){pos += tForward;if ((pos - from).magnitude > maxDistance){break;}posInt = Vector3Int.RoundToInt(pos);if (posInt == oldPoint)continue;oldPoint = posInt;aabb.center = posInt;aabb.size = Vector3.one;if (aabb.IntersectRay(enterRay, out distance)){enterPoint = enterRay.GetPoint(distance);if (leavePoint != enterPoint){distance = (enterPoint - leavePoint).magnitude * 0.01f;fillPoint = Vector3Int.RoundToInt(leavePoint + forward * distance);if (checkCollider(fillPoint, ref hitInfo))return true;fillPoint2 = Vector3Int.RoundToInt(enterPoint - forward * distance);if (fillPoint2 != fillPoint){if (checkCollider(fillPoint2, ref hitInfo))return true;}}}if (checkCollider(posInt, ref hitInfo))return true;leavePoint = GetIntersectPoint(aabb, leaveRay, leavePoint);}return false;bool checkCollider(Vector3Int origin, ref RaycastHit hitInfo){
#if UNITY_EDITORif (isDraw){Gizmos.color = Color.grey;Gizmos.DrawWireCube(origin, Vector3.one);UnityEditor.Handles.Label(origin, $"[{index++}]");}
#endifif (world.HasBlockCollider(origin)){aabb.center = origin;aabb.size = Vector3.one;hitInfo.point = origin;if (aabb.IntersectRay(enterRay, out distance)){hitInfo.point = enterRay.GetPoint(distance);
#if UNITY_EDITORif (isDraw){Gizmos.color = Color.red;Gizmos.DrawWireCube(origin, Vector3.one);UnityEditor.Handles.Label(hitInfo.point, $"【{hitInfo.point.x}, {hitInfo.point.y}, {hitInfo.point.z}】");}
#endif}return true;}if (world.HasVoxelCollider(origin)){if (RaycastVoxel(world, from, forward, origin, maxDistance, out hitInfo, isDraw)){return true;}}return false;}}static bool RaycastVoxel(BlockWorld world, Vector3 from, Vector3 forward, Vector3 blockPosition, float maxDistance, out RaycastHit hitInfo, bool isDraw = false){hitInfo = default;float distance = 0f;int loop = MAX_LOOP_COUNT;Vector3 pos = from;Vector3 tForward = forward * 0.24f;Vector3 voxelPosition;Vector3 leavePoint = from;Vector3 result = default;Vector3 fillPoint = default;Vector3 fillPoint2 = default;Vector3 enterPoint = default;Bounds aabb = default;Ray enterRay = default;enterRay.origin = from;enterRay.direction = forward;Ray leaveRay = default;leaveRay.origin = (from + forward * maxDistance) + forward * 2;leaveRay.direction = -forward;aabb.center = blockPosition;aabb.size = Vector3.one;if (aabb.IntersectRay(enterRay, out distance)){enterPoint = enterRay.GetPoint(distance);pos = enterPoint;leavePoint = enterPoint;}#if UNITY_EDITORif (isDraw){Gizmos.DrawWireSphere(enterPoint, 0.05f);}int index = 0;
#endifwhile (loop-- > 0){pos += tForward;if ((pos - from).magnitude > maxDistance){break;}aabb.center = blockPosition;aabb.size = BlockWorld.voxelAABBSize;if (!aabb.Contains(pos))break;voxelPosition = world.PositionToVoxelPosition(pos);voxelPosition = world.VoxelPositionToWorldPosition(pos, voxelPosition);aabb.center = voxelPosition;aabb.size = BlockWorld.voxelSize;if (aabb.IntersectRay(enterRay, out distance)){enterPoint = enterRay.GetPoint(distance);if (leavePoint != enterPoint){distance = (enterPoint - leavePoint).magnitude * 0.01f;fillPoint = leavePoint + forward * distance;if (checkCollider(fillPoint, ref hitInfo)){return true;}fillPoint2 = enterPoint - forward * distance;if (world.PositionToVoxelPosition(fillPoint) != world.PositionToVoxelPosition(fillPoint2)){if (checkCollider(fillPoint2, ref hitInfo))return true;}}}if (checkCollider(pos, ref hitInfo)){return true;}leavePoint = GetIntersectPoint(aabb, leaveRay, leavePoint);}return false;bool checkCollider(Vector3 origin, ref RaycastHit hitInfo){
#if UNITY_EDITORif (isDraw){Gizmos.color = Color.gray;var voxelPoint = world.PositionToVoxelPosition(origin);voxelPoint = world.VoxelPositionToWorldPosition(origin, voxelPoint);Gizmos.DrawWireCube(voxelPoint, BlockWorld.voxelSize);UnityEditor.Handles.Label(voxelPoint, $"[{index++}]");}
#endifif (world.HasVoxelCollider(origin, out result)){aabb.center = result;aabb.size = BlockWorld.voxelSize;hitInfo.point = result;if (aabb.IntersectRay(enterRay, out distance)){hitInfo.point = enterRay.GetPoint(distance);
#if UNITY_EDITORif (isDraw){Gizmos.color = Color.red;var voxelPoint = world.PositionToVoxelPosition(origin);voxelPoint = world.VoxelPositionToWorldPosition(origin, voxelPoint);Gizmos.DrawWireCube(voxelPoint, BlockWorld.voxelSize);UnityEditor.Handles.Label(hitInfo.point, $"【{hitInfo.point.x}, {hitInfo.point.y}, {hitInfo.point.z}】");}
#endif}return true;}return false;}}static Vector3 GetIntersectPoint(Bounds aabb, Ray ray, Vector3 point){if (aabb.IntersectRay(ray, out var distance)){point = ray.GetPoint(distance);}else{aabb.size *= 1.01f;if (aabb.IntersectRay(ray, out distance)){point = ray.GetPoint(distance);}}return point;}
}

相关文章:

一种基于体素的射线检测

效果 基于体素的射线检测 一个漏检的射线检测 从起点一直递增指定步长即可得到一个稀疏的检测 bool Raycast(Vector3 from, Vector3 forword, float maxDistance){int loop 6666;Vector3 pos from;Debug.DrawLine(from, from forword * maxDistance, Color.red);while (loo…...

利用Docker安装Protostar

文章目录 一、Protostar介绍二、Ubuntu下安装docker三、安装Protostar 一、Protostar介绍 Protostar是一个免费的Linux镜像演练环境&#xff0c;包含五个系列共23道漏洞分析和利用实战题目。 Protostar的安装有两种方式 第一种是下载镜像并安装虚拟机https://github.com/Exp…...

go基础语法10问

1.使用值为 nil 的 slice、map会发生啥 允许对值为 nil 的 slice 添加元素&#xff0c;但对值为 nil 的 map 添加元素&#xff0c;则会造成运行时 panic。 // map 错误示例 func main() {var m map[string]intm["one"] 1 // error: panic: assignment to entry i…...

SpringCloud + SpringGateway 解决Get请求传参为特殊字符导致400无法通过网关转发的问题

title: “SpringCloud SpringGateway 解决Get请求传参为特殊字符导致400无法通过网关转发的问题” createTime: 2021-11-24T10:27:5708:00 updateTime: 2021-11-24T10:27:5708:00 draft: false author: “Atomicyo” tags: [“tomcat”] categories: [“java”] description: …...

vim基本操作

功能&#xff1a; 命令行模式下的文本编辑器。根据文件扩展名自动判别编程语言。支持代码缩进、代码高亮等功能。使用方式&#xff1a;vim filename 如果已有该文件&#xff0c;则打开它。 如果没有该文件&#xff0c;则打开个一个新的文件&#xff0c;并命名为filename 模式…...

Drift plus penalty 漂移加惩罚Part1——介绍和工作原理

文章目录 正文Methodology 方法论Origins and applications 起源和应用How it works 它是怎样工作的The stochastic optimization problem 随机优化问题Virtual queues 虚拟队列The drift-plus-penalty expression 漂移加惩罚表达式Drift-plus-penalty algorithmApproximate sc…...

(四)动态阈值分割

文章目录 一、基本概念二、实例解析 一、基本概念 基于局部阈值分割的dyn_threshold()算子&#xff0c;适用于一些无法用单一灰度进行分割的情况&#xff0c;如背景比较复杂&#xff0c;有的部分比前景目标亮&#xff0c;或者有的部分比前景目标暗&#xff1b;又比如前景目标包…...

jvm介绍

1. JVM是什么 JVM是Java Virtual Machine的缩写&#xff0c;即咱们经常提到的Java虚拟机。虚拟机是一种抽象化的计算机&#xff0c;有着自己完善的硬件架构&#xff0c;如处理器、堆栈等&#xff0c;具体有什么咱们不做了解。目前我们只需要知道想要运行Java文件&#xff0c;必…...

数据结构与算法课后题-第三章(顺序队和链队)

#include <iostream> //引入头文件 using namespace std;typedef int Elemtype;#define Maxsize 5 #define ERROR 0 #define OK 1typedef struct {Elemtype data[Maxsize];int front, rear;int tag; }SqQueue;void InitQueue(SqQueue& Q) //初始化队列 {Q.rear …...

SSM - Springboot - MyBatis-Plus 全栈体系(十六)

第三章 MyBatis 三、MyBatis 多表映射 2. 对一映射 2.1 需求说明 根据 ID 查询订单&#xff0c;以及订单关联的用户的信息&#xff01; 2.2 OrderMapper 接口 public interface OrderMapper {Order selectOrderWithCustomer(Integer orderId); }2.3 OrderMapper.xml 配置…...

k8s--storageClass自动创建PV

文章目录 一、storageClass自动创建PV1.1 安装NFS1.2 创建nfs storageClass1.3 测试自动创建pv 一、storageClass自动创建PV 这里使用NFS实现 1.1 安装NFS 安装nfs-server&#xff1a; sh nfs_install.sh /mnt/data03 10.60.41.0/24nfs_install.sh #!/bin/bash### How to i…...

7.3 调用函数

前言&#xff1a; 思维导图&#xff1a; 7.3.1 函数调用的形式 我的笔记&#xff1a; 函数调用的形式 在C语言中&#xff0c;调用函数是一种常见的操作&#xff0c;主要有以下几种调用方式&#xff1a; 1. 函数调用语句 此时&#xff0c;函数调用独立存在&#xff0c;作为…...

如果使用pprof来进行性能的观测和优化

1. 分析性能瓶颈 在开始优化之前&#xff0c;首先需要确定你的程序的性能瓶颈在哪里。使用性能分析工具&#xff08;例如 Go 的内置 pprof 包&#xff09;来检测程序中消耗时间和内存的地方。这可以帮助你确定需要优化的具体部分。 2. 选择适当的数据结构和算法 选择正确的数…...

在移动固态硬盘上安装Ubuntu系统和ROS2

目录 原视频准备烧录 原视频 b站鱼香ros 准备 1.在某宝上买一个usb移动固态硬盘或固态U盘&#xff0c;至少64G 2.下载鱼香ros烧录工具 下载第二个就行了&#xff0c;不然某网盘的速度下载全部要一天 下载后&#xff0c;选择FishROS2OS制作工具压缩包&#xff0c;进行解压…...

【iptables 实战】02 iptables常用命令

一、iptables中基本的命令参数 -P 设置默认策略-F 清空规则链-L 查看规则链-A 在规则链的末尾加入新规则-I num 在规则链的头部加入新规则-D num 删除某一条规则-s 匹配来源地址IP/MASK&#xff0c;加叹号“&#xff01;”表示除这个IP外-d 匹配目标地址-i 网卡名称 匹配从这块…...

webview_flutter

查看webview内核 ​https://liulanmi.com/labs/core.html​ h5中获取设备 https://cloud.tencent.com/developer/ask/sof/105938013 https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator/mediaDevices web资源部署后navigator获取不到mediaDevices实例的解决方案&…...

【GESP考级C++】1级样题 闰年统计

GSEP 1级样题 闰年统计 题目描述 小明刚刚学习了如何判断平年和闰年&#xff0c;他想知道两个年份之间&#xff08;包含起始年份和终止年份&#xff09;有几个闰年。你能帮帮他吗&#xff1f; 输入格式 输入一行&#xff0c;包含两个整数&#xff0c;分别表示起始年份和终止…...

CentOS密码重置

背景&#xff1a; 我有一个CentOS虚拟机&#xff0c;但是密码忘记了&#xff0c;偶尔记起可以重置密码&#xff0c;于是今天尝试记录一下&#xff0c;又因为我最近记性比较差&#xff0c;所以必须要记录一下。 过程&#xff1a; 1、在引导菜单界面&#xff08;grub&#xff…...

Tomcat Servlet

Tomcat & Servlet 一、What is “Tomcat”?二、 What is “Servlet”?1、HttpServlet2、HttpServletRequest3、HttpServletResponse 一、What is “Tomcat”? Tomcat 本质上是一个基于 TCP 协议的 HTTP 服务器。我们知道HTTP是一种应用层协议&#xff0c;是 HTTP 客户端…...

国庆day2---select实现服务器并发

select.c&#xff1a; #include <myhead.h>#define ERR_MSG(msg) do{\fprintf(stderr,"__%d__:",__LINE__);\perror(msg);\ }while(0)#define IP "192.168.1.3" #define PORT 8888int main(int argc, const char *argv[]) {//创建报式套接字socketi…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...